gdata update

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@425538 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yonik Seeley 2006-07-25 22:23:01 +00:00
parent a0288da46d
commit 5e61ac9bf1
83 changed files with 4353 additions and 925 deletions

View File

@ -43,6 +43,7 @@
<property name="junit.output.dir" location="${build.dir}/test"/>
<property name="junit.reports" location="${build.dir}/test/reports"/>
<property name="junit.includes" value="**/Test*.java,**/*Test.java"/>
<property name="junit.excludes" value=""/>
<available
property="javacc.present"
@ -179,7 +180,7 @@
<formatter type="xml"/>
<formatter type="brief" usefile="false"/>
<batchtest fork="yes" todir="${junit.output.dir}" unless="testcase">
<fileset dir="src/test" includes="${junit.includes}"/>
<fileset dir="src/test" includes="${junit.includes}" excludes="${junit.excludes}"/>
</batchtest>
<batchtest fork="yes" todir="${junit.output.dir}" if="testcase">
<fileset dir="src/test" includes="**/${testcase}.java"/>

View File

@ -1,58 +1,84 @@
<?xml version="1.0"?>
<project name="gdata-server" default="default">
<description>
Serverside Google Data API implementation
</description>
<property name="gdata.war.name" value="gdata-server"/>
<property name="gdata.lib.dir" value="lib"/>
<path id="additional.dependencies">
<pathelement location="lib/servlet-api.jar" />
<!-- easymock version 1.2 for java 1.3 -->
<pathelement location="lib/easymock.jar" />
<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/commons-digester-1.7.jar" />
<pathelement location="lib/commons-beanutils.jar" />
<pathelement location="lib/commons-collections-3.2.jar" />
<project name="gdata-server" default="default" >
<description>
Serverside Google Data API implementation
</description>
<property name="javac.source" value="1.5" />
<property name="javac.target" value="1.5" />
<property name="gdata.war.name" value="gdata-server" />
<property name="gdata.lib.dir" value="lib" />
<property name="db4o.jar" value="db4o-5.2-java5.jar" />
<!-- set property for third party jars -->
<available property="db4o.jar.present" type="file" file="${gdata.lib.dir}/${db4o.jar}" value="test"/>
<condition property="junit.excludes" value="**/TestDb4o*.java">
<not>
<isset property="db4o.jar.present"/>
</not>
</condition>
<path id="additional.dependencies">
<fileset dir="${gdata.lib.dir}">
<include name="easymock.jar" />
<include name="servlet-api.jar" />
<include name="commons-logging-1.1.jar" />
<include name="gdata-client-1.0.jar" />
<include name="commons-digester-1.7.jar" />
<include name="commons-beanutils.jar" />
<include name="commons-collections-3.2.jar" />
<include name="${db4o.jar}" if="db4o.jar.present" />
</fileset>
</path>
<!-- redefine compile-core and compile-test to exclude 3rd party dependend sources -->
<target name="compile-core" depends="init">
<echo>Use gdata - compile-core task </echo>
<compile srcdir="src/java" destdir="${build.dir}/classes/java">
<classpath refid="classpath" />
<exclude name="org/apache/lucene/gdata/storage/db4o/**" unless="db4o.jar.present" />
</compile>
</target>
<target name="compile-test" depends="compile-core">
<echo>Use gdata - compile-test task </echo>
<compile srcdir="src/test" destdir="${build.dir}/classes/test">
<classpath refid="test.classpath" />
<exclude name="org/apache/lucene/gdata/storage/db4o/**" unless="db4o.jar.present" />
</compile>
<copy todir="${build.dir}/classes/test">
<fileset dir="src/test" excludes="**/*.java" />
</copy>
</target>
<pathconvert property="project.classpath" targetos="unix" refid="additional.dependencies" />
<property name="javac.source" value="1.5"/>
<property name="javac.target" value="1.5"/>
<import file="../contrib-build.xml" />
<target name="prepare-dist" depends="jar-core">
<echo>Prepare dist directory</echo>
<delete dir="${dist.dir}"/>
<mkdir dir="${dist.dir}"/>
<delete dir="${dist.dir}" />
<mkdir dir="${dist.dir}" />
</target>
<target name="war-gdata" depends="prepare-dist">
<echo>Distributing GData War </echo>
<war destfile="${dist.dir}/${gdata.war.name}.war"
webxml="webroot/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}" />
<target name="war-gdata" depends="prepare-dist">
<echo>Distributing GData War </echo>
<war destfile="${dist.dir}/${gdata.war.name}.war" webxml="webroot/WEB-INF/web.xml">
<metainf dir="webroot/meta-inf" />
<fileset dir="webroot" defaultexcludes="true">
<exclude name="meta-inf/context.xml" />
<exclude name="meta-inf/" />
<exclude name="WEB-INF/web.xml" />
</fileset>
<lib dir="${gdata.lib.dir}">
<include name="commons-logging-1.1.jar" />
<include name="gdata-client-1.0.jar" />
<include name="commons-digester-1.7.jar" />
<include name="commons-beanutils.jar" />
<include name="commons-collections-3.2.jar" />
<include name="${db4o.jar}" if="db4o.jar.present" />
</lib>
<lib dir="${build.dir}" includes="${final.name}.jar" />
<lib file="${lucene.jar}" />
</war>
</target>
</target>
</project>

View File

@ -226,9 +226,11 @@ public class GDataAccount {
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object o) {
if(o == null)
return false;
if (this == o)
return true;
if (!(o instanceof GDataAccount) || o == null)
if (!(o instanceof GDataAccount))
return false;
GDataAccount toCompare = (GDataAccount) o;
if (this.name.equals(toCompare.name))
@ -301,6 +303,8 @@ public class GDataAccount {
retVal.setRole(AccountRole.ENTRYAMINISTRATOR);
return retVal;
}
/**
* This enum respesents all account roles an account can have.

View File

@ -66,7 +66,8 @@ public class ServerBaseEntry {
private ProvidedService serviceConfig;
private BaseEntry entry;
private static final int DEFAULTVERSION = 1;
private int version;
@ -100,8 +101,8 @@ public class ServerBaseEntry {
*/
@SuppressWarnings("unchecked")
public ServerBaseEntry() {
this(new Entry());
this.entry = new Entry();
}
/**
@ -110,7 +111,7 @@ public class ServerBaseEntry {
@SuppressWarnings("unchecked")
public ServerBaseEntry(BaseEntry arg0) {
this.entry = arg0;
this.setVersion(DEFAULTVERSION);
}
@ -613,6 +614,23 @@ public class ServerBaseEntry {
public void declareExtensions(ExtensionProfile arg0) {
this.entry.declareExtensions(arg0);
}
/**
* @return Returns the version.
*/
public int getVersion() {
return this.version;
}
/**
* @param version The version to set.
*/
public void setVersion(int version) {
if(version < this.version)
throw new IllegalArgumentException("Version must be greater than the current version -- current version: "+this.version);
this.version = version;
setVersionId(""+this.version);
}

View File

@ -29,8 +29,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.server.authentication.AuthenticationController;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.Storage;
import org.apache.lucene.gdata.storage.StorageController;
@ -129,6 +129,7 @@ public class GDataRequest {
Storage storage = controller.getStorage();
String service = storage.getServiceForFeed(this.feedId);
storage.close();
/*
* ExtensionProfile and the type is used for building the Entry /
* Feed Instances from an inputstream or reader
@ -141,8 +142,11 @@ public class GDataRequest {
"feed is not registered or extension profile could not be created");
} catch (Exception e) {
e.printStackTrace();
throw new GDataRequestException(
"feed is not registered or extension profile could not be created");
"feed is not registered or extension profile could not be created -- "
+ e.getMessage(), e);
}
}
@ -307,27 +311,27 @@ public class GDataRequest {
builder.append(buildRequestIDString(false));
builder.append("?");
if (builder.charAt(builder.length() - 1) != '?')
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++) {
String values = this.request.getParameter(element);
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(element).append("=");
if (element.equals(START_INDEX_NEXT_PAGE_PARAMETER)) {
int tempVal = DEFAULT_START_INDEX;
try {
tempVal = Integer.parseInt(values);
} catch (Exception e) {
LOG.info("Can not parse StartIndex -- use defaut");
}
builder.append(values[i]);
builder.append(tempVal + getItemsPerPage());
continue;
}
builder.append(values);
if (parameters.hasMoreElements())
builder.append("&");
@ -339,9 +343,10 @@ public class GDataRequest {
DEFAULT_ITEMS_PER_PAGE);
}
if (this.request.getParameter(START_INDEX_NEXT_PAGE_PARAMETER) == null) {
builder.append('&');
if (builder.charAt(builder.length() - 1) != '?')
builder.append('&');
builder.append(START_INDEX_NEXT_PAGE_PARAMETER).append("=");
builder.append(DEFAULT_ITEMS_PER_PAGE + 1);
builder.append(getItemsPerPage() + 1);
}
return builder.toString();
@ -352,7 +357,9 @@ public class GDataRequest {
StringBuilder builder = new StringBuilder("http://");
builder.append(this.request.getHeader("Host"));
builder.append(this.request.getRequestURI());
if (endingSlash && !this.request.getRequestURI().endsWith("/"))
if (!endingSlash && builder.charAt(builder.length() - 1) == '/')
builder.setLength(builder.length() - 1);
if (endingSlash && builder.charAt(builder.length() - 1) != '/')
builder.append("/");
return builder.toString();
@ -454,7 +461,7 @@ public class GDataRequest {
*/
public boolean isFeedRequested() {
return (this.type.equals(GDataRequestType.GET) && (this.entryId == null
return (this.type == GDataRequestType.GET && (this.entryId == null
|| this.entryId.length() == 0 || (this.entryId.equals('/'))));
}

View File

@ -22,6 +22,8 @@ import java.util.Date;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.server.GDataRequest.OutputFormat;
import org.apache.lucene.gdata.utils.DateFormater;
@ -68,6 +70,7 @@ import com.google.gdata.util.common.xml.XmlWriter.Namespace;
*
*/
public class GDataResponse {
private static final Log LOG = LogFactory.getLog(GDataResponse.class);
private int error;
private boolean isError = false;
@ -169,7 +172,7 @@ public class GDataResponse {
if (time != null)
setLastModifiedHeader(time.getValue());
XmlWriter writer = createWriter();
if (this.outputFormat.equals(OutputFormat.ATOM)) {
this.response.setContentType(XMLMIME_ATOM);
feed.generateAtom(writer, profile);
@ -177,7 +180,7 @@ public class GDataResponse {
this.response.setContentType(XMLMIME_RSS);
feed.generateRss(writer, profile);
}
writer.close();
}
/**
@ -210,6 +213,8 @@ public class GDataResponse {
entry.generateAtom(writer, profile);
else
entry.generateRss(writer, profile);
writer.close();
}
private XmlWriter createWriter() throws IOException {

View File

@ -27,6 +27,7 @@ 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.ModificationConflictException;
import org.apache.lucene.gdata.storage.ResourceNotFoundException;
import org.apache.lucene.gdata.storage.Storage;
import org.apache.lucene.gdata.storage.StorageController;
@ -103,7 +104,9 @@ public class GDataService implements Service {
ServerBaseEntry entry = buildEntry(request, response);
entry.setFeedId(request.getFeedId());
entry.setServiceConfig(request.getConfigurator());
setTimeStamps(entry.getEntry());
BaseEntry tempEntry = entry.getEntry();
tempEntry.setPublished(getCurrentDateTime());
tempEntry.setUpdated(getCurrentDateTime());
BaseEntry retVal = null;
try {
retVal = this.storage.storeEntry(entry);
@ -129,6 +132,7 @@ public class GDataService implements Service {
entry.setServiceConfig(request.getConfigurator());
entry.setFeedId(request.getFeedId());
entry.setId(request.getEntryId());
setVersionId(entry,request,response);
if (entry.getId() == null)
throw new ServiceException(
"entry id is null -- can not delete null entry");
@ -140,7 +144,13 @@ public class GDataService implements Service {
"Could not delete entry", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
} catch (Exception e) {
}catch (ModificationConflictException e) {
response.setError(HttpServletResponse.SC_CONFLICT);
ServiceException ex = new ServiceException(
"Could not delete entry - version confilict", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
}catch (StorageException e) {
response.setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
ServiceException ex = new ServiceException(
"Could not delete entry", e);
@ -160,7 +170,7 @@ public class GDataService implements Service {
ServerBaseEntry entry = buildEntry(request, response);
entry.setFeedId(request.getFeedId());
setVersionId(entry,request,response);
entry.setServiceConfig(request.getConfigurator());
if (LOGGER.isInfoEnabled())
LOGGER.info("update Entry" + entry.getId() + " for feedId: "
@ -180,7 +190,11 @@ public class GDataService implements Service {
throw new ServiceException(
"Entry id in the entry xml does not match the requested resource");
}
setTimeStamps(entry.getEntry());
BaseEntry tempEntry = entry.getEntry();
tempEntry.setUpdated(getCurrentDateTime());
Link selfLink = entry.getSelfLink();
if(selfLink != null)
entry.getLinks().remove(selfLink);
BaseEntry retVal = null;
try {
retVal = this.storage.updateEntry(entry);
@ -190,7 +204,13 @@ public class GDataService implements Service {
"Could not update entry", e);
ex.setStackTrace(e.getStackTrace());
throw ex;
} catch (StorageException e) {
}catch (ModificationConflictException e) {
response.setError(HttpServletResponse.SC_CONFLICT);
ServiceException ex = new ServiceException(
"Could not update entry - version confilict", 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);
@ -261,13 +281,6 @@ public class GDataService implements Service {
}
}
private BaseEntry setTimeStamps(final BaseEntry entry) {
if (entry.getUpdated() == null)
entry.setUpdated(DateTime.now());
if (entry.getPublished() == null)
entry.setPublished(DateTime.now());
return entry;
}
/**
* @see org.apache.lucene.gdata.server.Service#getSingleEntry(org.apache.lucene.gdata.server.GDataRequest,
@ -282,6 +295,8 @@ public class GDataService implements Service {
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");
@ -318,10 +333,10 @@ public class GDataService implements Service {
@SuppressWarnings("unchecked")
private void dynamicElementFeedStragey(final BaseFeed feed,
final GDataRequest request) {
buildDynamicFeedElements(request, feed);
buildDynamicFeedElements(request, feed);
List<BaseEntry> entryList = feed.getEntries();
for (BaseEntry entry : entryList) {
String id = request.getContextPath() + entry.getId();
String id = new StringBuilder(request.getContextPath()).append(entry.getId()).append("/").toString();
setSelfLink(entry, id);
}
@ -334,7 +349,12 @@ public class GDataService implements Service {
*/@SuppressWarnings("unchecked")
private BaseEntry setSelfLink(final BaseEntry entry, String id) {
Link self = buildLink(Link.Rel.SELF, XMLMIME, id);
entry.getLinks().add(self);
StringBuilder builder = new StringBuilder(id);
builder.append(entry.getVersionId());
Link edit = buildLink(Link.Rel.ENTRY_EDIT,XMLMIME,builder.toString());
List<Link> list = entry.getLinks();
list.add(edit);
list.add(self);
return entry;
}
@ -347,10 +367,12 @@ public class GDataService implements Service {
feed.setItemsPerPage(request.getItemsPerPage());
feed.setStartIndex(request.getStartIndex());
feed.setId(request.getContextPath());
feed.getLinks().add(
List<Link> links = feed.getLinks();
links.add(
buildLink(Link.Rel.SELF, Link.Type.ATOM, request.getSelfId()));
feed.getLinks().add(
links.add(
buildLink(Link.Rel.NEXT, XMLMIME, request.getNextId()));
}
@ -394,5 +416,23 @@ public class GDataService implements Service {
}
}
private ServerBaseEntry setVersionId(final ServerBaseEntry entry, final GDataRequest request, final GDataResponse response)throws ServiceException{
try{
entry.setVersion(Integer.parseInt(request.getEntryVersion()));
return entry;
}catch (Exception e) {
LOGGER.error("Can not parse entry version -- version is not an integer -- versionid: "+request.getEntryVersion(),e);
response.setError(HttpServletResponse.SC_BAD_REQUEST);
throw new ServiceException("Can not parse entry version -- version is not an integer -- versionid: "+request.getEntryVersion(),e);
}
}
/*
* provide current time to set as published / updated values
* always use servertime to prevent client / server time lag
* Timezoneshift is 0
*/
protected DateTime getCurrentDateTime(){
return new DateTime(System.currentTimeMillis(),0);
}
}

View File

@ -20,6 +20,7 @@ import java.io.Reader;
import org.apache.commons.digester.Digester;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.utils.SimpleSaxErrorHandler;
import org.xml.sax.SAXException;
/**
@ -42,9 +43,12 @@ public class AccountBuilder {
SAXException {
if (reader == null)
throw new IllegalArgumentException("Reader must not be null");
String schemaFile = AccountBuilder.class.getResource("/gdata-account.xsd").getFile();
GDataAccount account = null;
Digester digester = new Digester();
digester.setValidating(false);
digester.setValidating(true);
digester.setErrorHandler(new SimpleSaxErrorHandler());
digester.setSchema(schemaFile);
digester.addObjectCreate("account", GDataAccount.class);
digester.addBeanPropertySetter("account/account-name", "name");
digester.addBeanPropertySetter("account/password", "password");
@ -55,8 +59,12 @@ public class AccountBuilder {
"authorMail");
digester.addBeanPropertySetter("account/account-owner/url",
"authorLink");
account = (GDataAccount) digester.parse(reader);
return account;
}
}

View File

@ -55,6 +55,7 @@ public class GDataAdminService extends GDataService implements AdminService {
if(account.getName() == null)
throw new ServiceException("Account name is null -- can't create feed");
try {
feed.setUpdated(getCurrentDateTime());
feed.setAccount(account);
this.storage.storeFeed(feed,account.getName());
} catch (StorageException e) {
@ -81,6 +82,7 @@ public class GDataAdminService extends GDataService implements AdminService {
throw new ServiceException("Account name is null -- can't update feed");
try {
feed.setAccount(account);
feed.setUpdated(getCurrentDateTime());
this.storage.updateFeed(feed,account.getName());
} catch (StorageException e) {
if(LOG.isInfoEnabled())

View File

@ -35,6 +35,7 @@ import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.data.GDataAccount.AccountRole;
import org.apache.lucene.gdata.server.registry.Component;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.configuration.Requiered;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
@ -81,7 +82,6 @@ public class BlowfishAuthenticationController implements
private Cipher enCrypt;
// TODO make this configurable
private int minuteOffset = 30;
private long milisecondOffset;
@ -92,8 +92,8 @@ public class BlowfishAuthenticationController implements
private ReentrantLock lock = new ReentrantLock();
// TODO make this configurable
private String key = "myTestKey";
private String key;
/**
* @see org.apache.lucene.gdata.server.authentication.AuthenticationController#initialize()
@ -236,7 +236,8 @@ public class BlowfishAuthenticationController implements
/**
* @return Returns the minuteOffset.
*/
public int getMinuteOffset() {
@Requiered
public int getLoginTimeout() {
return this.minuteOffset;
}
@ -244,7 +245,8 @@ public class BlowfishAuthenticationController implements
* @param minuteOffset
* The minuteOffset to set.
*/
public void setMinuteOffset(int minuteOffset) {
@Requiered
public void setLoginTimeout(int minuteOffset) {
this.minuteOffset = minuteOffset;
calculateTimeOffset();
}

View File

@ -0,0 +1,91 @@
/**
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.gdata.server.registry;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.server.registry.Scope.ScopeType;
/**
* This <tt>ServletRequestListener</tt> is used by the registry to notify
* registered {@link org.apache.lucene.gdata.server.registry.ScopeVisitor}
* implementations when a request is initialized e.g destroyed.
*
*
* @see org.apache.lucene.gdata.server.registry.ScopeVisitable
* @see javax.servlet.ServletRequestListener
* @author Simon Willnauer
*
*/
@Scope(scope = ScopeType.REQUEST)
public class GDataRequestListener implements ServletRequestListener,
ScopeVisitable {
private final GDataServerRegistry registry;
private final List<ScopeVisitor> visitors = new ArrayList<ScopeVisitor>(5);
private static final Log LOG = LogFactory
.getLog(GDataRequestListener.class);
/**
* @throws RegistryException
*
*/
public GDataRequestListener() throws RegistryException {
this.registry = GDataServerRegistry.getRegistry();
this.registry.registerScopeVisitable(this);
}
/**
* @see javax.servlet.ServletRequestListener#requestDestroyed(javax.servlet.ServletRequestEvent)
*/
public void requestDestroyed(ServletRequestEvent arg0) {
for (ScopeVisitor visitor : this.visitors) {
visitor.visiteDestroy();
}
}
/**
* @see javax.servlet.ServletRequestListener#requestInitialized(javax.servlet.ServletRequestEvent)
*/
public void requestInitialized(ServletRequestEvent arg0) {
for (ScopeVisitor visitor : this.visitors) {
visitor.visiteInitialize();
}
}
/**
* @see org.apache.lucene.gdata.server.registry.ScopeVisitable#accept(org.apache.lucene.gdata.server.registry.ScopeVisitor)
*/
public void accept(ScopeVisitor visitor) {
if (!this.visitors.contains(visitor) && visitor != null) {
this.visitors.add(visitor);
if(LOG.isDebugEnabled())
LOG.debug("visitor added -- " + visitor.getClass());
}
}
}

View File

@ -15,11 +15,16 @@
*/
package org.apache.lucene.gdata.server.registry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.server.registry.configuration.ComponentConfiguration;
import org.apache.lucene.gdata.server.registry.configuration.PropertyInjector;
/**
*
@ -41,7 +46,9 @@ import org.apache.commons.logging.LogFactory;
* 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>
* <p>
* The GDataServerRegistry is a Singleton
* </p>
*
*
* @author Simon Willnauer
@ -53,10 +60,18 @@ public class GDataServerRegistry {
private static final Log LOGGER = LogFactory
.getLog(GDataServerRegistry.class);
private ScopeVisitable requestVisitable;
private ScopeVisitable sessionVisitable;
//not available yet
private ScopeVisitable contextVisitable;
private List<ScopeVisitor> visitorBuffer = new ArrayList<ScopeVisitor>(5);
private final Map<String, ProvidedService> serviceTypeMap = new HashMap<String, ProvidedService>();
private final Map<ComponentType, ComponentBean> componentMap = new HashMap<ComponentType, ComponentBean>(
10);
ComponentType.values().length);
private GDataServerRegistry() {
// private - singleton
@ -85,6 +100,72 @@ public class GDataServerRegistry {
this.serviceTypeMap.put(configurator.getName(), configurator);
}
/**
* @param visitor -
* the visitor to register
* @throws RegistryException
*/
public synchronized void registerScopeVisitor(final ScopeVisitor visitor)
throws RegistryException {
if (visitor == null)
throw new IllegalArgumentException("visitor must not be null");
Scope scope = visitor.getClass().getAnnotation(Scope.class);
if (scope == null)
throw new RegistryException("Visitor has not Scope");
if (LOGGER.isInfoEnabled())
LOGGER.info("Register scope visitor -- " + visitor.getClass());
if (scope.scope().equals(Scope.ScopeType.REQUEST)
&& this.requestVisitable != null)
this.requestVisitable.accept(visitor);
else if (scope.scope() == Scope.ScopeType.SESSION
&& this.sessionVisitable != null)
this.sessionVisitable.accept(visitor);
else if (scope.scope() == Scope.ScopeType.CONTEXT
&& this.contextVisitable != null)
this.sessionVisitable.accept(visitor);
else if (!this.visitorBuffer.contains(visitor))
this.visitorBuffer.add(visitor);
}
/**
* @param visitable -
* the instance to register
* @throws RegistryException
* @see ScopeVisitable
*/
public synchronized void registerScopeVisitable(
final ScopeVisitable visitable) throws RegistryException {
if (visitable == null)
throw new IllegalArgumentException("visitable must not be null");
Scope scope = visitable.getClass().getAnnotation(Scope.class);
if (scope == null)
throw new RegistryException("Visitable has not Scope");
if (LOGGER.isInfoEnabled())
LOGGER.info("Register scope visitable -- " + visitable.getClass());
if (scope.scope() == Scope.ScopeType.REQUEST
&& this.requestVisitable == null)
this.requestVisitable = visitable;
else if (scope.scope() == Scope.ScopeType.SESSION
&& this.sessionVisitable == null)
this.sessionVisitable = visitable;
else if (scope.scope() == Scope.ScopeType.CONTEXT
&& this.contextVisitable == null)
this.sessionVisitable = visitable;
if (!this.visitorBuffer.isEmpty()) {
List<ScopeVisitor> tempList = this.visitorBuffer;
this.visitorBuffer = new ArrayList<ScopeVisitor>(5);
for (ScopeVisitor visitor : tempList) {
registerScopeVisitor(visitor);
}
tempList.clear();
}
}
/**
* Looks up the {@link ProvidedServiceConfig} by the given service name.
*
@ -100,6 +181,10 @@ public class GDataServerRegistry {
}
protected void flushRegistry() {
Collection<ProvidedService> services = this.serviceTypeMap.values();
for (ProvidedService service : services) {
service.destroy();
}
this.serviceTypeMap.clear();
this.componentMap.clear();
}
@ -122,6 +207,7 @@ public class GDataServerRegistry {
for (ComponentBean component : this.componentMap.values()) {
component.getObject().destroy();
}
flushRegistry();
}
@ -157,23 +243,51 @@ public class GDataServerRegistry {
}
/**
* @param <E>
* @param componentClass
* @throws RegistryException
* All registered {@link ServerComponent} registered via this method are
* available via the
* {@link GDataServerRegistry#lookup(Class, ComponentType)} method. For each
* {@link ComponentType} there will be one single instance registered in the
* registry.
* <p>
* Eventually this method invokes the initialize method of the
* ServerComponent interface to prepare the component to be available via
* the lookup service
* </p>
*
* @param <E> -
* The interface of the component to register
* @param componentClass -
* a implementation of a ServerComponent interface to register in
* the registry
* @param configuration -
* the component configuration {@link ComponentConfiguration}
* @throws RegistryException -
* if the provided class does not implement the
* {@link ServerComponent} interface, if the mandatory
* annotations not visible at runtime or not set, if the super
* type provided by the {@link ComponentType} for the class to
* register is not a super type of the class or if the
* invokation of the {@link ServerComponent#initialize()} method
* throws an exception.
*/
@SuppressWarnings("unchecked")
public <E extends ServerComponent> void registerComponent(final Class<E> componentClass)
public <E extends ServerComponent> void registerComponent(
final Class<E> componentClass,
final ComponentConfiguration configuration)
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());
if (!checkSuperType(componentClass, ServerComponent.class))
throw new RegistryException(
"can not register component. the given class does not implement ServerComponent interface -- "
+ componentClass.getName());
try {
Component annotation = componentClass.getAnnotation(Component.class);
Component annotation = componentClass
.getAnnotation(Component.class);
if (annotation == null)
throw new RegistryException(
"can not register component. the given class is not a component -- "
@ -189,49 +303,53 @@ public class GDataServerRegistry {
+ superType.getName() + "> is not a super type of <"
+ componentClass + ">");
ServerComponent comp = componentClass.newInstance();
if (configuration == null) {
if (LOGGER.isInfoEnabled())
LOGGER.info("no configuration for ComponentType: "
+ type.name());
} else
configureComponent(comp, type, configuration);
comp.initialize();
ComponentBean bean = new ComponentBean(comp, superType);
this.componentMap.put(type, bean);
this.componentMap.put(type, bean);
if (checkSuperType(componentClass, ScopeVisitor.class))
this.registerScopeVisitor((ScopeVisitor) comp);
} catch (Exception e) {
e.printStackTrace();
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());
/*
* Injects the configured properties located in the configuration into the
* given server component
*/
private void configureComponent(final ServerComponent component,
final ComponentType type, final ComponentConfiguration configuration) {
PropertyInjector injector = new PropertyInjector();
injector.setTargetObject(component);
injector.injectProperties(configuration);
}
private static boolean checkSuperType(Class type, Class consideredSuperType) {
if (type == null)
return false;
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))
if (checkSuperType(interfaces[i], consideredSuperType))
return true;
}
return checkSuperType(type.getSuperclass(), consideredSuperType);
}
private class ComponentBean {
private static class ComponentBean {
private final Class superType;
private final ServerComponent object;

View File

@ -45,4 +45,9 @@ public interface ProvidedService {
*/
public abstract String getName();
/**
* releases all dependencies and resources
*/
public abstract void destroy();
}

View File

@ -15,6 +15,14 @@
*/
package org.apache.lucene.gdata.server.registry;
import java.lang.reflect.Constructor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.utils.Pool;
import org.apache.lucene.gdata.utils.PoolObjectFactory;
import org.apache.lucene.gdata.utils.SimpleObjectPool;
import com.google.gdata.data.ExtensionProfile;
/**
@ -22,11 +30,40 @@ import com.google.gdata.data.ExtensionProfile;
* {@link org.apache.lucene.gdata.server.registry.ProvidedService} to be used
* inside the
* {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry}
* <p>
* ExtensionProfiles are used to generate and parse xml by the gdata api. For
* that case all methodes are synchronized. This will slow down the application
* when performing lots of xml generation concurrently. For that case the
* extensionProfile for a specific service will be pooled and reused.
* </p>
*
*
* @author Simon Willnauer
*
*/
public class ProvidedServiceConfig implements ProvidedService {
@Scope(scope = Scope.ScopeType.REQUEST)
public class ProvidedServiceConfig implements ProvidedService, ScopeVisitor {
private final static Log LOG = LogFactory
.getLog(ProvidedServiceConfig.class);
private static final int DEFAULT_POOL_SIZE = 5;
/*
* To ensure a extensionprofile instance will not be shared within multiple
* threads each thread requesting a config will have one instance for the
* entire request.
*/
private final ThreadLocal<ExtensionProfile> extProfThreadLocal = new ThreadLocal<ExtensionProfile>();
/*
* ExtensionProfiles are used to generate and parse xml by the gdata api.
* For that case all methodes are synchronized. This will slow down the
* application when performing lots of xml generation concurrently. for that
* case the extensionProfile for a specific service will be pooled and
* reused.
*/
private Pool<ExtensionProfile> profilPool;
private String serviceName;
private Class entryType;
@ -35,21 +72,35 @@ public class ProvidedServiceConfig implements ProvidedService {
private ExtensionProfile extensionProfile;
ProvidedServiceConfig(ExtensionProfile profile, Class feedType,
Class entryType, String serviceName) {
this.extensionProfile = profile;
this.feedType = feedType;
this.entryType = entryType;
this.serviceName = serviceName;
private int poolSize = DEFAULT_POOL_SIZE;
/**
* @return Returns the poolSize.
*/
public int getPoolSize() {
return this.poolSize;
}
/**
* Default constructor to instanciate via reflection
* @param poolSize
* The poolSize to set.
*/
public void setPoolSize(int poolSize) {
this.poolSize = poolSize >= DEFAULT_POOL_SIZE ? poolSize
: DEFAULT_POOL_SIZE;
}
/**
* Default constructor to instanciate via reflection
*/
public ProvidedServiceConfig() {
//
try {
GDataServerRegistry.getRegistry().registerScopeVisitor(this);
} catch (RegistryException e) {
throw new RuntimeException("Can not register ScopeVisitor -- "
+ e.getMessage(), e);
}
}
/**
@ -71,20 +122,44 @@ public class ProvidedServiceConfig implements ProvidedService {
* @see org.apache.lucene.gdata.server.registry.ProvidedService#getExtensionProfile()
*/
public ExtensionProfile getExtensionProfile() {
return this.extensionProfile;
ExtensionProfile ext = this.extProfThreadLocal.get();
if (ext != null) {
return ext;
}
if (this.profilPool == null)
createProfilePool();
ext = this.profilPool.aquire();
this.extProfThreadLocal.set(ext);
return ext;
}
/**
* @param extensionProfil -
* the extensionprofile for this feed configuration
*/
@SuppressWarnings("unchecked")
public void setExtensionProfile(ExtensionProfile extensionProfil) {
if (extensionProfil == null)
throw new IllegalArgumentException(
"ExtensionProfile must not be null");
if (this.extensionProfile != null)
return;
this.extensionProfile = extensionProfil;
}
private void createProfilePool() {
if (LOG.isInfoEnabled())
LOG.info("Create ExtensionProfile pool with poolsize:"
+ this.poolSize + " for service " + this.serviceName);
this.profilPool = new SimpleObjectPool<ExtensionProfile>(this.poolSize,
new ExtensionProfileFactory<ExtensionProfile>(
this.extensionProfile.getClass()));
}
/**
*TODO add comment
* TODO add comment
*
* @param <E>
* @param extensionProfileClass
* @throws InstantiationException
@ -97,7 +172,8 @@ public class ProvidedServiceConfig implements ProvidedService {
throw new IllegalArgumentException(
"ExtensionProfile class must not be null");
this.extensionProfile = extensionProfileClass.newInstance();
setExtensionProfile(extensionProfileClass.newInstance());
}
/**
@ -106,7 +182,7 @@ public class ProvidedServiceConfig implements ProvidedService {
public Class getEntryType() {
return this.entryType;
}
/**
* @param entryType
*/
@ -128,4 +204,95 @@ public class ProvidedServiceConfig implements ProvidedService {
this.serviceName = serviceName;
}
/**
* @see org.apache.lucene.gdata.server.registry.ProvidedService#destroy()
*/
public void destroy() {
if (this.profilPool != null)
this.profilPool.destroy();
if (LOG.isInfoEnabled())
LOG.info("Destroy Service " + this.serviceName
+ " -- release all resources");
this.feedType = null;
this.entryType = null;
this.extensionProfile = null;
}
private static class ExtensionProfileFactory<Type extends ExtensionProfile>
implements PoolObjectFactory<Type> {
private final Class<? extends ExtensionProfile> clazz;
private final Constructor<? extends ExtensionProfile> constructor;
private static final Object[] constArray = new Object[0];
ExtensionProfileFactory(Class<? extends ExtensionProfile> clazz) {
this.clazz = clazz;
try {
this.constructor = clazz.getConstructor(new Class[0]);
} catch (Exception e) {
throw new IllegalArgumentException(
"The given class has no defaul constructor -- can not use as a ExtensionProfile -- "
+ this.clazz.getName(), e);
}
}
/**
* @see org.apache.lucene.gdata.utils.PoolObjectFactory#getInstance()
*/
@SuppressWarnings("unchecked")
public Type getInstance() {
try {
return (Type) this.constructor.newInstance(constArray);
} catch (Exception e) {
throw new RuntimeException(
"Can not instanciate new ExtensionProfile -- ", e);
}
}
/**
* @param type -
* the ExtensionProfile to destroy
* @see org.apache.lucene.gdata.utils.PoolObjectFactory#destroyInstance(Object)
*/
public void destroyInstance(Type type) {
//
}
}
/**
* @see org.apache.lucene.gdata.server.registry.ScopeVisitor#visiteInitialize()
*/
public void visiteInitialize() {
if(this.profilPool == null)
createProfilePool();
/*
* don't set a extension profile for each thread. The current thread
* might use another service and does not need the extensionprofile of
* this service
*/
}
/**
* @see org.apache.lucene.gdata.server.registry.ScopeVisitor#visiteDestroy()
*/
public void visiteDestroy() {
/*
* Check every thread after request destroyed to release all profiles to
* the pool
*/
ExtensionProfile ext = this.extProfThreadLocal.get();
if (ext == null) {
if(LOG.isDebugEnabled())
LOG.debug("ThreadLocal owns no ExtensionProfile in requestDestroy for service "
+ this.serviceName);
return;
}
this.extProfThreadLocal.set(null);
this.profilPool.release(ext);
}
}

View File

@ -18,6 +18,8 @@ package org.apache.lucene.gdata.server.registry;
import java.io.IOException;
import org.apache.commons.digester.Digester;
import org.apache.lucene.gdata.server.registry.configuration.ComponentConfiguration;
import org.apache.lucene.gdata.utils.SimpleSaxErrorHandler;
import org.xml.sax.SAXException;
/**
@ -49,11 +51,14 @@ class RegistryBuilder {
private static void buildFromConfiguration(Digester digester,
GDataServerRegistry registry) throws IOException, SAXException {
digester.setValidating(false);
String schemaFile = RegistryBuilder.class.getResource("/gdata-config.xsd").getFile();
digester.setValidating(true);
digester.setSchema(schemaFile);
digester.setErrorHandler(new SimpleSaxErrorHandler());
digester.push(registry);
digester.addCallMethod("gdata/server-components/component",
"registerComponent", 0, new Class[] { Class.class });
/*
* register services
*/
digester.addObjectCreate("gdata/service", ProvidedServiceConfig.class);
digester.addSetProperties("gdata/service");
digester.addSetNext("gdata/service", "registerService");
@ -61,10 +66,22 @@ class RegistryBuilder {
digester.addBeanPropertySetter("gdata/service/entry-class", "entryType");
digester.addBeanPropertySetter("gdata/service/extension-profile",
"extensionProfileClass");
/*
* load components and configurations
*/
digester.addCallMethod("gdata/server-components/component",
"registerComponent", 2, new Class[] { Class.class , ComponentConfiguration.class});
digester.addCallParam("gdata/server-components/component/class",0);
digester.addObjectCreate("gdata/server-components/component/configuration",ComponentConfiguration.class);
digester.addCallMethod("gdata/server-components/component/configuration/property","set",2,new Class[]{String.class,String.class});
digester.addCallParam("gdata/server-components/component/configuration/property",0,"name");
digester.addCallParam("gdata/server-components/component/configuration/property",1);
digester.addCallParam("gdata/server-components/component/configuration",1,0);
digester.parse(RegistryBuilder.class
.getResourceAsStream("/gdata-config.xml"));
}
}

View File

@ -0,0 +1,63 @@
/**
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.gdata.server.registry;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* The Scope annotation is used in
* {@link org.apache.lucene.gdata.server.registry.ScopeVisitable} and
* {@link org.apache.lucene.gdata.server.registry.ScopeVisitor} implementations
* to indicate which scope should be visited.
*
* @author Simon Willnauer
*
*/
@Target( { TYPE })
@Retention(value = RUNTIME)
public @interface Scope {
/**
* @return - the scope type the class was annotated with
*/
ScopeType scope();
/**
* Defines a Scope for {@link Scope} annotations
*
* @author Simon Willnauer
*
*/
public static enum ScopeType {
/**
* Request scope
*/
REQUEST,
/**
* Session scope
*/
SESSION,
/**
* Context scope
*/
CONTEXT
}
}

View File

@ -0,0 +1,33 @@
/**
* 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;
/**
* Implementation of this interface accept
* {@link org.apache.lucene.gdata.server.registry.ScopeVisitor} objects and call
* their methods on the desired action.
*
* @author Simon Willnauer
*
*/
public interface ScopeVisitable {
/**
* @param visitor -
* the visitor to accept
*/
public abstract void accept(ScopeVisitor visitor);
}

View File

@ -0,0 +1,55 @@
/**
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.gdata.server.registry;
/**
* <p>
* <code>ScopeVisitor</code> is used to implement the <code>Visitor</code>
* pattern in GDATAServer. An object of this interface can be passed to a
* <code>ScopeVistable</code> which will then call its methods. <br/>
* {@link org.apache.lucene.gdata.server.registry.Component} Classes registered
* in the {@link org.apache.lucene.gdata.server.registry.GDataServerRegistry}
* will be added to the Visitableimplementation automatically. Please refer to
* the <i>Gang of Four </i> book of Design Patterns for more details on the
* <code>Visitor</code> pattern.
* </p>
* <p>
* A scope can be Session, Request or Context if one of the ScopeVisitors for
* the desired scope is available by the registry.
* </p>
* <p>
* This <a href="http://www.patterndepot.com/put/8/JavaPatterns.htm">site </a>
* has further discussion on design patterns and links to the GOF book. This <a
* href="http://www.patterndepot.com/put/8/visitor.pdf">link </a> describes the
* Visitor pattern in detail.
* </p>
*
* @author Simon Willnauer
*
*/
public interface ScopeVisitor {
/**
* Visites the initialization of the scope
*/
public abstract void visiteInitialize();
/**
* Visites the destory of the scope
*
*/
public abstract void visiteDestroy();
}

View File

@ -60,7 +60,7 @@ public abstract class AbstractAccountHandler extends RequestAuthenticator
@SuppressWarnings("unused")
public void processRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
try{
this.authenticated = authenticateAccount(request,
AccountRole.USERADMINISTRATOR);
@ -92,6 +92,10 @@ public abstract class AbstractAccountHandler extends RequestAuthenticator
setError(HttpServletResponse.SC_UNAUTHORIZED,"Authorization failed");
}
sendResponse(response);
}finally{
if(this.service!=null)
this.service.close();
}
}

View File

@ -141,7 +141,7 @@ public abstract class AbstractFeedHandler extends RequestAuthenticator implement
return this.errorMessage;
}
class FeedHandlerException extends Exception{
static class FeedHandlerException extends Exception{
/**
*

View File

@ -41,7 +41,10 @@ public abstract class AbstractGdataRequestHandler extends RequestAuthenticator i
GDataRequestHandler {
private final static Log LOG = LogFactory
.getLog(AbstractGdataRequestHandler.class);
/*
* UTF-8 is the encoding used in the client API to send the entries to the server
*/
private final static String ENCODING = "UTF-8";
protected Service service;
protected GDataRequest feedRequest;
protected GDataResponse feedResponse;
@ -57,6 +60,7 @@ public abstract class AbstractGdataRequestHandler extends RequestAuthenticator i
throws GDataRequestException, ServletException {
this.feedRequest = new GDataRequest(request, type);
this.feedResponse = new GDataResponse(response);
this.feedResponse.setEncoding(ENCODING);
getService();
try {
this.feedRequest.initializeRequest();

View File

@ -100,8 +100,14 @@ public class AuthenticationHandler implements GDataRequestHandler {
private GDataAccount getAccount(String accountName) throws ServiceException{
AdminService service = this.serviceFactory.getAdminService();
try{
return service.getAccount(accountName);
}finally{
service.close();
}
}
private void sendError(HttpServletResponse response, int code, String message)throws IOException{

View File

@ -75,9 +75,9 @@ public class DefaultDeleteHandler extends AbstractGdataRequestHandler {
LOG.error("Could not process DeleteFeed request - "
+ e.getMessage(), e);
sendError();
}
}finally{
closeService();
}
}
}

View File

@ -102,9 +102,9 @@ public class DefaultGetHandler extends AbstractGdataRequestHandler {
LOG.error("Could not process GetFeed request - " + e.getMessage(),
e);
sendError();
}
}finally{
closeService();
}
}
/**

View File

@ -78,9 +78,9 @@ public class DefaultInsertHandler extends AbstractGdataRequestHandler {
}catch (ServiceException e) {
LOG.error("Could not process GetFeed request - "+e.getMessage(),e);
this.feedResponse.sendError();
}
}finally{
closeService();
}
}
}

View File

@ -82,8 +82,9 @@ public class DefaultUpdateHandler extends AbstractGdataRequestHandler {
LOG.error("Could not process UpdateFeed request - "
+ e.getMessage(), e);
sendError();
}
}finally{
closeService();
}
}
}

View File

@ -26,6 +26,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.gdata.data.ServerBaseFeed;
import org.apache.lucene.gdata.server.ServiceFactory;
import org.apache.lucene.gdata.server.administration.AdminService;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
@ -44,6 +45,7 @@ public class DeleteFeedHandler extends AbstractFeedHandler{
public void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
super.processRequest(request,response);
if(this.authenticated){
AdminService service = null;
try {
ServerBaseFeed feed = createDeleteFeed(request);
@ -53,13 +55,17 @@ public class DeleteFeedHandler extends AbstractFeedHandler{
setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"required component is not available");
throw new FeedHandlerException("Can't save feed - ServiceFactory is null");
}
serviceFactory.getAdminService().deleteFeed(feed);
service = serviceFactory.getAdminService();
service.deleteFeed(feed);
} catch (FeedHandlerException e) {
LOG.error("Can not delete feed -- "+e.getMessage(),e);
}catch (Exception e) {
LOG.error("Can not delete feed -- "+e.getMessage(),e);
setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"can not create feed");
}
}finally{
if(service != null)
service.close();
}
}
sendResponse(response);

View File

@ -28,6 +28,7 @@ import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.data.ServerBaseFeed;
import org.apache.lucene.gdata.server.ServiceException;
import org.apache.lucene.gdata.server.ServiceFactory;
import org.apache.lucene.gdata.server.administration.AdminService;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
@ -47,6 +48,7 @@ public class InsertFeedHandler extends AbstractFeedHandler {
HttpServletResponse response) throws ServletException, IOException {
super.processRequest(request, response);
if (this.authenticated) {
AdminService service = null;
try {
ServerBaseFeed feed = createFeedFromRequest(request);
GDataAccount account = createRequestedAccount(request);
@ -61,7 +63,8 @@ public class InsertFeedHandler extends AbstractFeedHandler {
throw new FeedHandlerException(
"Can't save feed - ServiceFactory is null");
}
serviceFactory.getAdminService().createFeed(feed, account);
service = serviceFactory.getAdminService();
service.createFeed(feed, account);
} catch (ServiceException e) {
setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"can not create feed");
@ -69,6 +72,9 @@ public class InsertFeedHandler extends AbstractFeedHandler {
} catch (Exception e) {
LOG.error("Can not create feed -- " + e.getMessage(), e);
}finally{
if(service != null)
service.close();
}
}

View File

@ -92,6 +92,11 @@ public class RequestAuthenticator implements GDataHttpAuthenticator {
+ request.getFeedId(), e);
throw new AuthenticatorException(" Service exception occured", e);
}finally{
if(adminService!=null)
adminService.close();
}
return false;

View File

@ -28,6 +28,7 @@ import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.data.ServerBaseFeed;
import org.apache.lucene.gdata.server.ServiceException;
import org.apache.lucene.gdata.server.ServiceFactory;
import org.apache.lucene.gdata.server.administration.AdminService;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
@ -48,6 +49,7 @@ public class UpdateFeedHandler extends AbstractFeedHandler {
HttpServletResponse response) throws ServletException, IOException {
super.processRequest(request, response);
if (this.authenticated) {
AdminService service= null;
try {
ServerBaseFeed feed = createFeedFromRequest(request);
GDataAccount account = createRequestedAccount(request);
@ -62,7 +64,8 @@ public class UpdateFeedHandler extends AbstractFeedHandler {
throw new FeedHandlerException(
"Can't update feed - ServiceFactory is null");
}
serviceFactory.getAdminService().updateFeed(feed, account);
service = serviceFactory.getAdminService();
service.updateFeed(feed, account);
} catch (ServiceException e) {
setError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"can not update feed");
@ -71,10 +74,13 @@ public class UpdateFeedHandler extends AbstractFeedHandler {
LOG.error("Can not update feed -- " + e.getMessage(), e);
}finally{
if(service != null)
service.close();
}
}
sendResponse(response);
}
}

View File

@ -21,6 +21,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -41,6 +42,8 @@ import org.apache.commons.logging.LogFactory;
*
*/
public class IDGenerator {
final AtomicBoolean stopped = new AtomicBoolean(false);
private final SecureRandom secureRandom;
private final MessageDigest mdigest;
@ -110,8 +113,10 @@ public class IDGenerator {
/**
* Stops the id-producer
*/
public void stopIDGenerator() {
public void stopIDGenerator() {
this.stopped.set(true);
this.runner.interrupt();
}
private class UIDProducer implements Runnable {
@ -134,10 +139,10 @@ public class IDGenerator {
*/
public void run() {
while (true) {
while (!IDGenerator.this.stopped.get()) {
try {
this.queue.put(produce());
} catch (InterruptedException e) {
} catch (InterruptedException e) {
LOGGER
.warn("UIDProducer has been interrupted -- runner is going down");
return;
@ -147,7 +152,7 @@ public class IDGenerator {
}
private String produce() {
String randomNumber = new Integer(this.random.nextInt()).toString();
String randomNumber = Integer.toString(this.random.nextInt());
byte[] byteResult = this.digest.digest(randomNumber.getBytes());
return hexEncode(byteResult);
}

View File

@ -0,0 +1,75 @@
/**
* 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;
/**
* This exception will be thrown if a Version conflict occures while updateing
* or deleteing an entry. Or if one entry is modified concurrently.
*
* @author Simon Willnauer
*
*/
public class ModificationConflictException extends StorageException {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* Constructs a new ModificationConflictException
*/
public ModificationConflictException() {
super();
}
/**
* Constructs a new ModificationConflictException
*
* @param message -
* the exception message
*/
public ModificationConflictException(String message) {
super(message);
}
/**
* Constructs a new ModificationConflictException
*
* @param message -
* the exception message
* @param cause -
* the root cause of this exception
*/
public ModificationConflictException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new ModificationConflictException
*
* @param cause -
* the root cause of this exception
*/
public ModificationConflictException(Throwable cause) {
super(cause);
}
}

View File

@ -212,6 +212,8 @@ public interface Storage {
throws StorageException;
/**
*
* Retrieves the {@link GDataAccount} for the given account name
* @param accountName -
* the name of the requested account
* @return - a {@link GDataAccount} instance for the requested account name

View File

@ -58,4 +58,10 @@ public interface StorageController extends ServerComponent {
* if the storage instance can not be created
*/
public abstract Storage getStorage() throws StorageException;
/**
* Releases a new unique ID
* @return - unique ID
*/
public abstract String releaseId();
}

View File

@ -23,7 +23,7 @@ package org.apache.lucene.gdata.storage;
* @author Simon Willnauer
*
*/
public class StorageException extends Exception {
public class StorageException extends RuntimeException {
/**
*

View File

@ -0,0 +1,50 @@
/**
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.gdata.storage.lucenestorage;
/**
*
* @author Simon Willnauer
*
*/
public interface ConcurrentStorageLock {
/**
* @param key
* @return
*/
public abstract boolean setLock(final String key);
/**
* @param key
* @return
*/
public abstract boolean releaseLock(final String key);
/**
* @return
*/
public abstract boolean releaseThreadLocks();
/**
* @param key
* @return
*/
public abstract boolean isKeyLocked(final String key);
/**
*
*/
public abstract void close();
}

View File

@ -0,0 +1,175 @@
/**
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.gdata.storage.lucenestorage;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author Simon Willnauer
*
*/
public class SingleHostConcurrentStorageLock implements ConcurrentStorageLock {
private volatile static ConcurrentStorageLock INSTANCE = null;
private final Map<String,Thread> locks;
private final Map<Thread,String> threads;
private final ReentrantReadWriteLock synLock = new ReentrantReadWriteLock();
private final Lock readLock = this.synLock.readLock();
private final Lock writeLock = this.synLock.writeLock();
private final AtomicBoolean isClosed = new AtomicBoolean(false);
/**
*
*/
private SingleHostConcurrentStorageLock() {
super();
this.locks = new HashMap<String,Thread>(10);
this.threads = new HashMap<Thread,String>(10);
}
protected static synchronized ConcurrentStorageLock getConcurrentStorageLock(){
if(INSTANCE == null)
INSTANCE = new SingleHostConcurrentStorageLock();
return INSTANCE;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.ConcurrentStorageLock#setLock(java.lang.String)
*/
public boolean setLock(String key) {
this.writeLock.lock();
try{
if(this.isClosed.get())
throw new IllegalStateException("Lock has been closed");
Thread t = Thread.currentThread();
if(this.threads.containsKey(t))
throw new ConcurrencyException("one thread must not obtain more than one lock -- single thread can not modify more than one resource");
if(this.locks.containsKey(key)){
return false;
}
this.locks.put(key, t);
this.threads.put(t,key);
return true;
}finally{
this.writeLock.unlock();
}
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.ConcurrentStorageLock#releaseLock(java.lang.String)
*/
public boolean releaseLock(String key) {
this.writeLock.lock();
try{
if(this.isClosed.get())
throw new IllegalStateException("Lock has been closed");
Thread t = Thread.currentThread();
if(!this.threads.containsKey(t))
return false;
if(!this.locks.containsKey(key))
return false;
if(t != this.locks.get(key))
throw new ConcurrencyException("Illegal lock access -- current thread is not owner");
this.locks.remove(key);
this.threads.remove(t);
return true;
}finally{
this.writeLock.unlock();
}
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.ConcurrentStorageLock#releaseThreadLocks()
*/
public boolean releaseThreadLocks() {
this.writeLock.lock();
try{
if(this.isClosed.get())
throw new IllegalStateException("Lock has been closed");
Thread t = Thread.currentThread();
if(!this.threads.containsKey(t))
return false;
String key = this.threads.get(t);
this.threads.remove(t);
if(!this.locks.containsKey(key))
return false;
this.locks.remove(key);
return true;
}finally{
this.writeLock.unlock();
}
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.ConcurrentStorageLock#isKeyLocked(java.lang.String)
*/
public boolean isKeyLocked(String key) {
this.readLock.lock();
try{
if(this.isClosed.get())
throw new IllegalStateException("Lock has been closed");
return this.locks.containsKey(key);
}finally{
this.readLock.unlock();
}
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.ConcurrentStorageLock#close()
*/
public void close() {
this.writeLock.lock();
try{
if(this.isClosed.get())
throw new IllegalStateException("Lock has been closed");
this.isClosed.set(true);
this.locks.clear();
this.threads.clear();
INSTANCE = new SingleHostConcurrentStorageLock();
}finally{
this.writeLock.unlock();
}
}
protected void forceClear(){
this.writeLock.lock();
try{
if(this.isClosed.get())
throw new IllegalStateException("Lock has been closed");
this.locks.clear();
this.threads.clear();
}finally{
this.writeLock.unlock();
}
}
static class ConcurrencyException extends RuntimeException{
private static final long serialVersionUID = 6388236477729760962L;
ConcurrencyException(String message){
super(message);
}
}
}

View File

@ -52,6 +52,10 @@ import com.google.gdata.data.Link;
* The read lock may be held simultaneously by multiple reader threads, so long
* as there are no writers. The write lock is exclusive.
* </p>
* <p>
* The entry and feed ID's must not be a composite key. The entry and feed ID
* must be unique.
* </p>
*
* @see java.util.concurrent.locks.ReentrantReadWriteLock
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageModifier
@ -61,255 +65,294 @@ import com.google.gdata.data.Link;
*
*/
public class StorageBuffer {
private static final Log LOG = LogFactory.getLog(StorageBuffer.class);
private static final Log LOG = LogFactory.getLog(StorageBuffer.class);
private final Map<String, Map<String, StorageEntryWrapper>> bufferMap;
private final Map<String, Map<String, StorageEntryWrapper>> bufferMap;
private final Map<String, Long> modifiyMap;
private final Map<String, Long> modifiyMap;
private final List<String> excludeList;
private final List<String> excludeList;
private final ReadWriteLock lock = new ReentrantReadWriteLock(true);
private final ReadWriteLock lock = new ReentrantReadWriteLock(true);
private final Lock readLock = this.lock.readLock();
private final Lock readLock = this.lock.readLock();
private final Lock writeLock = this.lock.writeLock();
private final Lock writeLock = this.lock.writeLock();
private final static int DEFAULT_BUFFER_COUNT = 10;
private final int bufferSize;
/**
* Constructs a new StorageBuffer.
* <p>
* The expectedBufferCount sould be higher than the maximum of entries added
* to the buffer, resizing the buffer is very efficient. For detailed
* infomation {@link HashMap} as this is used inside the buffer
* </p>
*
* @param expectedBufferCount -
* the expected size of the buffer
*
*/
protected StorageBuffer(final int expectedBufferCount) {
this.bufferMap = new HashMap<String, Map<String, StorageEntryWrapper>>(
expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT
: expectedBufferCount);
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);
}
protected final static int DEFAULT_BUFFER_COUNT = 10;
/**
* Adds a {@link StorageEntryWrapper} to the buffer. If a wrapper
* representing the same entry are already in the buffer the wrapper will be
* replaced.
*
* @param wrapper -
* the wrapper to buffer
*/
public void addEntry(final StorageEntryWrapper wrapper) {
this.writeLock.lock();
try {
if (LOG.isInfoEnabled())
LOG.info(" Buffering wrapper - " + wrapper.getOperation()
+ " ID: " + wrapper.getEntryId() + " FeedID: "
+ wrapper.getFeedId());
if (wrapper.getOperation().equals(StorageOperation.DELETE))
return;
/**
* Constructs a new StorageBuffer.
* <p>
* The expectedBufferCount sould be higher than the maximum of entries added
* to the buffer, resizing the buffer is very efficient. For detailed
* infomation {@link HashMap} as this is used inside the buffer
* </p>
*
* @param expectedBufferCount -
* the expected size of the buffer
*
*/
protected StorageBuffer(final int expectedBufferCount) {
this.bufferSize = expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT
: expectedBufferCount;
this.bufferMap = new HashMap<String, Map<String, StorageEntryWrapper>>(
this.bufferSize);
this.excludeList = new ArrayList<String>(this.bufferSize);
this.modifiyMap = new HashMap<String, Long>(this.bufferSize);
}
String feedId = wrapper.getFeedId();
if (this.bufferMap.containsKey(feedId))
this.bufferMap.get(feedId).put(wrapper.getEntryId(), wrapper);
else {
Map<String, StorageEntryWrapper> newFeedMap = new HashMap<String, StorageEntryWrapper>(
20);
newFeedMap.put(wrapper.getEntryId(), wrapper);
this.bufferMap.put(feedId, newFeedMap);
/**
* Adds a {@link StorageEntryWrapper} to the buffer. If a wrapper
* representing the same entry are already in the buffer the wrapper will be
* replaced.
* <p>
* This method does ignore already delted entries. This should before the
* entry is added to the buffer.
* </p>
*
* @param wrapper -
* the wrapper to buffer
*/
public void addEntry(final StorageEntryWrapper wrapper) {
this.writeLock.lock();
try {
if (LOG.isInfoEnabled())
LOG.info(" Buffering wrapper - " + wrapper.getOperation()
+ " ID: " + wrapper.getEntryId() + " FeedID: "
+ wrapper.getFeedId());
if (wrapper.getOperation().equals(StorageOperation.DELETE))
return;
String feedId = wrapper.getFeedId();
if (this.bufferMap.containsKey(feedId))
this.bufferMap.get(feedId).put(wrapper.getEntryId(), wrapper);
else {
Map<String, StorageEntryWrapper> newFeedMap = new HashMap<String, StorageEntryWrapper>(
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
* buffer
*/
this.excludeList.add(wrapper.getEntryId());
this.writeLock.unlock();
}
}
}
addLastModified(wrapper.getFeedId(), wrapper.getTimestamp());
/*
* add to exclude from searches doc will be available via the buffer
* if the entry is not already in the buffer
*/
if (!this.excludeList.contains(wrapper.getEntryId()))
this.excludeList.add(wrapper.getEntryId());
} finally {
this.writeLock.unlock();
}
}
private void addLastModified(final String feedId, Long timestamp) {
if (this.modifiyMap.containsKey(feedId))
this.modifiyMap.remove(feedId);
this.modifiyMap.put(feedId, timestamp);
private void addLastModified(final String feedId, Long timestamp) {
this.writeLock.lock();
try {
if (this.modifiyMap.containsKey(feedId))
this.modifiyMap.remove(feedId);
this.modifiyMap.put(feedId, timestamp);
} finally {
this.writeLock.unlock();
}
}
}
protected Long getFeedLastModified(final String feedId) {
return this.modifiyMap.get(feedId);
}
/**
* the timestamp of the last modification for the given feed id
*
* @param feedId -
* feed id
* @return timestamp
*/
protected Long getFeedLastModified(final String feedId) {
this.readLock.lock();
try {
return this.modifiyMap.get(feedId);
} finally {
this.readLock.unlock();
}
}
protected Set<Entry<String, Long>> getLastModified() {
return this.modifiyMap.entrySet();
}
protected Set<Entry<String, Long>> getLastModified() {
return this.modifiyMap.entrySet();
}
/**
* Returns all entries for the given feed id sorted by the update timestamp
* desc.
*
* @param feedId -
* the feed id
* @return a {@link List} of all {@link StorageEntryWrapper} object buffered
* in this buffer or an empty list if not entry has been buffered
* for the given feed
*/
public List<StorageEntryWrapper> getSortedEntries(String feedId) {
this.readLock.lock();
try {
if (!this.bufferMap.containsKey(feedId))
return null;
Map<String, StorageEntryWrapper> tempMap = this.bufferMap
.get(feedId);
if (tempMap == null)
return null;
Collection<StorageEntryWrapper> col = tempMap.values();
List<StorageEntryWrapper> returnList = new ArrayList<StorageEntryWrapper>(
col);
Collections.sort(returnList);
return returnList;
/**
* Returns all entries for the given feed id sorted by the update timestamp
* desc.
*
* @param feedId -
* the feed id
* @return a {@link List} of all {@link StorageEntryWrapper} object buffered
* in this buffer or an empty list if not entry has been buffered
* for the given feed
*/
public List<StorageEntryWrapper> getSortedEntries(String feedId) {
this.readLock.lock();
try {
if (!this.bufferMap.containsKey(feedId))
return null;
Map<String, StorageEntryWrapper> tempMap = this.bufferMap
.get(feedId);
if (tempMap == null)
return null;
Collection<StorageEntryWrapper> col = tempMap.values();
List<StorageEntryWrapper> returnList = new ArrayList<StorageEntryWrapper>(
col);
Collections.sort(returnList);
return returnList;
} finally {
this.readLock.unlock();
}
} finally {
this.readLock.unlock();
}
}
}
/**
* Adds a deleted entry to the buffer.
*
* @param entryId -
* the deleted entry id
* @param feedId -
* the feed of the entry
*/
public void addDeleted(final String entryId, final String feedId) {
this.writeLock.lock();
try {
this.excludeList.add(entryId);
Map<String, StorageEntryWrapper> tempMap = this.bufferMap
.get(feedId);
if (tempMap == null)
return;
tempMap.remove(entryId);
this.addLastModified(feedId, new Long(System.currentTimeMillis()));
} finally {
this.writeLock.unlock();
/**
* Adds a deleted entry to the buffer.
*
* @param entryId -
* the deleted entry id
* @param feedId -
* the feed of the entry
*/
public void addDeleted(final String entryId, final String feedId) {
this.writeLock.lock();
try {
Map<String, StorageEntryWrapper> tempMap = this.bufferMap
.get(feedId);
if (tempMap != null) {
tempMap.remove(entryId);
this.addLastModified(feedId, new Long(System
.currentTimeMillis()));
}
/*
* add to exclude from searches
*/
if (!this.excludeList.contains(entryId))
this.excludeList.add(entryId);
} finally {
}
this.writeLock.unlock();
}
}
/**
* Returns an entry for the given entry id in the feed context spezified by
* the feed id;
*
* @param entryId -
* the id of the entry to return
* @param feedId -
* the feed containing the entry
* @return - the entry or <code>null</code> if the corresponding entry is
* not in the buffer.
*/
public StorageEntryWrapper getEntry(final String entryId,
final String feedId) {
this.readLock.lock();
try {
}
if (this.bufferMap.containsKey(feedId))
return this.bufferMap.get(feedId).get(entryId);
return null;
/**
* Returns an entry for the given entry id in the feed context spezified by
* the feed id;
*
* @param entryId -
* the id of the entry to return
* @param feedId -
* the feed containing the entry
* @return - the entry or <code>null</code> if the corresponding entry is
* not in the buffer.
*/
public StorageEntryWrapper getEntry(final String entryId,
final String feedId) {
this.readLock.lock();
try {
} finally {
this.readLock.unlock();
}
}
if (this.bufferMap.containsKey(feedId))
return this.bufferMap.get(feedId).get(entryId);
return null;
/**
* The buffer contains updated and delete entries. These entries are already
* available in the lucene index but should not be found during search.
*
* <p>
* This list contains all entries should not be found by the index searcher.
* This method creates a copy of the current list to prevent concurrent
* modification exceptions while iteration over the collection.
* </p>
*
*
* @see ModifiedEntryFilter
* @return - a String array of entries to be omitted from a lucene index
* search
*/
public String[] getExculdList() {
this.readLock.lock();
try {
return this.excludeList
.toArray(new String[this.excludeList.size()]);
} finally {
this.readLock.unlock();
}
}
} finally {
this.readLock.unlock();
}
}
// not synchronized
private void clearBuffer() {
this.bufferMap.clear();
this.excludeList.clear();
this.modifiyMap.clear();
/**
* The buffer contains updated and delete entries. These entries are already
* available in the lucene index but should not be found during search.
*
* <p>
* This list contains all entries should not be found by the index searcher.
* This method creates a copy of the current list to prevent concurrent
* modification exceptions while iteration over the collection.
* </p>
*
*
* @see ModifiedEntryFilter
* @return - a String array of entries to be omitted from a lucene index
* search
*/
public String[] getExculdList() {
this.readLock.lock();
try {
return this.excludeList
.toArray(new String[this.excludeList.size()]);
} finally {
this.readLock.unlock();
}
}
}
// not synchronized --> see close()
private void clearBuffer() {
/**
* clears the buffer -
*/
public void close() {
this.writeLock.lock();
try {
clearBuffer();
} finally {
this.writeLock.unlock();
}
this.bufferMap.clear();
this.excludeList.clear();
this.modifiyMap.clear();
}
}
static class BufferableEntry extends BaseEntry {
/**
* clears the buffer -
*/
public void close() {
this.writeLock.lock();
try {
clearBuffer();
} finally {
this.writeLock.unlock();
}
/**
*
*/
@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>();
}
static class BufferableEntry extends BaseEntry {
/**
* @see com.google.gdata.data.BaseEntry#declareExtensions(com.google.gdata.data.ExtensionProfile)
*/
@Override
public void declareExtensions(ExtensionProfile arg0) {
//
}
/**
*
*/
@SuppressWarnings("unchecked")
public BufferableEntry() {
super();
this.links = new LinkedList<Link>();
}
}
/**
* @param arg0
*/
@SuppressWarnings("unchecked")
public BufferableEntry(BaseEntry arg0) {
super(arg0);
if (this.links.size() > 0) {
LinkedList list = new LinkedList<Link>();
list.addAll(this.links);
this.links = list;
} else
this.links = new LinkedList<Link>();
}
/**
* @see com.google.gdata.data.BaseEntry#declareExtensions(com.google.gdata.data.ExtensionProfile)
*/
@Override
public void declareExtensions(ExtensionProfile arg0) {
//
}
}
/**
* @return Returns the bufferSize.
*/
public int getBufferSize() {
return this.bufferSize;
}
}

View File

@ -12,18 +12,18 @@ import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.server.registry.Component;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.configuration.Requiered;
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.recover.RecoverController;
import org.apache.lucene.gdata.storage.lucenestorage.recover.RecoverException;
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;
/**
*
@ -33,14 +33,15 @@ import org.apache.lucene.store.RAMDirectory;
*/
@Component(componentType = ComponentType.STORAGECONTROLLER)
public class StorageCoreController implements StorageController {
protected static final Log LOG = LogFactory
.getLog(StorageCoreController.class);
private IndexSearcher searcher;
private final Directory storageDir;
private Directory storageDir;
private final StorageModifier modifier;
private StorageModifier modifier;
private ReferenceCounter<StorageQuery> storageQuery;
@ -49,39 +50,39 @@ public class StorageCoreController implements StorageController {
private final ReentrantLock storageControllerLock = new ReentrantLock();
private final Condition closeCondition;
private static final int DEFAULT_STORAGE_BUFFER_SIZE = 10;
private static final int DEFAULT_STORAGE_BUFFER_SIZE = 3;
private static final int DEFAULT_STORAGE_PERSIST_FACTOR = 10;
private static final int DEFAULT_STORAGE_PERSIST_FACTOR = 3;
private static final String RECOVERDIRECTORY = "recover";
private static final String STORAGELOG = ".lucenestorage";
private IDGenerator idGenerator;
private final ConcurrentStorageLock storageLock;
/*
*properties set by configuration file e.g. Registry
*/
private int indexOptimizeInterval;
private String storageDirectory;
private boolean keepRecoveredFiles;
private boolean recover;
private int storageBufferSize;
private int storagePersistFactor;
private StorageConfigurator configurator;
private IDGenerator idGenerator;
private int indexOptimizeInterval;
// private RecoverController recoverController;
private RecoverController recoverController;
/**
* Creates a new <tt>StoragCoreController</tt> and sets up the storage
* environment reading the configuration file.
*
*
*
* @throws IOException -
* if an IOException occures
* @throws StorageException -
* if the storage lock can not be created or the
* {@link IDGenerator} can not be loaded
* @see org.apache.lucene.gdata.server.registry.ServerComponent#initialize()
*/
public StorageCoreController() throws IOException, StorageException {
public void initialize() {
synchronized (StorageCoreController.class) {
this.closeCondition = this.storageControllerLock.newCondition();
try {
this.idGenerator = new IDGenerator(10);
} catch (Exception e) {
@ -89,11 +90,11 @@ public class StorageCoreController implements StorageController {
}
boolean createNewStorage = false;
this.configurator = StorageConfigurator.getStorageConfigurator();
if (!this.configurator.isRamDirectory()) {
if (this.storageDir == null) {
String storageDirPath = this.configurator.getStorageDirectory();
File storeDir = new File(storageDirPath);
File storeDir = new File(this.storageDirectory);
File storageLog = new File(storeDir.getAbsolutePath()
+ System.getProperty("file.separator") + STORAGELOG);
try {
@ -106,35 +107,83 @@ public class StorageCoreController implements StorageController {
} else
throw new StorageException(
"could not create storage lock file in "
+ storageDirPath);
+ this.storageDirectory);
} else
this.storageDir = FSDirectory.getDirectory(storeDir,
false);
} catch (IOException e) {
storageLog.delete();
throw e;
throw new StorageException(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.storageBufferSize = this.storageBufferSize < DEFAULT_STORAGE_BUFFER_SIZE ? DEFAULT_STORAGE_BUFFER_SIZE
: this.storageBufferSize;
this.storagePersistFactor = this.storagePersistFactor < DEFAULT_STORAGE_PERSIST_FACTOR ? DEFAULT_STORAGE_PERSIST_FACTOR
: this.storagePersistFactor;
} else
this.storageDir = getRamDirectory();
}else
createNewStorage = true;
this.currentBuffer = new StorageBuffer(this.storageBufferSize);
try{
this.modifier = createStorageModifier(createNewStorage);
this.searcher = new IndexSearcher(this.storageDir);
// this.recoverController = new RecoverController(null,this.configurator.isRecover(),this.configurator.isKeepRecoveredFiles());
}catch (Exception e) {
throw new StorageException("Can not create Searcher/Modifier -- "+e.getMessage(),e);
}
if(createNewStorage)
createAdminAccount();
if(!this.recover)
return;
try{
tryRecover();
}catch (Exception e) {
LOG.fatal("Recovering failed",e);
throw new StorageException("Recovering failed -- "+e.getMessage(),e);
}
this.recoverController = createRecoverController(false,false);
try{
this.recoverController.initialize();
}catch (Exception e) {
LOG.fatal("Can not initialize recover controller",e);
throw new StorageException("Can not initialize recover controller -- "+e.getMessage(),e);
}
}
}
/*
* reads the remaining recover files to store the failed entries
*/
private void tryRecover() throws IOException, RecoverException{
if(!this.recover)
return;
LOG.info("try to recover files if there are any");
this.recoverController = createRecoverController(true,false);
this.recoverController.initialize();
this.recoverController.recoverEntries(this.modifier);
this.recoverController.destroy();
}
private RecoverController createRecoverController(boolean doRecover, boolean keepfiles){
String recoverDirectory = null;
if(this.storageDirectory.endsWith("/") || this.storageDirectory.endsWith("\\"))
recoverDirectory = this.storageDirectory.substring(0,this.storageDirectory.length()-1)+System.getProperty("file.separator")+RECOVERDIRECTORY;
else
recoverDirectory = this.storageDirectory+System.getProperty("file.separator")+RECOVERDIRECTORY;
File recoverDirectoryFile = new File(recoverDirectory);
return new RecoverController(recoverDirectoryFile,doRecover,keepfiles);
}
/**
* Creates a new <tt>StoragCoreController</tt>
*/
public StorageCoreController() {
this.closeCondition = this.storageControllerLock.newCondition();
this.storageLock = SingleHostConcurrentStorageLock.getConcurrentStorageLock();
}
@ -188,7 +237,9 @@ public class StorageCoreController implements StorageController {
this.storageQuery.increamentReference();
return this.storageQuery;
}finally{
try{
this.closeCondition.signalAll();
}catch (Throwable e) {/**/}
this.storageControllerLock.unlock();
}
}
@ -239,7 +290,9 @@ public class StorageCoreController implements StorageController {
this.currentBuffer = new StorageBuffer(this.storageBufferSize);
}finally{
this.closeCondition.signalAll();
try{
this.closeCondition.signalAll();
}catch (Throwable e) {/**/}
this.storageControllerLock.unlock();
}
@ -259,7 +312,9 @@ public class StorageCoreController implements StorageController {
throw new IllegalStateException("StorageController is already closed -- server is shutting down");
return this.currentBuffer;
}finally{
try{
this.closeCondition.signalAll();
}catch (Throwable e) {/**/}
this.storageControllerLock.unlock();
}
}
@ -284,7 +339,9 @@ public class StorageCoreController implements StorageController {
return new IndexModifier(this.storageDir, new StandardAnalyzer(),
false);
}finally{
this.closeCondition.signalAll();
try{
this.closeCondition.signalAll();
}catch (Throwable e) {/**/}
this.storageControllerLock.unlock();
}
}
@ -308,48 +365,16 @@ public class StorageCoreController implements StorageController {
LOG.info("StorageController has been closed -- server is shutting down -- release all resources");
if (this.storageQuery != null)
this.storageQuery.decrementRef();
if(this.recoverController != null)
this.recoverController.destroy();
this.storageLock.close();
this.modifier.close();
this.idGenerator.stopIDGenerator();
}finally{
this.storageControllerLock.unlock();
}
}
/**
* The size of the <tt>StorageBuffer</tt>.
*
* @return - storage buffer size
*/
public int getStorageBufferSize() {
return this.storageBufferSize;
}
/**
* The size of the <tt>StorageBuffer</tt>. This size should be at least
* as big as the persist factor to prevent the <tt>StorageBuffer</tt> from
* resizing
*
* @param storageBufferSize
*/
public void setStorageBufferSize(int storageBufferSize) {
this.storageBufferSize = storageBufferSize;
}
/**
* An integer value after how many changes to the StorageModifier the
* buffered changes will be persisted / wirtten to the index
*
* @return - the persist factor
*/
public int getStoragePersistFactor() {
return this.storagePersistFactor;
}
/**
* @param storagePersistFactor
*/
public void setStoragePersistFactor(int storagePersistFactor) {
this.storagePersistFactor = storagePersistFactor;
}
/**
* Forces the StorageModifier to write all buffered changes.
@ -364,12 +389,13 @@ public class StorageCoreController implements StorageController {
this.modifier.forceWrite();
}
private boolean createLuceneStorageLog(File storageDirectory)
private boolean createLuceneStorageLog(File directory)
throws IOException {
if (storageDirectory.isDirectory() && !storageDirectory.exists()) {
storageDirectory.createNewFile();
if (directory.isDirectory() && !directory.exists()) {
if(!directory.createNewFile())
throw new StorageException("Can not create directory -- "+directory);
}
File file = new File(storageDirectory.getAbsolutePath()
File file = new File(directory.getAbsolutePath()
+ System.getProperty("file.separator") + STORAGELOG);
return file.createNewFile();
@ -383,7 +409,7 @@ public class StorageCoreController implements StorageController {
* @throws StorageException -
* if no id can be released
*/
public synchronized String releaseID() throws StorageException {
public synchronized String releaseId() {
try {
return this.idGenerator.getUID();
} catch (InterruptedException e) {
@ -427,26 +453,142 @@ public class StorageCoreController implements StorageController {
}
}
// 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);
}
protected ConcurrentStorageLock getLock(){
return this.storageLock;
}
/**
* The size of the <tt>StorageBuffer</tt>.
*
* @return - storage buffer size
*/
public int getBufferSize() {
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
*/
@Requiered
public void setBufferSize(int storageBufferSize) {
this.storageBufferSize = storageBufferSize;
}
/**
* An integer value after how many changes to the StorageModifier the
* buffered changes will be persisted / wirtten to the index
*
* @return - the persist factor
*/
public int getPersistFactor() {
return this.storagePersistFactor;
}
/**
* @param storagePersistFactor
*/
@Requiered
public void setPersistFactor(int storagePersistFactor) {
this.storagePersistFactor = storagePersistFactor;
}
/**
* @return Returns the indexOptimizeInterval.
*/
public int getIndexOptimizeInterval() {
return this.indexOptimizeInterval;
}
/**
* @param indexOptimizeInterval The indexOptimizeInterval to set.
*/
@Requiered
public void setOptimizeInterval(int indexOptimizeInterval) {
this.indexOptimizeInterval = indexOptimizeInterval;
}
/**
* @return Returns the keepRecoveredFiles.
*/
public boolean isKeepRecoveredFiles() {
return this.keepRecoveredFiles;
}
/**
* @param keepRecoveredFiles The keepRecoveredFiles to set.
*/
@Requiered
public void setKeepRecoveredFiles(boolean keepRecoveredFiles) {
this.keepRecoveredFiles = keepRecoveredFiles;
}
/**
* @return Returns the recover.
*/
public boolean isRecover() {
return this.recover;
}
/**
* @param recover The recover to set.
*/
@Requiered
public void setRecover(boolean recover) {
this.recover = recover;
}
/**
* @param storageDir The storageDir to set.
*/
public void setStorageDir(Directory storageDir) {
this.storageDir = storageDir;
}
/**
* @param storageDirectory The storageDirectory to set.
*/
@Requiered
public void setDirectory(String storageDirectory) {
this.storageDirectory = storageDirectory;
}
protected void writeRecoverEntry(StorageEntryWrapper wrapper) throws RecoverException{
if(this.recoverController!= null &&!this.recoverController.isRecovering() )
this.recoverController.storageModified(wrapper);
}
protected void registerNewRecoverWriter() throws IOException {
if(this.recoverController == null || this.recoverController.isRecovering())
return;
this.recoverController.destroy();
this.recoverController = createRecoverController(false,false);
this.recoverController.initialize();
}
}

View File

@ -17,6 +17,7 @@
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import org.apache.lucene.document.Document;
@ -37,11 +38,13 @@ import com.google.gdata.util.common.xml.XmlWriter;
* @author Simon Willnauer
*
*/
public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>,
public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>, Serializable,
StorageWrapper {
private static final long serialVersionUID = -4619985652059888526L;
/*
* client api uses UTF-8 to encode server requests and entries
*/
private static final String INTERNAL_ENCODING = "UTF-8";
/**
@ -64,21 +67,27 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>,
*/
public final static String FIELD_TIMESTAMP = "timestamp";
private final String entryId;
/**
* lucene field name entry version
*/
public final static String FIELD_VERSION = "entryVersion";
private int version;
private final String feedId;
private String entryId;
private String feedId;
private String content;
private final ServerBaseEntry entry;
private transient ServerBaseEntry entry;
private Long timestamp;
private transient Document document;
private Document document;
private StorageOperation operation;
private ProvidedService config;
private transient ProvidedService config;
/**
* Creates a new StorageEntryWrapper.
@ -94,14 +103,15 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>,
*/
public StorageEntryWrapper(final ServerBaseEntry entry,
StorageOperation operation) throws IOException {
this.entry = entry;
this.operation = operation;
this.entryId = entry.getId();
this.feedId = entry.getFeedId();
this.version = entry.getVersion();
if (operation != StorageOperation.DELETE) {
this.config = entry.getServiceConfig();
this.content = buildContent();
}
this.timestamp = new Long(
@ -110,7 +120,8 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>,
}
private String buildContent() throws IOException {
StringWriter writer = new StringWriter();
XmlWriter xmlWriter = new XmlWriter(writer, INTERNAL_ENCODING);
@ -132,10 +143,12 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>,
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,
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));
this.document.add(new Field(FIELD_VERSION, Integer.toString(this.version),
Field.Store.YES, Field.Index.UN_TOKENIZED));
return this.document;
@ -205,7 +218,7 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>,
*
*/
public int compareTo(StorageEntryWrapper arg0) {
return arg0.timestamp == this.timestamp ? 0
return arg0.timestamp.equals(this.timestamp) ? 0
: (arg0.timestamp > this.timestamp ? 1 : -1);
}
@ -223,4 +236,14 @@ public class StorageEntryWrapper implements Comparable<StorageEntryWrapper>,
return this.timestamp;
}
/**
* @return - the version of the entry
*/
public int getVersion() {
return this.version;
}
}

View File

@ -25,6 +25,7 @@ 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.ModificationConflictException;
import org.apache.lucene.gdata.storage.ResourceNotFoundException;
import org.apache.lucene.gdata.storage.Storage;
import org.apache.lucene.gdata.storage.StorageController;
@ -76,11 +77,16 @@ public class StorageImplementation implements Storage {
*/
public BaseEntry storeEntry(final ServerBaseEntry entry)
throws StorageException {
if (entry == null)
throw new StorageException("entry is null");
if(entry.getFeedId() == null)
throw new StorageException("feedid is null");
if(entry.getVersion() != 1)
throw new StorageException("entry version must be 1");
if(entry.getServiceConfig() == null)
throw new StorageException("ProvidedService must not be null");
StorageModifier modifier = this.controller.getStorageModifier();
String id = this.controller.releaseID();
String id = this.controller.releaseId();
entry.setId(entry.getFeedId() + id);
if (LOG.isInfoEnabled())
LOG.info("Store entry " + id + " -- feed: " + entry.getFeedId());
@ -108,23 +114,34 @@ public class StorageImplementation implements Storage {
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("delete entry " + entry.getId() + " -- feed: "
+ entry.getFeedId());
StorageModifier modifier = this.controller.getStorageModifier();
ReferenceCounter<StorageQuery> query = this.controller.getStorageQuery();
// try to set concurrency Lock
String key = entry.getId();
setLock(key);
try{
if(query.get().isEntryStored(entry.getId(),entry.getFeedId())){
modifier.deleteEntry(new StorageEntryWrapper(entry,StorageOperation.DELETE));
if(query.get().checkEntryVersion(entry.getId(),entry.getFeedId(),entry.getVersion())){
modifier.deleteEntry(new StorageEntryWrapper(entry,StorageOperation.DELETE));
}else
throw new ModificationConflictException("The entry version does not match -- entry "+entry.getId()+" feed:"+entry.getFeedId()+" version: "+entry.getVersion());
}
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();
if(query != null)
query.decrementRef();
// release lock for concurrency
releaseLock(key);
}
}
@ -137,6 +154,8 @@ public class StorageImplementation implements Storage {
throw new StorageException("entry is null");
if(entry.getId() == null)
throw new StorageException("entry id is null");
if(entry.getServiceConfig() == null)
throw new StorageException("service config is not set -- null");
if(entry.getFeedId() == null)
throw new StorageException("feed id is null");
if (LOG.isInfoEnabled())
@ -144,28 +163,56 @@ public class StorageImplementation implements Storage {
+ entry.getFeedId());
StorageModifier modifier = this.controller.getStorageModifier();
ReferenceCounter<StorageQuery> query = this.controller.getStorageQuery();
// try to set concurrency Lock
String key = entry.getId();
setLock(key);
try {
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,
StorageOperation.UPDATE);
if(query.get().isEntryStored(entry.getId(),entry.getFeedId()))
modifier.updateEntry(wrapper);
else
if(query.get().isEntryStored(entry.getId(),entry.getFeedId())){
if(query.get().checkEntryVersion(entry.getId(),entry.getFeedId(),entry.getVersion())){
entry.setVersion(entry.getVersion()+1);
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,
StorageOperation.UPDATE);
modifier.updateEntry(wrapper);
}else
throw new ModificationConflictException("The entry version does not match -- entry "+entry.getId()+" feed:"+entry.getFeedId()+" version: "+entry.getVersion());
}else
throw new ResourceNotFoundException("Entry for entry id: "+entry.getId()+" is not stored");
} catch (IOException e) {
LOG.error("Can't update entry for feedID: " + entry.getFeedId()
+ "; entryId: " + entry.getId() + " -- " + e.getMessage(),
e);
StorageException ex = new StorageException("Can't create Entry -- "
StorageException ex = new StorageException("Can't update Entry -- "
+ e.getMessage(), e);
ex.setStackTrace(e.getStackTrace());
throw ex;
}
finally{
if(query != null)
query.decrementRef();
// release lock for concurrency
releaseLock(key);
}
return entry.getEntry();
}
private void setLock(String key) throws ModificationConflictException{
if(!this.controller.getLock().setLock(key))
throw new ModificationConflictException("Can not set lock for entry -- "+key);
}
private void releaseLock(String key) throws StorageException{
if(!this.controller.getLock().releaseLock(key))
throw new StorageException("Can not release lock for key: "+key);
}
/**
* @see org.apache.lucene.gdata.storage.Storage#getFeed(org.apache.lucene.gdata.data.ServerBaseFeed)
@ -382,7 +429,7 @@ public class StorageImplementation implements Storage {
throw ex;
} finally {
if (query == null)
if (query != null)
query.decrementRef();
}
}
@ -415,7 +462,7 @@ public class StorageImplementation implements Storage {
throw ex;
} finally {
if (query == null)
if (query != null)
query.decrementRef();
}

View File

@ -1,3 +1,18 @@
/**
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
@ -9,7 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -67,13 +82,9 @@ public class StorageModifier {
private IndexModifier modifier;
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
private Lock lock = new ReentrantLock();
private final AtomicBoolean isClosed = new AtomicBoolean(false);
private final Lock readLock = this.lock.readLock();
private final Lock writeLock = this.lock.writeLock();
private final static int DEFAULT_OPTIMIZE_INTERVAL = 10;
@ -130,17 +141,33 @@ public class StorageModifier {
throws StorageException {
if(wrapper.getOperation() != StorageOperation.UPDATE)
throw new StorageException("Illegal method call -- updateEntry does not accept other storageOperations than update");
this.readLock.lock();
this.lock.lock();
try {
Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID,
wrapper.getEntryId());
this.documentMap.put(wrapper.getEntryId(), wrapper
.getLuceneDocument());
this.deletedForUpdateDocumentQueue.add(tempTerm);
this.buffer.addEntry(wrapper);
storageModified();
/*
* If storage not written write entry to recoverfile
* and make the entry available via the buffer
*/
if(this.modifiedCounter != 0)
try{
this.controller.writeRecoverEntry(wrapper);
this.buffer.addEntry(wrapper);
}catch (Exception e) {
/*
* remove from all resources
*/
this.documentMap.remove(wrapper.getEntryId());
this.deletedForUpdateDocumentQueue.remove(tempTerm);
}
} finally {
this.readLock.unlock();
this.lock.unlock();
}
}
@ -156,14 +183,27 @@ public class StorageModifier {
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();
this.lock.lock();
try {
this.documentMap.put(wrapper.getEntryId(), wrapper
.getLuceneDocument());
this.buffer.addEntry(wrapper);
storageModified();
/*
* If storage not written write entry to recoverfile
* and make the entry available via the buffer
*/
if(this.modifiedCounter != 0)
try{
this.controller.writeRecoverEntry(wrapper);
this.buffer.addEntry(wrapper);
}catch (Exception e) {
/*
* remove from all resources
*/
this.documentMap.remove(wrapper.getEntryId());
}
} finally {
this.readLock.unlock();
this.lock.unlock();
}
}
@ -179,15 +219,30 @@ public class StorageModifier {
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();
this.lock.lock();
try {
Term tempTerm = new Term(StorageEntryWrapper.FIELD_ENTRY_ID,
wrapper.getEntryId());
this.deletedDocumentQueue.add(tempTerm);
this.buffer.addDeleted(wrapper.getEntryId(), wrapper.getFeedId());
storageModified();
/*
* If storage not written write entry to recoverfile
* and make the entry available via the buffer
*/
if(this.modifiedCounter != 0)
try{
this.controller.writeRecoverEntry(wrapper);
this.buffer.addDeleted(wrapper.getEntryId(), wrapper.getFeedId());
}catch (Exception e) {
/*
* remove from all resources
*/
this.deletedDocumentQueue.remove(tempTerm);
}
} finally {
this.readLock.unlock();
this.lock.unlock();
}
}
@ -201,12 +256,12 @@ public class StorageModifier {
* if the feed can not be written
*/
public void createFeed(StorageFeedWrapper wrapper) throws StorageException {
this.readLock.lock();
this.lock.lock();
try {
this.forceWriteDocuments.add(wrapper.getLuceneDocument());
storageModified();
} finally {
this.readLock.unlock();
this.lock.unlock();
}
}
@ -220,12 +275,12 @@ public class StorageModifier {
* if the user can not be persisted.
*/
public void createAccount(StorageAccountWrapper account) throws StorageException {
this.readLock.lock();
this.lock.lock();
try {
this.forceWriteDocuments.add(account.getLuceneDocument());
storageModified();
} finally {
this.readLock.unlock();
this.lock.unlock();
}
}
@ -239,14 +294,14 @@ public class StorageModifier {
* If the user could not be deleted
*/
public void deleteAccount(String accountName) throws StorageException {
this.readLock.lock();
this.lock.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();
this.lock.unlock();
}
}
@ -261,7 +316,7 @@ public class StorageModifier {
*/
public void updateAccount(final StorageAccountWrapper user)
throws StorageException {
this.readLock.lock();
this.lock.lock();
try {
this.forceWriteTerms.add(new Term(
StorageAccountWrapper.FIELD_ACCOUNTNAME, user.getUser()
@ -269,7 +324,7 @@ public class StorageModifier {
this.forceWriteDocuments.add(user.getLuceneDocument());
storageModified();
} finally {
this.readLock.unlock();
this.lock.unlock();
}
}
@ -284,14 +339,14 @@ public class StorageModifier {
*/
public void updateFeed(final StorageFeedWrapper wrapper)
throws StorageException {
this.readLock.lock();
this.lock.lock();
try {
this.forceWriteTerms.add(new Term(StorageFeedWrapper.FIELD_FEED_ID,
wrapper.getFeed().getId()));
this.forceWriteDocuments.add(wrapper.getLuceneDocument());
storageModified();
} finally {
this.readLock.unlock();
this.lock.unlock();
}
}
@ -305,7 +360,7 @@ public class StorageModifier {
* if the feed can not be deleted
*/
public void deleteFeed(final String feedId) throws StorageException {
this.readLock.lock();
this.lock.lock();
try {
this.deletedDocumentQueue.add(new Term(StorageEntryWrapper.FIELD_FEED_REFERENCE,feedId));
this.forceWriteTerms.add(new Term(StorageFeedWrapper.FIELD_FEED_ID,
@ -313,16 +368,14 @@ public class StorageModifier {
storageModified();
} finally {
this.readLock.unlock();
this.lock.unlock();
}
}
private void storageModified() throws StorageException {
if(this.isClosed.get())
throw new IllegalStateException("StorageModifier is already closed");
this.readLock.unlock();
this.writeLock.lock();
try {
if(this.isClosed.get())
throw new IllegalStateException("StorageModifier is already closed");
@ -343,18 +396,18 @@ public class StorageModifier {
LOG.error("Writing persistent index failed - Recovering", e);
throw new StorageException("could not write to storage index -- "+e.getMessage(),e);
} finally {
this.readLock.lock();
this.writeLock.unlock();
}
}
protected void forceWrite() throws IOException {
/**
* Persists all changes imediately
* @throws IOException -- if an IO Exception occures
*/
public void forceWrite() throws IOException {
if(this.isClosed.get())
throw new IllegalStateException("StorageModifier is already closed");
this.writeLock.lock();
this.lock.lock();
try {
if (LOG.isInfoEnabled())
LOG.info("ForceWrite called -- current modifiedCounter: "
@ -363,12 +416,12 @@ public class StorageModifier {
requestNewIndexModifier();
this.modifiedCounter = 0;
} finally {
this.writeLock.unlock();
this.lock.unlock();
}
}
private void requestNewIndexModifier() throws IOException {
this.controller.registerNewRecoverWriter();
this.controller.registerNewStorageQuery();
this.buffer = this.controller.releaseNewStorageBuffer();
this.modifier = this.controller.createIndexModifier();
@ -435,7 +488,7 @@ public class StorageModifier {
protected void close() throws IOException {
if(this.isClosed.get())
throw new IllegalStateException("StorageModifier is already closed");
this.writeLock.lock();
this.lock.lock();
try {
if(this.isClosed.get())
throw new IllegalStateException("StorageModifier is already closed");
@ -447,7 +500,7 @@ public class StorageModifier {
writePersistentIndex(true);
this.modifiedCounter = 0;
} finally {
this.writeLock.unlock();
this.lock.unlock();
}
}

View File

@ -17,6 +17,7 @@
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
@ -25,6 +26,7 @@ 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.document.Field;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.server.GDataEntityBuilder;
import org.apache.lucene.gdata.server.registry.ProvidedService;
@ -66,6 +68,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;
@ -178,20 +181,19 @@ public class StorageQuery {
@SuppressWarnings("unchecked")
public BaseFeed getLatestFeedQuery(final String feedId,
final int resultCount, final int startIndex,
final ProvidedService config) throws IOException,
ParseException {
final ProvidedService config) throws IOException, ParseException {
DateTime updated = null;
Hits feedHits = storageFeedQuery(feedId);
if(feedHits.length() == 0)
if (feedHits.length() == 0)
return null;
BaseFeed retVal = buildFeedFromLuceneDocument(feedHits.doc(0),config);
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();
@ -199,14 +201,13 @@ public class StorageQuery {
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){
if (alreadyAdded == resultCount) {
retVal.getEntries().addAll(returnList);
retVal.setUpdated(updated);
return retVal;
@ -229,14 +230,17 @@ public class StorageQuery {
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();
}
if (updated == null) {
try {
long updatedTimeStamp = Long.parseLong(hits.doc(0).get(
StorageEntryWrapper.FIELD_TIMESTAMP));
updated = new DateTime(updatedTimeStamp);
} catch (Exception e) {
LOG.warn("could not create DateTime -- " + e.getMessage(),
e);
updated = buildEntryFromLuceneDocument(hits.doc(0), config)
.getUpdated();
}
}
}
retVal.setUpdated(updated);
@ -351,21 +355,18 @@ public class StorageQuery {
}
private BaseEntry buildEntryFromLuceneDocument(final Document doc,
final ProvidedService config) throws ParseException,
IOException {
StringReader reader = new StringReader(doc.getField(
StorageEntryWrapper.FIELD_CONTENT).stringValue());
return GDataEntityBuilder.buildEntry( reader, config);
final ProvidedService config) throws ParseException, IOException {
Reader reader = new StringReader(doc.getField(StorageEntryWrapper.FIELD_CONTENT).stringValue());
BaseEntry entry = GDataEntityBuilder.buildEntry(reader, config);
entry.setVersionId(doc.getField(StorageEntryWrapper.FIELD_VERSION).stringValue());
return entry;
}
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);
final ProvidedService config) throws ParseException, IOException {
Reader reader = new StringReader(doc.getField(StorageFeedWrapper.FIELD_CONTENT).stringValue());
return GDataEntityBuilder.buildFeed(reader, config);
}
@ -403,21 +404,28 @@ public class StorageQuery {
/**
* 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
*
* @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{
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
*
* @param feedID -
* the feed ID
* @return - the feed type
* @throws IOException - if the storage can not be accessed
* @throws IOException -
* if the storage can not be accessed
*/
public String getService(String feedID) throws IOException {
Hits hits = storageFeedQuery(feedID);
@ -427,6 +435,7 @@ public class StorageQuery {
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));
@ -435,58 +444,103 @@ public class StorageQuery {
/**
* 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
*
* @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)
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)
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));
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
else
throw new StorageException("Entry not found");
return 0;
}
protected long getFeedLastModified(final String feedId)throws IOException{
protected long getFeedLastModified(final String feedId) throws IOException {
Long bufferedTime = this.buffer.getFeedLastModified(feedId);
if(bufferedTime != null)
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));
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;
protected boolean isEntryStored(String entryId, String feedId)
throws IOException {
if (LOG.isDebugEnabled())
LOG.debug("Checking isEntryStored for entryid " + entryId
+ " feedid: " + feedId);
if (this.buffer.getEntry(entryId, feedId) != null)
return true;
Hits h = storageQuery(entryId);
if(h.length() > 0)
if (h.length() > 0)
return true;
return false;
}
protected boolean checkEntryVersion(String id, String feedId, int version)
throws IOException {
if (LOG.isDebugEnabled())
LOG.debug("Checking entry version for entryid " + id + " feedid: "
+ feedId + " version: " + version);
StorageEntryWrapper wrapper = this.buffer.getEntry(id, feedId);
if (wrapper != null)
return wrapper.getVersion() == version;
Hits h = storageQuery(id);
if (h.length() < 1)
return false;
Document doc = h.doc(0);
String fieldValue = null;
try {
fieldValue = doc.getField(StorageEntryWrapper.FIELD_VERSION)
.stringValue();
int storedVersion = Integer.parseInt(fieldValue);
if(LOG.isDebugEnabled())
LOG.debug("StoredEntry has version "+storedVersion +" return compare result");
return storedVersion == version;
} catch (Exception e) {
LOG.error("Entry has no parable Version id or field is not set -- "
+ fieldValue);
}
return false;
}
}

View File

@ -60,18 +60,29 @@ public class RecoverController {
private final boolean recover;
private final boolean keepRecoverFiles;
/**
* @param recoverDirectory
* @param recover
* @param keepRecoverFiles
*/
public RecoverController(final File recoverDirectory, boolean recover, boolean keepRecoverFiles) {
if (recoverDirectory == null)
throw new IllegalArgumentException("directory must not be null");
if(!recoverDirectory.exists())
recoverDirectory.mkdirs();
if (!recoverDirectory.isDirectory())
throw new IllegalStateException("the given File is not a directory");
throw new IllegalStateException("the given File is not a directory -- "+recoverDirectory);
this.recover = recover;
this.keepRecoverFiles = keepRecoverFiles;
this.recoverDirectory = recoverDirectory;
}
public void storageModified(StorageEntryWrapper wrapper)
/**
* @param wrapper
* @throws RecoverException
*/
public void storageModified(StorageEntryWrapper wrapper)
throws RecoverException {
// prevent deadlock either recovering or writing
if(this.recover){
@ -92,6 +103,9 @@ public class RecoverController {
}
}
/**
* @param modifier
*/
public void recoverEntries(final StorageModifier modifier){
// prevent deadlock either recovering or writing
if(!this.recover){
@ -105,14 +119,17 @@ public class RecoverController {
for (int i = 0; i < files.length; i++) {
if(!files[i].isDirectory()){
try{
LOG.info("Recover file -- "+files[i]);
this.fileReader = new BufferedReader(new FileReader(files[i]));
List<StorageEntryWrapper> entryList = this.reader.recoverEntries(this.fileReader);
if(entryList.size() == 0)
continue;
storeEntries(entryList,modifier);
this.fileReader.close();
if(!this.keepRecoverFiles)
if(!this.keepRecoverFiles){
LOG.info("Recovering file -- "+files[i]+" successful, delete file");
files[i].delete();
}
}catch (StorageException e) {
LOG.error("Can't store recover entries for file: "+files[i].getName()+" -- keep file "+e.getMessage(),e);
}catch (IOException e) {
@ -126,7 +143,7 @@ public class RecoverController {
}
}
protected void storeEntries(final List<StorageEntryWrapper> entries, final StorageModifier modifier) throws StorageException{
protected void storeEntries(final List<StorageEntryWrapper> entries, final StorageModifier modifier) throws StorageException, IOException{
for (StorageEntryWrapper wrapper : entries) {
if(wrapper.getOperation() == StorageOperation.DELETE)
modifier.deleteEntry(wrapper);
@ -134,12 +151,15 @@ public class RecoverController {
modifier.insertEntry(wrapper);
else if(wrapper.getOperation() == StorageOperation.UPDATE)
modifier.updateEntry(wrapper);
modifier.forceWrite();
}
}
protected synchronized void initialize() throws IOException {
/**
* @throws IOException
*/
public synchronized void initialize() throws IOException {
if(this.recover)
return;
String filename = System.currentTimeMillis() + FILE_SUFFIX;
@ -150,12 +170,18 @@ public class RecoverController {
}
protected void destroy() throws RecoverException {
/**
* @throws RecoverException
*/
public synchronized void destroy() throws RecoverException {
if (this.fileWriter != null) {
this.lock.lock();
try {
this.fileWriter.flush();
this.fileWriter.close();
if(!this.keepRecoverFiles && this.currentRecoverFile != null)
this.currentRecoverFile.delete();
} catch (IOException e) {
throw new RecoverException("Can't close recover writer ", e);
} finally {
@ -163,6 +189,14 @@ public class RecoverController {
}
}
}
/**
* @return <code>true</code> if the RecoverController is initialized in recover mode, otherwise <code>false</code>
*/
public boolean isRecovering() {
return this.recover;
}

View File

@ -16,11 +16,13 @@
package org.apache.lucene.gdata.storage.lucenestorage.recover;
import org.apache.lucene.gdata.storage.StorageException;
/**
* @author Simon Willnauer
*
*/
public class RecoverException extends Exception {
public class RecoverException extends StorageException {
/**
*

View File

@ -140,24 +140,24 @@ public class RecoverReader {
throw new RecoverException("Illegal metadata --- "+recoverString);
temp = tokenizer.nextToken();
if(temp == null)
throw new RecoverException("Can't recover feed Id -- "+temp);
throw new RecoverException("Can't recover feed Id -- is null");
this.feedId = temp;
temp = tokenizer.nextToken();
if(temp == null)
throw new RecoverException("Can't recover entry Id -- "+temp);
throw new RecoverException("Can't recover entry Id -- is null");
this.entryId = temp;
temp = tokenizer.nextToken();
try{
this.timestamp = Long.parseLong(temp);
}catch (Exception e) {
throw new RecoverException("Can't recover timestamp -- "+temp,e);
throw new RecoverException("Can't recover timestamp -- is null",e);
}
if(this.operation != StorageOperation.DELETE){
temp = tokenizer.nextToken();
if(temp == null)
throw new RecoverException("Can't recover service -- "+temp);
throw new RecoverException("Can't recover service -- is null");
if(!GDataServerRegistry.getRegistry().isServiceRegistered(temp))
throw new RecoverException("Service in recover metadata is not registered - "+temp);
this.config = GDataServerRegistry.getRegistry().getProvidedService(temp);

View File

@ -65,6 +65,7 @@ public class RecoverWriter {
writer.write(META_DATA_ENTRY_SEPARATOR);
writer.write(STORAGE_OPERATION_SEPARATOR);
writer.write(META_DATA_ENTRY_SEPARATOR);
writer.flush();
}

View File

@ -40,21 +40,21 @@ import java.util.Stack;
*/
public class DateFormater {
private final Stack<SimpleDateFormat> objectStack = new Stack<SimpleDateFormat>();
private static final DateFormater formater = new DateFormater();
/**
* Date format as it is used in Http Last modified header (Tue, 15 Nov 1994
* 12:45:26 GMT)
*/
public static String HTTP_HEADER_DATE_FORMAT = "EEE, d MMM yyyy HH:mm:ss z";
public final static String HTTP_HEADER_DATE_FORMAT = "EEE, d MMM yyyy HH:mm:ss z";
/**
* Date format as it is used in Http Last modified header (Tue, 15 Nov 1994
* 12:45:26 +0000)
*/
public static String HTTP_HEADER_DATE_FORMAT_TIME_OFFSET = "EEE, d MMM yyyy HH:mm:ss Z";
public final static String HTTP_HEADER_DATE_FORMAT_TIME_OFFSET = "EEE, d MMM yyyy HH:mm:ss Z";
private DateFormater() {
protected DateFormater() {
super();
}
@ -74,8 +74,11 @@ public class DateFormater {
"given parameters must not be null");
SimpleDateFormat inst = formater.getFormater();
inst.applyPattern(format);
formater.returnFomater(inst);
return inst.format(date);
try{
return inst.format(date);
}finally{
formater.returnFomater(inst);
}
}
/**
* Parses the given string into one of the specified formates
@ -109,19 +112,26 @@ public class DateFormater {
"given parameters must not be null");
SimpleDateFormat inst = formater.getFormater();
try{
inst.applyPattern(pattern);
return inst.parse(dateString);
}finally{
formater.returnFomater(inst);
}
}
private SimpleDateFormat getFormater() {
protected SimpleDateFormat getFormater() {
if (this.objectStack.empty())
return new SimpleDateFormat(DateFormater.HTTP_HEADER_DATE_FORMAT,Locale.ENGLISH);
return this.objectStack.pop();
}
private void returnFomater(final SimpleDateFormat format) {
protected void returnFomater(final SimpleDateFormat format) {
if (this.objectStack.size() <= 25)
this.objectStack.push(format);
}
}

View File

@ -0,0 +1,74 @@
/**
* 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.utils;
/**
* Basic interface to be implemented by ObjectPool implementations. Pools should
* provide a constructor with a
* {@link org.apache.lucene.gdata.utils.PoolObjectFactory} as a mandatory
* parameter to create and destory the pooled objects.
*
* @see org.apache.lucene.gdata.utils.PoolObjectFactory
*
* @author Simon Willnauer
* @param <Type> -
* the type of the pooled objects
*
*/
public interface Pool<Type> {
/**
* Return an object from the pool or create one if the pool is empty.
*
* @return - a pooled object
*/
public abstract Type aquire();
/**
* Adds a previously aquired object to the pool. If the pool has already
* been closed or if the pool has already reached his size the released
* object will be destroyed using
* {@link PoolObjectFactory#destroyInstance(Object)} method.
*
* @param type -
* the previously aquired object
*/
public abstract void release(final Type type);
/**
* @return - the defined size of the pool
*/
public abstract int getSize();
/**
* @return - the expire time of the objects in the pool if defined
*/
public abstract long getExpireTime();
/**
* @return <code>true</code> if and only if the pool uses an expire
* mechanismn, otherwith <code>false</code>
*/
public abstract boolean expires();
/**
* releases all pooled objects using
* {@link PoolObjectFactory#destroyInstance(Object)} method. The pool can not
* be reused after this method has been called
*/
public abstract void destroy();
}

View File

@ -0,0 +1,53 @@
/**
* 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.utils;
/**
* <p>
* This interface enables {@link org.apache.lucene.gdata.utils.Pool} users to
* build a custom creation and destroy mechanismn for pooled objects.
* Implementations can use standart creation to prevent the pool from using
* reflection to create objects of the specific type. This implementation
* seperates the Pool implementation from the creation or the destruction of a
* pooled type.
* </p>
* <p>
* The destroy method can be used to close datasource connections or release
* resources if the object will be removed from the pool
* </p>
*
*
* @see org.apache.lucene.gdata.utils.Pool
* @author Simon Willnauer
* @param <Type> -
* the type to be created
*
*/
public interface PoolObjectFactory<Type> {
/**
* @return an instance of the specified Type
*/
public abstract Type getInstance();
/**
* destroys the given instance
* @param type - the object to destroy / release all resources
*/
public abstract void destroyInstance(Type type);
}

View File

@ -0,0 +1,175 @@
/**
* 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.utils;
import java.util.Stack;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A Simple implementation of the {@link org.apache.lucene.gdata.utils.Pool}
* interface using a {@link java.util.Stack} as a buffer for the pooled objects.
* This implementation does not provide any timeout mechanismn. Objects will
* stay inside the pool until the pool is destroyed.
* <p>
* If any object will be released e.g. handover to the pool and the pool has
* already enought objects in the pool the released object will be destroyed. If
* the pool is empty a new Object will be created.
* </p>
* <p>
* This implementation does not track any references to the objects aquired by
* any other resource. The objects must be destroyed manually if not released to
* the pool after aquired.
* </p>
*
* @author Simon Willnauer
* @param <Type>
*
*/
public class SimpleObjectPool<Type> implements Pool<Type> {
private static final Log LOG = LogFactory.getLog(SimpleObjectPool.class);
private volatile boolean isDestroyed = false;
private final PoolObjectFactory<Type> factory;
static final int DEFAULTSIZE = 5;
static final int MINIMALSIZE = 1;
private final int size;
private final Stack<Type> pool;
private final ReentrantReadWriteLock masterLock = new ReentrantReadWriteLock();
private final Lock readLock = this.masterLock.readLock();
private final Lock writeLock = this.masterLock.writeLock();
/**
* Constructs a new {@link SimpleObjectPool} and sets the ObjectFactory and the pool size
* @param size - the maximum size of the pool
* @param factory - factory to create and destroy pooled objects
*
*/
public SimpleObjectPool(int size, PoolObjectFactory<Type> factory) {
if (factory == null)
throw new IllegalArgumentException("Factory must not be null");
this.factory = factory;
this.size = size < MINIMALSIZE ? MINIMALSIZE : size;
this.pool = new Stack<Type>();
for (int i = 0; i < this.size; i++) {
this.pool.push(this.factory.getInstance());
}
}
/**
* @param factory
*/
public SimpleObjectPool(PoolObjectFactory<Type> factory) {
this(DEFAULTSIZE,factory);
}
/**
* @see org.apache.lucene.gdata.utils.Pool#aquire()
*/
public Type aquire() {
// fail if writelock is aquired
if (this.readLock.tryLock()) {
try {
if (this.isDestroyed)
throw new IllegalStateException(
"The pool has already been closed");
if (this.pool.isEmpty())
return this.factory.getInstance();
return this.pool.pop();
} finally {
this.readLock.unlock();
}
}
throw new IllegalStateException("The pool has already been closed");
}
/**
*
* @param type - generic type
* @see org.apache.lucene.gdata.utils.Pool#release(Object)
*/
public void release(Type type) {
// fail if writelock is aquired
if (this.readLock.tryLock()) {
try {
if (this.pool.size() < this.size && !this.isDestroyed)
this.pool.push(type);
else
this.factory.destroyInstance(type);
} finally {
this.readLock.unlock();
}
return;
}
// enable object need to be destoryed
this.factory.destroyInstance(type);
}
/**
* @see org.apache.lucene.gdata.utils.Pool#getSize()
*/
public int getSize() {
return this.size;
}
/**
* @see org.apache.lucene.gdata.utils.Pool#getExpireTime()
*/
public long getExpireTime() {
return 0;
}
/**
* @see org.apache.lucene.gdata.utils.Pool#expires()
*/
public boolean expires() {
return false;
}
/**
* @see org.apache.lucene.gdata.utils.Pool#destroy()
*/
public void destroy() {
this.writeLock.lock();
try {
if (this.isDestroyed)
return;
this.isDestroyed = true;
LOG.info("Destroy all elements in the pool -- poolsize: "+this.pool.size());
for (Type type : this.pool) {
this.factory.destroyInstance(type);
}
this.pool.clear();
} finally {
this.writeLock.unlock();
}
}
}

View File

@ -0,0 +1,52 @@
/**
* 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.utils;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* For use with Digester to throw exceptions on errors
* @author Simon Willnauer
*
*/
public final class SimpleSaxErrorHandler implements ErrorHandler{
/**
* @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
*/
public void warning(SAXParseException arg0) throws SAXException {
//
}
/**
* @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
*/
public void error(SAXParseException arg0) throws SAXException {
throw new SAXException("ERROR: Can not parse XML Document -- "+arg0.getMessage(),arg0);
}
/**
* @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
*/
public void fatalError(SAXParseException arg0) throws SAXException {
throw new SAXException("FATAL ERROR: Can not parse XML Document -- "+arg0.getMessage(),arg0);
}
}

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="password">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="5" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="account-name">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:whiteSpace value="collapse" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="email-address" type="xs:string" />
<xs:element name="url" type="xs:anyURI" />
<xs:element name="name" type="xs:string" />
<xs:element name="account-role">
<xs:simpleType>
<xs:restriction base="xs:positiveInteger">
<xs:fractionDigits value="2" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="account-owner">
<xs:complexType>
<xs:sequence>
<xs:element ref="name" />
<xs:element ref="email-address" />
<xs:element ref="url" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="account">
<xs:complexType>
<xs:sequence>
<xs:element ref="account-name" />
<xs:element ref="password" />
<xs:element ref="account-role" />
<xs:element ref="account-owner" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gdata>
<service name="feed" public="true">
<feed-class>com.google.gdata.data.Feed</feed-class>
<entry-class>com.google.gdata.data.Entry</entry-class>
<extension-profile>
com.google.gdata.data.ExtensionProfile
</extension-profile>
</service>
<service name="calendar" public="true">
<feed-class>
com.google.gdata.data.extensions.EventFeed
</feed-class>
<entry-class>
com.google.gdata.data.extensions.EventEntry
</entry-class>
<extension-profile>
com.google.gdata.data.ExtensionProfile
</extension-profile>
</service>
<server-components>
<component>
org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController
</component>
<component>
org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory
</component>
<component>
org.apache.lucene.gdata.server.ServiceFactory
</component>
<component>
org.apache.lucene.gdata.server.authentication.BlowfishAuthenticationController
</component>
</server-components>
</gdata>

View File

@ -1,12 +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.ramDirectory">true</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

@ -1,5 +1,8 @@
package org.apache.lucene.gdata.data;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.lucene.gdata.data.GDataAccount.AccountRole;
import junit.framework.TestCase;
@ -59,6 +62,7 @@ public class TestGDataUser extends TestCase {
assertEquals(4,this.user.getRoles().size());
}

View File

@ -15,6 +15,9 @@
*/
package org.apache.lucene.gdata.server;
import java.util.Enumeration;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServletRequest;
import junit.framework.TestCase;
@ -39,17 +42,15 @@ 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 {
protected void setUp() throws Exception {
try{
GDataServerRegistry.getRegistry().registerComponent(StorageStub.class,null);
}catch (Exception e) {
}
ProvidedService configurator = new ProvidedServiceStub();
GDataServerRegistry.getRegistry().registerService(configurator);
@ -225,7 +226,7 @@ public class TestGDataRequest extends TestCase {
String feedAndEntryID = "/feed/entryid";
String queryString = "max-results=25";
this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15");
this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/host/feed/entryId/15/");
this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
this.control.expectAndReturn(this.request.getParameter("max-results"),"25",2);
this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
@ -235,7 +236,6 @@ public class TestGDataRequest extends TestCase {
this.control.replay();
this.feedRequest.initializeRequest();
String selfID = "http://"+host+"/host/feed/entryId/15?"+queryString;
assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
this.control.reset();
@ -354,67 +354,95 @@ public class TestGDataRequest extends TestCase {
this.control.replay();
assertEquals("bla",this.feedRequest.getAuthToken());
this.control.verify();
this.control.reset();
}
public void testGetNextId() throws GDataRequestException{
// String host = "www.apache.org";
// String feedAndEntryID = "/feed/entryid";
// String queryString = "?max-results=25";
// String startIndex = "&start-index=26";
// this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
// this.control.expectAndDefaultReturn(this.request.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"),
// null);
// this.control.expectAndDefaultReturn(this.request.getQueryString(),
// queryString);
// this.control.replay();
// this.feedRequest.initializeRequest();
// String nextID = "http://"+host+"/feed/"+queryString+startIndex;
//
// assertEquals("Next ID",nextID,this.feedRequest.getNextId());
// this.control.reset();
String host = "www.apache.org";
String feedAndEntryID = "/feed/entryid";
String queryString = "?max-results=25";
String startIndex = "&start-index=26";
Enumeration enu = new StringTokenizer("max-results",",");
this.control.expectAndDefaultReturn(this.request.getParameterNames(),enu);
this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/feed/");
this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/");
this.control.expectAndReturn(this.request.getParameter("max-results"),"25",4);
this.control.expectAndReturn(this.request.getParameter("start-index"),null);
this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
null);
this.control.expectAndDefaultReturn(this.request.getQueryString(),
queryString);
this.control.replay();
this.feedRequest.initializeRequest();
String nextID = "http://"+host+"/feed"+queryString+startIndex;
assertEquals("Next ID",nextID,this.feedRequest.getNextId());
this.control.verify();
this.control.reset();
enu = new StringTokenizer("alt,max-results,start-index",",");
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(),"/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";
// nextID = "http://"+host+"/feed"+queryString+startIndex;
//
// assertEquals("Next ID 51",nextID,this.feedRequest.getNextId());
// this.control.reset();
//
// queryString = "";
// this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
// this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
// this.control.expectAndDefaultReturn(this.request.getParameter("max-results"),null);
// this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
// null);
// this.control.expectAndDefaultReturn(this.request.getQueryString(),
// null);
// this.control.replay();
// this.feedRequest.initializeRequest();
// String selfID = "http://"+host+"/feed"+"?max-results=25";
//
// assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
// this.control.reset();
this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/feed/");
this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/");
this.control.expectAndReturn(this.request.getParameter("max-results"),"25",4);
this.control.expectAndReturn(this.request.getParameter("start-index"),"26",4);
this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
"rss");
this.control.expectAndDefaultReturn(this.request.getQueryString(),
queryString+startIndex);
this.control.expectAndDefaultReturn(this.request.getParameterNames(),enu);
this.control.replay();
this.feedRequest.initializeRequest();
startIndex = "&start-index=51";
nextID = "http://"+host+"/feed"+queryString+startIndex;
assertEquals("Next ID 51",nextID,this.feedRequest.getNextId());
this.control.reset();
queryString = "";
this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/feed/");
this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/entryId/15");
this.control.expectAndDefaultReturn(this.request.getParameter("max-results"),null);
this.control.expectAndDefaultReturn(this.request.getParameter("alt"),
null);
this.control.expectAndDefaultReturn(this.request.getQueryString(),
null);
this.control.replay();
this.feedRequest.initializeRequest();
String selfID = "http://"+host+"/feed"+"?max-results=25";
assertEquals("Self ID",selfID,this.feedRequest.getSelfId());
this.control.reset();
}
public void testGetContextPath(){
String host = "www.apache.org";
this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/feed/id/");
this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/id/");
this.control.replay();
String result = "http://"+host+"/feed/id/";
assertEquals(result,this.feedRequest.getContextPath());
this.control.verify();
this.control.reset();
this.control.expectAndDefaultReturn(this.request.getHeader("Host"),host);
this.control.expectAndDefaultReturn(this.request.getRequestURI(),"/feed/id");
this.control.expectAndDefaultReturn(this.request.getPathInfo(),"/feed/id");
this.control.replay();
assertEquals(result,this.feedRequest.getContextPath());
this.control.verify();
}
}

View File

@ -13,6 +13,8 @@ import org.xml.sax.SAXException;
public class TestAccountBuilder extends TestCase {
private StringReader reader;
private String inputXML;
private StringReader invalidReader;
private String invalidInputXML;
protected void setUp() throws Exception {
this.inputXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<account>" +
@ -27,6 +29,18 @@ public class TestAccountBuilder extends TestCase {
"</account>";
this.reader = new StringReader(this.inputXML);
this.invalidInputXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<account>" +
"<account-name>simon</account-name>" +
"<account-role>6</account-role>" +
"<account-owner>" +
"<name>simon willnauer</name>" +
"<email-address>simon@gmail.com</email-address>" +
"<url>http://www.javawithchopsticks.de</url>" +
"</account-owner>" +
"</account>";
this.invalidReader = new StringReader(this.invalidInputXML);
}
@ -50,5 +64,14 @@ public class TestAccountBuilder extends TestCase {
assertFalse(user.isUserInRole(AccountRole.USERADMINISTRATOR));
}
public void testBuildUserWrongXML() throws IOException{
try{
AccountBuilder.buildAccount(this.invalidReader);
fail("invalid xml");
}catch (SAXException e) {
}
}
}

View File

@ -84,7 +84,7 @@ public class TestBlowfishAuthenticationController extends TestCase {
}catch (Exception e) {
// TODO: handle exception
}
this.controller.setMinuteOffset(0);
this.controller.setLoginTimeout(0);
assertFalse(this.controller.authenticateToken(token,this.clientIp,AccountRole.ENTRYAMINISTRATOR,this.accountName));
}

View File

@ -15,6 +15,8 @@
*/
package org.apache.lucene.gdata.server.registry;
import junit.framework.TestCase;
import org.apache.lucene.gdata.server.ServiceFactory;
import org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory;
import org.apache.lucene.gdata.servlet.handler.RequestHandlerFactory;
@ -22,111 +24,130 @@ 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.ExtensionProfile;
import com.google.gdata.data.Feed;
import junit.framework.TestCase;
/**
* @author Simon Willnauer
*
*
*/
public class TestFeedRegistry extends TestCase {
private GDataServerRegistry reg;
private ProvidedServiceConfig configurator;
@Override
protected void setUp(){
this.reg = GDataServerRegistry.getRegistry();
this.configurator = new ProvidedServiceConfig();
private GDataServerRegistry reg;
private ProvidedServiceConfig configurator;
@Override
protected void setUp() {
this.reg = GDataServerRegistry.getRegistry();
this.configurator = new ProvidedServiceConfig();
this.configurator.setEntryType(Entry.class);
this.configurator.setFeedType(Feed.class);
}
/**
* @see junit.framework.TestCase#tearDown()
*/
@Override
protected void tearDown() throws Exception {
this.reg.flushRegistry();
}
/**
* Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getRegistry()'
*/
public void testGetRegistry() {
GDataServerRegistry reg1 = GDataServerRegistry.getRegistry();
assertEquals("test singleton",this.reg,reg1);
}
this.configurator.setExtensionProfile(new ExtensionProfile());
}
/**
* Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.registerFeed(FeedInstanceConfigurator)'
*/
public void testRegisterService() {
String service = "service";
registerService(service);
assertEquals("Registered Configurator",this.configurator,this.reg.getProvidedService(service));
assertNull("not registered Configurator",this.reg.getProvidedService("something"));
try{
this.reg.getProvidedService(null);
fail("Exception expected");
}catch (IllegalArgumentException e) {
//
}
}
/**
* @see junit.framework.TestCase#tearDown()
*/
@Override
protected void tearDown() throws Exception {
this.reg.flushRegistry();
/**
* Test method for 'org.apache.lucene.gdata.server.registry.FeedRegistry.getFeedConfigurator(String)'
*/
public void testFlushRegistry() {
}
/**
* Test method for
* 'org.apache.lucene.gdata.server.registry.FeedRegistry.getRegistry()'
*/
public void testGetRegistry() {
GDataServerRegistry reg1 = GDataServerRegistry.getRegistry();
assertEquals("test singleton", this.reg, reg1);
}
/**
* Test method for
* 'org.apache.lucene.gdata.server.registry.FeedRegistry.registerFeed(FeedInstanceConfigurator)'
*/
public void testRegisterService() {
String service = "service";
registerService(service);
assertEquals("Registered Configurator",this.configurator,this.reg.getProvidedService(service));
this.reg.flushRegistry();
assertNull("Registry flushed",this.reg.getProvidedService(service));
}
/**
*
*/
public void testIsFeedRegistered(){
String service = "service";
registerService(service);
assertTrue("Feed is registerd",this.reg.isServiceRegistered(service));
assertFalse("null Feed is not registerd",this.reg.isServiceRegistered(null));
assertFalse("Feed is not registerd",this.reg.isServiceRegistered("something"));
}
private void registerService(String servicename){
this.configurator.setName(servicename);
this.reg.registerService(this.configurator);
}
public void testRegisterComponent() throws RegistryException{
assertEquals("Registered Configurator", this.configurator, this.reg
.getProvidedService(service));
assertNull("not registered Configurator", this.reg
.getProvidedService("something"));
try {
this.reg.registerComponent(StorageController.class);
this.reg.getProvidedService(null);
fail("Exception expected");
} catch (IllegalArgumentException e) {
//
}
}
/**
* Test method for
* 'org.apache.lucene.gdata.server.registry.FeedRegistry.getFeedConfigurator(String)'
*/
public void testFlushRegistry() {
String service = "service";
registerService(service);
assertEquals("Registered Configurator", this.configurator, this.reg
.getProvidedService(service));
this.reg.flushRegistry();
assertNull("Registry flushed", this.reg.getProvidedService(service));
}
/**
*
*/
public void testIsFeedRegistered() {
String service = "service";
registerService(service);
assertTrue("Feed is registerd", this.reg.isServiceRegistered(service));
assertFalse("null Feed is not registerd", this.reg
.isServiceRegistered(null));
assertFalse("Feed is not registerd", this.reg
.isServiceRegistered("something"));
}
private void registerService(String servicename) {
this.configurator.setName(servicename);
this.reg.registerService(this.configurator);
}
public void testRegisterComponent() throws RegistryException {
try {
this.reg.registerComponent(StorageController.class, null);
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");
new GDataRequestListener();
try {
this.reg.registerComponent(StorageCoreController.class, null);
fail("no config");
} catch (Exception e) {
// TODO: handle exception
}
this.reg.registerComponent(DefaultRequestHandlerFactory.class, null);
RequestHandlerFactory factory = this.reg.lookup(
RequestHandlerFactory.class,
ComponentType.REQUESTHANDLERFACTORY);
try {
this.reg
.registerComponent(DefaultRequestHandlerFactory.class, null);
fail("RegistryException expected");
} catch (RegistryException e) {
//
//
}
this.reg.registerComponent(ServiceFactory.class);
ServiceFactory servicefactory = this.reg.lookup(ServiceFactory.class,ComponentType.SERVICEFACTORY);
this.reg.registerComponent(ServiceFactory.class, null);
ServiceFactory servicefactory = this.reg.lookup(ServiceFactory.class,
ComponentType.SERVICEFACTORY);
assertNotNull(servicefactory);
assertNotNull(factory);
}
}

View File

@ -61,8 +61,8 @@ public class TestAbstractFeedHandler extends TestCase {
try {
GDataServerRegistry.getRegistry().registerComponent(StorageStub.class);
GDataServerRegistry.getRegistry().registerComponent(ServiceFactoryStub.class);
GDataServerRegistry.getRegistry().registerComponent(StorageStub.class,null);
GDataServerRegistry.getRegistry().registerComponent(ServiceFactoryStub.class,null);
} catch (RegistryException e) {
e.printStackTrace();

View File

@ -24,8 +24,10 @@ public class TestIDGenerator extends TestCase {
}
@Override
protected void tearDown() throws Exception {
this.idgen.stopIDGenerator();
protected void tearDown() throws Exception {
this.idgen.stopIDGenerator();
}
/**

View File

@ -0,0 +1,212 @@
/**
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
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.util.ReferenceCounter;
import org.apache.lucene.index.IndexModifier;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
/**
* @author Simon Willnauer
*
*/
@Component(componentType = ComponentType.STORAGECONTROLLER)
public class StorageCoreControllerStub extends StorageCoreController {
private final IDGenerator idGenerator;
public StorageCoreControllerStub() throws IOException, StorageException {
try{
this.idGenerator = new IDGenerator(5);
}catch (NoSuchAlgorithmException e) {
throw new StorageException(e);
}
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#createIndexModifier()
*/
@Override
protected IndexModifier createIndexModifier() throws IOException {
return null;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#forceWrite()
*/
@Override
public void forceWrite() throws IOException {
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getDirectory()
*/
@Override
protected Directory getDirectory() {
return null;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getBufferSize()
*/
@Override
public int getBufferSize() {
return 1;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getStorageModifier()
*/
@Override
protected StorageModifier getStorageModifier() {
try {
return new StorageModifierStub();
} catch (IOException e) {
e.printStackTrace();
} catch (StorageException e) {
e.printStackTrace();
}
return null;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getPersistFactor()
*/
@Override
public int getPersistFactor() {
return 1;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getStorageQuery()
*/
@Override
protected ReferenceCounter<StorageQuery> getStorageQuery() {
ReferenceCounter<StorageQuery> retVal = new ReferenceCounter<StorageQuery>(new StorageQueryStub(null,null)){
@Override
protected void close() {
//
}
};
retVal.increamentReference();
retVal.increamentReference();
return retVal;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#registerNewStorageQuery()
*/
@Override
protected void registerNewStorageQuery() throws IOException {
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#releaseId()
*/
@Override
public synchronized String releaseId() throws StorageException {
try {
return this.idGenerator.getUID();
} catch (InterruptedException e) {
throw new StorageException(e);
}
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#releaseNewStorageBuffer()
*/
@Override
protected StorageBuffer releaseNewStorageBuffer() {
return null;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#setBufferSize(int)
*/
@Override
public void setBufferSize(int storageBufferSize) {
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#setPersistFactor(int)
*/
@Override
public void setPersistFactor(int storagePersistFactor) {
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#destroy()
*/
@Override
public void destroy() {
this.idGenerator.stopIDGenerator();
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#getStorage()
*/
@Override
public Storage getStorage() throws StorageException {
return new StorageImplementation();
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController#initialize()
*/
@Override
public void initialize() {
// this.setStorageDir(new RAMDirectory());
// super.initialize();
}
}

View File

@ -32,7 +32,10 @@ import org.apache.lucene.store.RAMDirectory;
*
*/
public class StorageModifierStub extends StorageModifier {
public boolean throwException = false;
public StorageModifierStub() throws IOException, StorageException{
super(new StorageCoreControllerStub(), new IndexModifier(new RAMDirectory(),new StandardAnalyzer(),true), new StorageBuffer(1),1, 1);
}
/**
* @param controller
* @param modifier
@ -46,7 +49,7 @@ public class StorageModifierStub extends StorageModifier {
IndexModifier modifier, StorageBuffer buffer, int persitsFactor,
int optimizeInterval) throws IOException, StorageException {
super(new StorageCoreController(), new IndexModifier(new RAMDirectory(),new StandardAnalyzer(),true), new StorageBuffer(1),1, 1);
super(new StorageCoreControllerStub(), new IndexModifier(new RAMDirectory(),new StandardAnalyzer(),true), new StorageBuffer(1),1, 1);
// TODO Auto-generated constructor stub
}
@ -56,7 +59,8 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
protected void close() throws IOException {
if(throwException)
throw new IOException();
}
@ -65,7 +69,8 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
public void createAccount(StorageAccountWrapper account) throws StorageException {
if(throwException)
throw new StorageException();
}
@ -74,7 +79,8 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
public void createFeed(StorageFeedWrapper wrapper) throws StorageException {
if(throwException)
throw new StorageException();
}
@ -83,7 +89,8 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
public void deleteAccount(String accountName) throws StorageException {
if(throwException)
throw new StorageException();
}
@ -92,7 +99,8 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
public void deleteEntry(StorageEntryWrapper wrapper) throws StorageException {
if(throwException)
throw new StorageException();
}
@ -101,7 +109,8 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
public void deleteFeed(String feedId) throws StorageException {
if(throwException)
throw new StorageException();
}
@ -109,8 +118,9 @@ public class StorageModifierStub extends StorageModifier {
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageModifier#forceWrite()
*/
@Override
protected void forceWrite() throws IOException {
public void forceWrite() throws IOException {
if(throwException)
throw new IOException();
}
@ -119,7 +129,8 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
public void insertEntry(StorageEntryWrapper wrapper) throws StorageException {
if(throwException)
throw new StorageException();
}
@ -128,7 +139,8 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
public void updateAccount(StorageAccountWrapper user) throws StorageException {
if(throwException)
throw new StorageException();
}
@ -137,8 +149,10 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
public void updateEntry(StorageEntryWrapper wrapper) throws StorageException {
if(throwException)
throw new StorageException();
if(wrapper != null)
wrapper.getEntry();
}
/**
@ -146,7 +160,8 @@ public class StorageModifierStub extends StorageModifier {
*/
@Override
public void updateFeed(StorageFeedWrapper wrapper) throws StorageException {
if(throwException)
throw new StorageException();
}

View File

@ -0,0 +1,156 @@
/**
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
import java.util.List;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.search.Searcher;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
import com.google.gdata.util.ParseException;
/**
* @author Simon Willnauer
*
*/
public class StorageQueryStub extends StorageQuery {
public boolean booleanReturn = true;
/**
* @param buffer
* @param searcher
*/
public StorageQueryStub(StorageBuffer buffer, Searcher searcher) {
super(buffer, searcher);
// TODO Auto-generated constructor stub
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#checkEntryVersion(java.lang.String, java.lang.String, int)
*/
@Override
protected boolean checkEntryVersion(String id, String feedId, int version) throws IOException {
return booleanReturn;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#close()
*/
@Override
public void close() throws IOException {
super.close();
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#entryQuery(java.util.List, java.lang.String, org.apache.lucene.gdata.server.registry.ProvidedService)
*/
@Override
public List<BaseEntry> entryQuery(List<String> entryIds, String feedId, ProvidedService config) throws IOException, ParseException {
return null;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#getAccountNameForFeedId(java.lang.String)
*/
@Override
public String getAccountNameForFeedId(String feedId) throws IOException {
return null;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#getEntryLastModified(java.lang.String, java.lang.String)
*/
@Override
protected long getEntryLastModified(String entryId, String feedId) throws IOException, StorageException {
return System.currentTimeMillis();
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#getFeedLastModified(java.lang.String)
*/
@Override
protected long getFeedLastModified(String feedId) throws IOException {
return System.currentTimeMillis();
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#getLatestFeedQuery(java.lang.String, int, int, org.apache.lucene.gdata.server.registry.ProvidedService)
*/
@Override
public BaseFeed getLatestFeedQuery(String feedId, int resultCount, int startIndex, ProvidedService config) throws IOException, ParseException {
return null;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#getService(java.lang.String)
*/
@Override
public String getService(String feedID) throws IOException {
return null;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#getUser(java.lang.String)
*/
@Override
public GDataAccount getUser(String username) throws IOException {
return null;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#isEntryStored(java.lang.String, java.lang.String)
*/
@Override
protected boolean isEntryStored(String entryId, String feedId) throws IOException {
return booleanReturn;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#isFeedStored(java.lang.String)
*/
@Override
public boolean isFeedStored(String feedId) throws IOException {
return booleanReturn;
}
/**
* @see org.apache.lucene.gdata.storage.lucenestorage.StorageQuery#singleEntryQuery(java.lang.String, java.lang.String, org.apache.lucene.gdata.server.registry.ProvidedService)
*/
@Override
public BaseEntry singleEntryQuery(String entryId, String feedId, ProvidedService config) throws IOException, ParseException {
return null;
}
}

View File

@ -0,0 +1,133 @@
package org.apache.lucene.gdata.storage.lucenestorage;
import org.apache.lucene.gdata.storage.lucenestorage.SingleHostConcurrentStorageLock.ConcurrencyException;
import junit.framework.TestCase;
public class TestSingelHostConcurrencyLock extends TestCase {
SingleHostConcurrentStorageLock lock;
boolean threadResult = false;
protected void setUp() throws Exception {
this.lock = (SingleHostConcurrentStorageLock)SingleHostConcurrentStorageLock.getConcurrentStorageLock();
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
threadResult = false;
this.lock.close();
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.SingleHostConcurrentStorageLock.getConcurrentStorageLock()'
*/
public void testGetConcurrentStorageLock() {
ConcurrentStorageLock lock = SingleHostConcurrentStorageLock.getConcurrentStorageLock();
assertEquals(lock,SingleHostConcurrentStorageLock.getConcurrentStorageLock() );
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.SingleHostConcurrentStorageLock.setLock(String)'
*/
public void testSetLock() throws InterruptedException {
final String key = "someKey";
final String nextKey = "fooKey";
assertTrue(lock.setLock(key));
assertTrue(lock.isKeyLocked(key));
try{
this.lock.setLock(key);
fail("thread has already locked the key");
}catch (Exception e) {
// TODO: handle exception
}
try{
assertTrue(lock.setLock(nextKey));
fail("thread has already locked the key");
}catch (Exception e) {
// TODO: handle exception
}
Thread t = new Thread(new Runnable(){
public void run(){
threadResult = lock.setLock(key);
}
});
t.start();
t.join(300);
assertFalse(threadResult);
t = new Thread(new Runnable(){
public void run(){
threadResult = lock.setLock(nextKey);
}
});
t.start();
t.join(300);
assertTrue(threadResult);
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.SingleHostConcurrentStorageLock.releaseLock(String)'
*/
public void testReleaseLock() throws InterruptedException {
final String key = "someKey";
final String nextKey = "fooKey";
assertTrue(lock.setLock(key));
assertTrue(lock.isKeyLocked(key));
assertTrue(lock.releaseLock(key));
assertTrue(this.lock.setLock(key));
try{
assertTrue(lock.setLock(nextKey));
fail("thread has already locked the key");
}catch (Exception e) {
// TODO: handle exception
}
Thread t = new Thread(new Runnable(){
public void run(){
threadResult = lock.setLock(nextKey);
}
});
t.start();
t.join(300);
assertTrue(threadResult);
try{
this.lock.releaseLock(nextKey);
fail("current thread is not owner");
}catch (ConcurrencyException e) {
// TODO: handle exception
}
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.SingleHostConcurrentStorageLock.releaseThreadLocks()'
*/
public void testReleaseThreadLocks() {
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.SingleHostConcurrentStorageLock.isKeyLocked(String)'
*/
public void testIsKeyLocked() {
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.SingleHostConcurrentStorageLock.close()'
*/
public void testClose() {
}
}

View File

@ -0,0 +1,236 @@
package org.apache.lucene.gdata.storage.lucenestorage;
import java.io.IOException;
import java.util.List;
import junit.framework.TestCase;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.gdata.utils.ProvidedServiceStub;
import com.google.gdata.data.DateTime;
public class TestStorageBuffer extends TestCase {
private static final String FEEDID = "feed";
private static final String ENTRYID = "someID";
private StorageBuffer buffer;
protected void setUp() throws Exception {
super.setUp();
this.buffer = new StorageBuffer(10);
}
protected void tearDown() throws Exception {
this.buffer.close();
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.StorageBuffer(int)'
*/
public void testStorageBuffer() {
assertEquals(StorageBuffer.DEFAULT_BUFFER_COUNT,new StorageBuffer(StorageBuffer.DEFAULT_BUFFER_COUNT-1).getBufferSize());
assertEquals(StorageBuffer.DEFAULT_BUFFER_COUNT,new StorageBuffer(StorageBuffer.DEFAULT_BUFFER_COUNT).getBufferSize());
assertEquals(StorageBuffer.DEFAULT_BUFFER_COUNT+1,new StorageBuffer(StorageBuffer.DEFAULT_BUFFER_COUNT+1).getBufferSize());
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.addEntry(StorageEntryWrapper)'
*/
public void testAddEntry() throws IOException {
ServerBaseEntry e = createServerBaseEntry(ENTRYID,FEEDID);
StorageEntryWrapper wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
assertEquals(1,this.buffer.getSortedEntries(FEEDID).size());
this.buffer.addEntry(wrapper);
assertEquals(1,this.buffer.getSortedEntries(FEEDID).size());
e.setId("someotherID");
e.setFeedId(FEEDID);
e.setServiceConfig(new ProvidedServiceStub());
wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
assertEquals(2,this.buffer.getSortedEntries(FEEDID).size());
e.setId("someotherID");
e.setFeedId("someOtherFeed");
e.setServiceConfig(new ProvidedServiceStub());
wrapper = new StorageEntryWrapper(e,StorageOperation.UPDATE);
this.buffer.addEntry(wrapper);
wrapper = new StorageEntryWrapper(e,StorageOperation.DELETE);
e.setId("deleted and ingnored");
e.setFeedId("someOtherFeed");
e.setServiceConfig(new ProvidedServiceStub());
this.buffer.addEntry(wrapper);
assertEquals(2,this.buffer.getSortedEntries(FEEDID).size());
assertEquals(1,this.buffer.getSortedEntries("someOtherFeed").size());
assertEquals("Contains 2 different IDs",2,this.buffer.getExculdList().length);
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.addDeleted(String, String)'
*/
public void testAddDeleted() throws IOException {
this.buffer.addDeleted(ENTRYID,FEEDID);
assertNull(this.buffer.getSortedEntries(FEEDID));
assertEquals(1,this.buffer.getExculdList().length);
assertEquals(ENTRYID,this.buffer.getExculdList()[0]);
this.buffer.addDeleted(ENTRYID,FEEDID);
assertNull(this.buffer.getSortedEntries(FEEDID));
assertEquals(1,this.buffer.getExculdList().length);
assertEquals(ENTRYID,this.buffer.getExculdList()[0]);
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.getFeedLastModified(String)'
*/
public void testGetFeedLastModified() throws IOException, InterruptedException {
ServerBaseEntry e = createServerBaseEntry(ENTRYID,FEEDID);
e.setUpdated(new DateTime(System.currentTimeMillis()-200,0));
StorageEntryWrapper wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
assertEquals(new Long(e.getUpdated().getValue()),this.buffer.getFeedLastModified(FEEDID));
//test update
// force timestamp
e.setUpdated(new DateTime(System.currentTimeMillis()-180,0));
wrapper = new StorageEntryWrapper(e,StorageOperation.UPDATE);
this.buffer.addEntry(wrapper);
Long firstAddTimestamp = new Long(e.getUpdated().getValue());
assertEquals(firstAddTimestamp,this.buffer.getFeedLastModified(FEEDID));
// force timestamp
e.setUpdated(new DateTime(System.currentTimeMillis()-160,0));
assertFalse("updated after add" ,e.getUpdated().equals(this.buffer.getFeedLastModified(FEEDID)));
//insert for other feed
String otherID = "someOtherFeedID";
e.setFeedId(otherID);
// force timestamp
e.setUpdated(new DateTime(System.currentTimeMillis()-140,0));
wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
assertEquals(new Long(e.getUpdated().getValue()),this.buffer.getFeedLastModified(otherID));
assertEquals(firstAddTimestamp,this.buffer.getFeedLastModified(FEEDID));
assertTrue(firstAddTimestamp.equals(this.buffer.getFeedLastModified(FEEDID)));
this.buffer.addDeleted(e.getId(),FEEDID);
// time will be set inside the buffer
assertTrue(firstAddTimestamp < this.buffer.getFeedLastModified(FEEDID));
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.getSortedEntries(String)'
*/
public void testGetSortedEntries() throws IOException, InterruptedException {
assertNull(this.buffer.getSortedEntries(FEEDID));
ServerBaseEntry e = createServerBaseEntry("2",FEEDID);
e.setUpdated(new DateTime(System.currentTimeMillis()-200,0));
StorageEntryWrapper wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
e.setId("0");
// force timestamp
e.setUpdated(new DateTime(System.currentTimeMillis()-180,0));
wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
e.setId("1");
// force timestamp
e.setUpdated(new DateTime(System.currentTimeMillis()-160,0));
wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
e.setId("0");
// force timestamp
e.setUpdated(new DateTime(System.currentTimeMillis()-140,0));
wrapper = new StorageEntryWrapper(e,StorageOperation.UPDATE);
this.buffer.addEntry(wrapper);
// force timestamp
e.setUpdated(new DateTime(System.currentTimeMillis()-120,0));
wrapper = new StorageEntryWrapper(e,StorageOperation.DELETE);
this.buffer.addEntry(wrapper);
List<StorageEntryWrapper> list = this.buffer.getSortedEntries(FEEDID);
assertEquals(3,list.size());
for (int i = 0; i < 3; i++) {
assertEquals(""+i,list.get(i).getEntryId());
}
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.getEntry(String, String)'
*/
public void testGetEntry() throws IOException {
assertNull(this.buffer.getEntry(ENTRYID,FEEDID));
ServerBaseEntry e = createServerBaseEntry(ENTRYID,FEEDID);
StorageEntryWrapper wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
assertSame(wrapper,this.buffer.getEntry(ENTRYID,FEEDID));
e = createServerBaseEntry("0",FEEDID);
wrapper = new StorageEntryWrapper(e,StorageOperation.UPDATE);
this.buffer.addEntry(wrapper);
assertSame(wrapper,this.buffer.getEntry("0",FEEDID));
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.getExculdList()'
*/
public void testGetExculdList() throws IOException {
ServerBaseEntry e = createServerBaseEntry(ENTRYID,FEEDID);
StorageEntryWrapper wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
this.buffer.addEntry(wrapper);
assertEquals(1,this.buffer.getExculdList().length);
assertEquals(wrapper.getEntryId(),this.buffer.getExculdList()[0]);
wrapper = new StorageEntryWrapper(e,StorageOperation.UPDATE);
this.buffer.addEntry(wrapper);
assertEquals(1,this.buffer.getExculdList().length);
assertEquals(wrapper.getEntryId(),this.buffer.getExculdList()[0]);
this.buffer.addDeleted(ENTRYID,FEEDID);
assertEquals(1,this.buffer.getExculdList().length);
assertEquals(wrapper.getEntryId(),this.buffer.getExculdList()[0]);
e = createServerBaseEntry("someOtherEntry","someOtherFeed");
wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
this.buffer.addEntry(wrapper);
assertEquals(2,this.buffer.getExculdList().length);
}
/*
* Test method for 'org.apache.lucene.gdata.storage.lucenestorage.StorageBuffer.close()'
*/
public void testClose() throws IOException {
ServerBaseEntry e = createServerBaseEntry(ENTRYID,FEEDID);
StorageEntryWrapper wrapper = new StorageEntryWrapper(e,StorageOperation.INSERT);
this.buffer.addEntry(wrapper);
assertNotNull(this.buffer.getSortedEntries(FEEDID));
assertNotNull(this.buffer.getEntry(ENTRYID,FEEDID));
assertEquals(1,this.buffer.getExculdList().length);
this.buffer.close();
assertNull(this.buffer.getSortedEntries(FEEDID));
assertNull(this.buffer.getEntry(ENTRYID,FEEDID));
assertEquals(0,this.buffer.getExculdList().length);
}
public ServerBaseEntry createServerBaseEntry(String entryID, String feedId) throws IOException{
ServerBaseEntry e = new ServerBaseEntry();
e.setId(entryID);
e.setFeedId(feedId);
e.setServiceConfig(new ProvidedServiceStub());
return e;
}
}

View File

@ -0,0 +1,443 @@
package org.apache.lucene.gdata.storage.lucenestorage;
import java.util.concurrent.atomic.AtomicBoolean;
import junit.framework.TestCase;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.ModificationConflictException;
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.utils.MultiThreadEntryStub;
import org.apache.lucene.gdata.utils.ProvidedServiceStub;
import org.apache.lucene.gdata.utils.Visitor;
import com.google.gdata.data.DateTime;
public class TestStorageImplementation extends TestCase {
private static GDataServerRegistry reg = null;
private Storage storage;
public static boolean fail = false;
protected void setUp() throws Exception {
if (reg == null) {
reg = GDataServerRegistry.getRegistry();
if(reg.lookup(StorageController.class,ComponentType.STORAGECONTROLLER)!= null);
reg.destroy();
reg.registerComponent(StorageCoreControllerStub.class,null);
}
this.storage = reg.lookup(StorageController.class,
ComponentType.STORAGECONTROLLER).getStorage();
}
protected void tearDown() throws Exception {
this.storage.close();
fail = false;
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.storeEntry(ServerBaseEntry)'
*/
public void testStoreEntry() {
try {
this.storage.storeEntry(null);
fail("entry is null");
} catch (StorageException e) {
//
}
ServerBaseEntry entry = new ServerBaseEntry();
entry.setServiceConfig(new ProvidedServiceStub());
try {
this.storage.storeEntry(entry);
fail("feed is null");
} catch (StorageException e) {
//
}
entry.setFeedId("someID");
try {
this.storage.storeEntry(entry);
} catch (StorageException e1) {
fail("unexpected exception");
}
entry.setServiceConfig(null);
try {
this.storage.storeEntry(entry);
fail("no service config");
} catch (StorageException e) {
}
entry.setVersion(5);
try {
this.storage.storeEntry(entry);
fail("version is greater than 1");
} catch (StorageException e) {
}
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.deleteEntry(ServerBaseEntry)'
*/
public void testDeleteEntry() throws InterruptedException {
try {
this.storage.storeEntry(null);
fail("entry is null");
} catch (StorageException e) {
//
}
ServerBaseEntry entry = new ServerBaseEntry();
entry.setServiceConfig(new ProvidedServiceStub());
entry.setId("someID");
entry.setFeedId("someID");
try {
this.storage.storeEntry(entry);
} catch (StorageException e) {
fail("unexpected exception");
//
}
entry.setFeedId(null);
try {
this.storage.deleteEntry(entry);
fail("feed is null");
} catch (StorageException e) {
//
}
entry.setFeedId("someID");
try {
this.storage.deleteEntry(entry);
} catch (StorageException e1) {
e1.printStackTrace();
fail("unexpected exception");
}
entry.setFeedId("someID");
try {
this.storage.deleteEntry(entry);
} catch (StorageException e1) {
e1.printStackTrace();
fail("unexpected exception");
}
Object monitor = new Object();
AtomicBoolean reached = new AtomicBoolean(false);
MultiThreadEntryStub concuEntry = new MultiThreadEntryStub();
concuEntry.setId(System.currentTimeMillis() + "");
ProvidedService conf = new ProvidedServiceStub();
concuEntry.setServiceConfig(conf);
concuEntry.setUpdated(DateTime.now());
concuEntry.setFeedId("feed");
this.storage.storeEntry(concuEntry);
storage.close();
concuEntry.acceptGetVersionVisitor(getMonitorVisitor(monitor,reached));
Thread t1 = getDelThread(storage, concuEntry, false);
Thread t2 = getDelThread(storage, concuEntry, true);
t1.start();
/*
* Wait active -- not nice but works fine here
* wait until thread parked
*/
while (true) {
synchronized (monitor) {
if (reached.get())
break;
monitor.wait(10);
}
}
t2.start();
t2.join(800);
/*
* Wait active -- not nice but works fine here
* wake up the waiting thread
*/
while (true) {
synchronized (monitor) {
if (!reached.get())
break;
monitor.notifyAll();
}
}
t1.join(300);
if (fail)
fail("thread failed -- see stacktrace");
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.updateEntry(ServerBaseEntry)'
*/
public void testUpdateEntry() throws InterruptedException {
Object monitor = new Object();
AtomicBoolean reached = new AtomicBoolean(false);
MultiThreadEntryStub concuEntry = new MultiThreadEntryStub();
concuEntry.setId(System.currentTimeMillis() + "");
ProvidedService conf = new ProvidedServiceStub();
concuEntry.setServiceConfig(conf);
concuEntry.setUpdated(DateTime.now());
concuEntry.setFeedId("feed");
this.storage.storeEntry(concuEntry);
storage.close();
concuEntry.acceptGetEntryVisitor(getMonitorVisitor(monitor,reached));
Thread t1 = getUpdThread(storage, concuEntry, false);
Thread t2 = getUpdThread(storage, concuEntry, true);
t1.start();
/*
* Wait active -- not nice but works fine here
* wait until thread parked
*/
while (true) {
synchronized (monitor) {
if (reached.get())
break;
monitor.wait(10);
}
}
t2.start();
t2.join(800);
/*
* Wait active -- not nice but works fine here
* wake up the waiting thread
*/
while (true) {
synchronized (monitor) {
if (!reached.get())
break;
monitor.notifyAll();
}
}
t1.join(300);
if (fail)
fail("thread failed -- see stacktrace");
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.getFeed(ServerBaseFeed)'
*/
public void testGetFeed() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.getEntry(ServerBaseEntry)'
*/
public void testGetEntry() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.close()'
*/
public void testClose() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.storeAccount(GDataAccount)'
*/
public void testStoreAccount() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.updateAccount(GDataAccount)'
*/
public void testUpdateAccount() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.deleteAccount(String)'
*/
public void testDeleteAccount() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.storeFeed(ServerBaseFeed,
* String)'
*/
public void testStoreFeed() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.deleteFeed(String)'
*/
public void testDeleteFeed() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.updateFeed(ServerBaseFeed,
* String)'
*/
public void testUpdateFeed() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.getServiceForFeed(String)'
*/
public void testGetServiceForFeed() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.getAccount(String)'
*/
public void testGetAccount() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.getAccountNameForFeedId(String)'
*/
public void testGetAccountNameForFeedId() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.getEntryLastModified(String,
* String)'
*/
public void testGetEntryLastModified() {
}
/*
* Test method for
* 'org.apache.lucene.gdata.storage.lucenestorage.StorageImplementation.getFeedLastModified(String)'
*/
public void testGetFeedLastModified() {
}
static class Runner implements Runnable {
Storage s;
StorageController c;
ServerBaseEntry e;
boolean expConf;
StorageOperation op;
public Runner(Storage s, ServerBaseEntry e,
boolean expectConflict, StorageOperation op) {
this.s = s;
this.e = e;
this.expConf = expectConflict;
this.op = op;
}
public void run() {
try {
if (this.op == StorageOperation.DELETE)
this.s.deleteEntry(e);
if (this.op == StorageOperation.UPDATE)
this.s.updateEntry(e);
if (expConf)
fail = true;
} catch (ModificationConflictException ex) {
if (!expConf)
fail = true;
ex.printStackTrace();
} catch (StorageException ex) {
ex.printStackTrace();
fail = true;
}
}
}
private Visitor getMonitorVisitor(final Object monitor, final AtomicBoolean reached){
/*
* The executing thread stops at a defined position while holding the semaphore inside the storageImpl
*/
return new Visitor(){
public void execute(Object[] o){
synchronized (monitor) {
try {
reached.set(true);
monitor.wait();
reached.set(false);
} catch (InterruptedException e) {
//
}
}
}
};
}
private Thread getDelThread(Storage s, ServerBaseEntry e,
boolean conflictExpected) {
Thread t1 = new Thread(new Runner(s, e, conflictExpected,
StorageOperation.DELETE));
t1.setPriority(Thread.MAX_PRIORITY);
return t1;
}
private Thread getUpdThread(Storage s, ServerBaseEntry e,
boolean conflictExpected) {
Thread t1 = new Thread(new Runner(s, e, conflictExpected,
StorageOperation.UPDATE));
t1.setPriority(Thread.MAX_PRIORITY);
return t1;
}
}

View File

@ -7,10 +7,7 @@ import junit.framework.TestCase;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.data.ServerBaseFeed;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.StorageController;
import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
@ -23,6 +20,7 @@ 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;
@ -50,13 +48,16 @@ public class TestStorageModifier extends TestCase {
private static String service = "myService";
protected void setUp() throws Exception {
GDataServerRegistry.getRegistry().registerComponent(
StorageCoreController.class);
this.controller = new StorageCoreController();
this.dir = new RAMDirectory();
this.controller.setStorageDir(this.dir);
this.controller.setKeepRecoveredFiles(false);
this.controller.setOptimizeInterval(10);
this.controller.setRecover(false);
this.controller.setBufferSize(10);
this.controller.setPersistFactor(10);
this.controller.initialize();
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();
@ -65,8 +66,9 @@ public class TestStorageModifier extends TestCase {
protected void tearDown() throws Exception {
this.count = 1;
// destroy all resources
GDataServerRegistry.getRegistry().destroy();// TODO remove dependency
// here
this.controller.destroy();
}
@ -121,7 +123,8 @@ public class TestStorageModifier extends TestCase {
assertEquals("updated Title:", insertString, fetchedEntry
.getTitle().getPlainText());
}
}
/*
@ -132,14 +135,16 @@ public class TestStorageModifier extends TestCase {
ParseException, StorageException {
Thread a = getRunnerThread(this.count);
a.start();
Thread b = getRunnerThread((this.count += 10));
b.start();
// wait for the first thread to check for the inserted entries
a.start();
// wait for the first thread to check for the inserted entries
a.join();
try{
for (int i = 1; i < this.count; i++) {
ReferenceCounter<StorageQuery> innerQuery = this.controller
.getStorageQuery();
BaseEntry e = innerQuery.get().singleEntryQuery("" + i, feedId,
@ -358,6 +363,7 @@ public class TestStorageModifier extends TestCase {
StorageEntryWrapper wrapper = new StorageEntryWrapper(en,
StorageOperation.INSERT);
modifier.insertEntry(wrapper);
// System.out.println("insert: "+i+" Thread: "+Thread.currentThread().getName());
} catch (Exception e1) {
e1.printStackTrace();

View File

@ -10,15 +10,13 @@ import junit.framework.TestCase;
import org.apache.lucene.gdata.data.GDataAccount;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.data.ServerBaseFeed;
import org.apache.lucene.gdata.server.registry.ComponentType;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.StorageController;
import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.gdata.storage.lucenestorage.util.ReferenceCounter;
import org.apache.lucene.gdata.utils.ProvidedServiceStub;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.BaseFeed;
@ -37,12 +35,17 @@ public class TestStorageQuery extends TestCase {
private static String accountName = "simon";
private static String service = ProvidedServiceStub.SERVICE_NAME;
protected void setUp() throws Exception {
GDataServerRegistry.getRegistry().registerComponent(StorageCoreController.class);
this.configurator = new ProvidedServiceStub();
GDataServerRegistry.getRegistry().registerService(this.configurator);
this.controller = (StorageCoreController)GDataServerRegistry.getRegistry().lookup(StorageController.class,ComponentType.STORAGECONTROLLER);
this.controller = new StorageCoreController();
this.dir = new RAMDirectory();
this.controller.setStorageDir(this.dir);
this.controller.setKeepRecoveredFiles(false);
this.controller.setOptimizeInterval(10);
this.controller.setRecover(false);
this.controller.setBufferSize(10);
this.controller.setPersistFactor(10);
this.controller.initialize();
this.configurator = new ProvidedServiceStub();
this.modifier = this.controller.getStorageModifier();
this.dir = this.controller.getDirectory();
ServerBaseFeed feed = new ServerBaseFeed();
@ -55,12 +58,8 @@ public class TestStorageQuery extends TestCase {
insertEntries(this.count);
this.query = this.controller.getStorageQuery();
}
/**
* @param entrycount
* @throws IOException
@ -93,7 +92,7 @@ public class TestStorageQuery extends TestCase {
protected void tearDown() throws Exception {
this.query.decrementRef();
GDataServerRegistry.getRegistry().destroy();
this.controller.destroy();
}
/*
@ -244,6 +243,43 @@ public class TestStorageQuery extends TestCase {
assertEquals(entry.getUpdated().getValue(),this.query.get().getFeedLastModified(feedId));
this.query = this.controller.getStorageQuery();
assertEquals(entry.getUpdated().getValue(),this.query.get().getFeedLastModified(feedId));
}
public void testCheckVersionId() throws IOException, StorageException{
this.modifier.forceWrite();
ReferenceCounter<StorageQuery> sQuery = this.controller.getStorageQuery();
ServerBaseEntry entry = new ServerBaseEntry(new Entry());
entry.setId("test");
entry.setServiceConfig(this.configurator);
entry.setUpdated(new DateTime(System.currentTimeMillis(),0));
entry.setFeedId(feedId);
entry.setVersion(5);
StorageEntryWrapper wrapper = new StorageEntryWrapper(entry,StorageOperation.INSERT);
this.modifier.insertEntry(wrapper);
//test in buffer
assertTrue(sQuery.get().checkEntryVersion(entry.getId(),entry.getFeedId(),entry.getVersion()));
assertFalse(sQuery.get().checkEntryVersion(entry.getId(),entry.getFeedId(),10000));
assertFalse(sQuery.get().checkEntryVersion(entry.getId(),"someOtherFeed",entry.getVersion()));
assertFalse(sQuery.get().checkEntryVersion("foobar",entry.getFeedId(),entry.getVersion()));
this.modifier.forceWrite();
//test in buffer after written
assertTrue(sQuery.get().checkEntryVersion(entry.getId(),entry.getFeedId(),entry.getVersion()));
assertFalse(sQuery.get().checkEntryVersion(entry.getId(),entry.getFeedId(),10000));
assertFalse(sQuery.get().checkEntryVersion(entry.getId(),"someOtherFeed",entry.getVersion()));
assertFalse(sQuery.get().checkEntryVersion("foobar",entry.getFeedId(),entry.getVersion()));
sQuery.decrementRef();
sQuery = this.controller.getStorageQuery();
//test in index
assertTrue(sQuery.get().checkEntryVersion(entry.getId(),entry.getFeedId(),entry.getVersion()));
assertFalse(sQuery.get().checkEntryVersion(entry.getId(),entry.getFeedId(),10000));
assertFalse(sQuery.get().checkEntryVersion("foobar",entry.getFeedId(),entry.getVersion()));
sQuery.decrementRef();
}
private void entryQueryHelper(ReferenceCounter<StorageQuery> currentQuery) throws IOException, ParseException{
@ -255,7 +291,9 @@ public class TestStorageQuery extends TestCase {
assertEquals(entryIdList.size(),entryList.size());
List<String> entryIdCompare = new ArrayList<String>();
for (BaseEntry entry : entryList) {
assertEquals("1",entry.getVersionId());
entryIdCompare.add(entry.getId());
}
assertTrue(entryIdList.containsAll(entryIdCompare));

View File

@ -3,35 +3,34 @@ package org.apache.lucene.gdata.storage.lucenestorage.recover;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.rmi.registry.Registry;
import junit.framework.TestCase;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.storage.StorageException;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper;
import org.apache.lucene.gdata.storage.lucenestorage.StorageModifier;
import org.apache.lucene.gdata.storage.lucenestorage.StorageModifierStub;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.gdata.utils.ProvidedServiceStub;
import org.easymock.MockControl;
import com.google.gdata.data.DateTime;
import junit.framework.TestCase;
public class TestRecoverController extends TestCase {
private RecoverController writeController;
private RecoverController readController;
private File recDir = new File("./temp/");
private File recDir;
private String feedId = "feedid";
private String entryId = "entryId";
protected void setUp() throws Exception {
this.recDir = new File("unittest"+System.currentTimeMillis());
if(!this.recDir.exists())
this.recDir.mkdir();
this.recDir.deleteOnExit();
GDataServerRegistry.getRegistry().registerService(new ProvidedServiceStub());
this.writeController = new RecoverController(this.recDir,false,false);
this.readController = new RecoverController(this.recDir,true,false);
this.writeController = new RecoverController(this.recDir,false,true);
this.readController = new RecoverController(this.recDir,true,true);
@ -82,8 +81,8 @@ public class TestRecoverController extends TestCase {
fail("unexpected exception"+e.getMessage());
}
this.readController.destroy();
assertEquals(0,this.recDir.listFiles().length);
assertNotSame(length,this.recDir.listFiles().length);
assertEquals(1,this.recDir.listFiles().length);
createCorruptedFile();
this.readController.initialize();
try{
@ -92,7 +91,7 @@ public class TestRecoverController extends TestCase {
fail("unexpected exception"+e.getMessage());
}
this.readController.destroy();
assertEquals(1,this.recDir.listFiles().length);
assertEquals(2,this.recDir.listFiles().length);
}

View File

@ -8,7 +8,6 @@ import java.util.List;
import junit.framework.TestCase;
import org.apache.lucene.gdata.server.registry.GDataServerRegistry;
import org.apache.lucene.gdata.server.registry.ProvidedService;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper;
import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.StorageOperation;
import org.apache.lucene.gdata.utils.ProvidedServiceStub;

View File

@ -0,0 +1,92 @@
/**
* 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.utils;
import org.apache.lucene.gdata.data.ServerBaseEntry;
import com.google.gdata.data.BaseEntry;
/**
* @author Simon Willnauer
*
*/
public class MultiThreadEntryStub extends ServerBaseEntry {
private Visitor getEntryVisitor;
private Visitor getVersionVisitor;
/**
*
*/
public MultiThreadEntryStub() {
}
/**
* @param arg0
*/
public MultiThreadEntryStub(BaseEntry arg0) {
super(arg0);
}
public void acceptGetEntryVisitor(Visitor visitor){
this.getEntryVisitor = visitor;
}
public void acceptGetVersionVisitor(Visitor visitor){
this.getVersionVisitor = visitor;
}
/**
* @see org.apache.lucene.gdata.data.ServerBaseEntry#getEntry()
*/
@Override
public BaseEntry getEntry() {
if(this.getEntryVisitor != null){
this.getEntryVisitor.execute(null);
}
return super.getEntry();
}
/**
* @see org.apache.lucene.gdata.data.ServerBaseEntry#getVersion()
*/
@Override
public int getVersion() {
if(this.getVersionVisitor != null){
this.getVersionVisitor.execute(null);
}
return super.getVersion();
}
}

View File

@ -35,4 +35,7 @@ public class ProvidedServiceStub implements ProvidedService {
return SERVICE_NAME;
}
public void destroy() {
}
}

View File

@ -57,4 +57,9 @@ public class StorageControllerStub implements StorageController {
public void initialize() {
}
public String releaseId() {
return null;
}
}

View File

@ -170,4 +170,9 @@ public static String SERVICE_TYPE_RETURN = "service";
return null;
}
public String releaseId() {
return null;
}
}

View File

@ -1,11 +1,8 @@
package org.apache.lucene.gdata.utils;
import java.text.ParseException;
import java.util.Calendar;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import com.sun.org.apache.xalan.internal.xsltc.compiler.Pattern;
import junit.framework.TestCase;
@ -18,24 +15,30 @@ public class TestDateFormater extends TestCase {
protected void tearDown() throws Exception {
super.tearDown();
}
/*
* Test method for 'org.apache.lucene.gdata.utils.DateFormater.formatDate(Date, String)'
*/
public void testFormatDate() throws ParseException {
// this reg. --> bit weak but does the job
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("[A-Z][a-z]{1,2}, [0-9]{1,2} [A-Z][a-z]{2} [0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2} [A-Z]{2,4}");
Date date = new Date();
String formatedDate = DateFormater.formatDate(date,DateFormater.HTTP_HEADER_DATE_FORMAT);
assertTrue(pattern.matcher(formatedDate).matches());
DateFormater.parseDate("Sun, 25 Jun 2006 13:51:23 +0000",DateFormater.HTTP_HEADER_DATE_FORMAT,DateFormater.HTTP_HEADER_DATE_FORMAT_TIME_OFFSET);
DateFormater.parseDate("Sun, 25 Jun 2006 13:51:23 CEST",DateFormater.HTTP_HEADER_DATE_FORMAT,DateFormater.HTTP_HEADER_DATE_FORMAT_TIME_OFFSET);
//TODO extend this
}
public void testFormatDateStack(){
DateFormater formater = new DateFormater();
SimpleDateFormat f1 = formater.getFormater();
SimpleDateFormat f2 = formater.getFormater();
assertNotSame(f1,f2);
formater.returnFomater(f1);
assertSame(f1,formater.getFormater());
formater.returnFomater(f2);
assertSame(f2,formater.getFormater());
}
}

View File

@ -0,0 +1,139 @@
package org.apache.lucene.gdata.utils;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
public class TestSimpleObjectPool extends TestCase {
private Pool testPool;
private int SIZE = 10;
protected void setUp() throws Exception {
this.testPool =new SimpleObjectPool(SIZE,new ObjectFactoryStub());
}
protected void tearDown() throws Exception {
super.tearDown();
}
/*
* Test method for 'org.apache.lucene.gdata.utils.SimpleObjectPool.SimpleObjectPool(int, PoolObjectFactory<Type>)'
*/
public void testSimpleObjectPool() {
SimpleObjectPool pool = new SimpleObjectPool(1,new ObjectFactoryStub());
assertEquals(pool.getSize(),SimpleObjectPool.MINIMALSIZE);
pool = new SimpleObjectPool(-100,new ObjectFactoryStub());
assertEquals(pool.getSize(),SimpleObjectPool.MINIMALSIZE);
pool = new SimpleObjectPool(new ObjectFactoryStub());
assertEquals(pool.getSize(),SimpleObjectPool.DEFAULTSIZE);
pool = new SimpleObjectPool(100,new ObjectFactoryStub());
assertEquals(100,pool.getSize());
try{
pool = new SimpleObjectPool(1,null);
fail("factory must not be null");
}catch (Exception e) {
// TODO: handle exception
}
}
/*
* Test method for 'org.apache.lucene.gdata.utils.SimpleObjectPool.aquire()'
*/
public void testAquire() {
List l = new ArrayList(SIZE);
for (int i = 0; i < SIZE; i++) {
Object o = this.testPool.aquire();
assertNotNull(o);
assertFalse(l.contains(o));
l.add(o);
}
for (Object object : l) {
this.testPool.release(object);
}
for (int i = 0; i < SIZE; i++) {
Object o = this.testPool.aquire();
assertNotNull(o);
assertTrue(l.contains(o));
}
}
/*
* Test method for 'org.apache.lucene.gdata.utils.SimpleObjectPool.release(Type)'
*/
public void testRelease() {
List l = new ArrayList(SIZE);
for (int i = 0; i < SIZE; i++) {
Object o = this.testPool.aquire();
assertNotNull(o);
assertFalse(l.contains(o));
l.add(o);
}
for (Object object : l) {
this.testPool.release(object);
}
for (int i = 0; i < 10; i++) {
this.testPool.release(new Object());
}
for (int i = 0; i < SIZE; i++) {
Object o = this.testPool.aquire();
assertNotNull(o);
assertTrue(l.contains(o));
}
//############################
for (Object object : l) {
this.testPool.release(object);
}
for (int i = 0; i < SIZE +SIZE; i++) {
Object o = this.testPool.aquire();
assertNotNull(o);
if(i>= SIZE)
assertFalse(l.contains(o));
else
assertTrue(l.contains(o));
}
}
public void testDestroy(){
this.testPool.destroy();
try{
this.testPool.aquire();
fail("pool is already closed");
}catch (Exception e) {
// TODO: handle exception
}
this.testPool.release(new Object());
}
static class ObjectFactoryStub implements PoolObjectFactory{
public Object getInstance() {
return new Object();
}
public void destroyInstance(Object type) {
//
}
}
}

View File

@ -0,0 +1,5 @@
package org.apache.lucene.gdata.utils;
public interface Visitor {
public void execute(Object[] objects);
}

View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<gdata>
<service name="feed" public="true">
<service name="feed" poolSize="20" public="true">
<feed-class>com.google.gdata.data.Feed</feed-class>
<entry-class>com.google.gdata.data.Entry</entry-class>
<extension-profile>
com.google.gdata.data.ExtensionProfile
</extension-profile>
</service>
<service name="calendar" public="true">
<service name="calendar" poolSize="20" public="true">
<feed-class>
com.google.gdata.data.extensions.EventFeed
</feed-class>
@ -20,16 +20,34 @@
</service>
<server-components>
<component>
org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController
<class>
org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController
</class>
<configuration>
<property name="bufferSize">20</property>
<property name="optimizeInterval">20</property>
<property name="persistFactor">20</property>
<property name="directory">/tmp/storage</property>
<property name="recover">true</property>
<property name="keepRecoveredFiles">false</property>
</configuration>
</component>
<component>
org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory
<class>
org.apache.lucene.gdata.servlet.handler.DefaultRequestHandlerFactory
</class>
</component>
<component>
org.apache.lucene.gdata.server.ServiceFactory
<class>org.apache.lucene.gdata.server.ServiceFactory</class>
</component>
<component>
org.apache.lucene.gdata.server.authentication.BlowfishAuthenticationController
<class>
org.apache.lucene.gdata.server.authentication.BlowfishAuthenticationController
</class>
<configuration>
<property name="key">cryptKey</property>
<property name="loginTimeout">60</property>
</configuration>
</component>
</server-components>
</gdata>

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="feed-class" type="xs:string" />
<xs:element name="entry-class" type="xs:string" />
<xs:element name="extension-profile" type="xs:string" />
<xs:element name="class" type="xs:string" />
<xs:element name="property">
<xs:complexType mixed="true">
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="configuration">
<xs:complexType>
<xs:sequence>
<xs:element ref="property" minOccurs="1"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="service">
<xs:complexType>
<xs:sequence>
<xs:element ref="feed-class" maxOccurs="1"
minOccurs="1" />
<xs:element ref="entry-class" maxOccurs="1"
minOccurs="1" />
<xs:element ref="extension-profile" maxOccurs="1"
minOccurs="1" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="public" type="xs:boolean" />
<xs:attribute name="poolSize" type="xs:nonNegativeInteger"
use="required" />
</xs:complexType>
</xs:element>
<xs:element name="component">
<xs:complexType>
<xs:sequence>
<xs:element ref="class" maxOccurs="1" minOccurs="1" />
<xs:element ref="configuration" minOccurs="0"
maxOccurs="1" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="server-components">
<xs:complexType>
<xs:sequence>
<xs:element ref="component" minOccurs="1"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="gdata">
<xs:complexType>
<xs:sequence>
<xs:element ref="service" minOccurs="1"
maxOccurs="unbounded" />
<xs:element ref="server-components" maxOccurs="1"
minOccurs="1" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

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.persistFactor">20</entry>
<entry key="gdata.server.storage.lucene.optimizeInterval">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

@ -13,6 +13,11 @@
org.apache.lucene.gdata.server.registry.RegistryContextListener
</listener-class>
</listener>
<listener>
<listener-class>
org.apache.lucene.gdata.server.registry.GDataRequestListener
</listener-class>
</listener>
<servlet>
<servlet-name>ControllerServlet</servlet-name>
<servlet-class>