mirror of https://github.com/apache/lucene.git
gdata fixes: LUCENE-653, LUCENE-654
git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@432040 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d24ee28c66
commit
d3629f25eb
|
@ -11,7 +11,7 @@
|
|||
<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">
|
||||
<condition property="junit.excludes" value="**/db4o/**/*.java">
|
||||
<not>
|
||||
<isset property="db4o.jar.present"/>
|
||||
</not>
|
||||
|
|
|
@ -18,9 +18,9 @@ package org.apache.lucene.gdata.search;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.lucene.document.Document;
|
||||
|
@ -46,7 +46,7 @@ public class StandardGdataSearcher implements GDataSearcher<String> {
|
|||
|
||||
private final ReferenceCounter<IndexSearcher> searcher;
|
||||
|
||||
private static final Map<String, QueryFilter> queryFilterCache = new WeakHashMap<String, QueryFilter>();
|
||||
private static final Map<String, QueryFilter> queryFilterCache = new HashMap<String, QueryFilter>();
|
||||
|
||||
/** constructs a new GdataSearcher
|
||||
* @param searcher - the current lucene searcher instance
|
||||
|
@ -77,15 +77,15 @@ public class StandardGdataSearcher implements GDataSearcher<String> {
|
|||
QueryFilter filter = null;
|
||||
synchronized (queryFilterCache) {
|
||||
filter = queryFilterCache.get(feedId);
|
||||
}
|
||||
|
||||
if (filter == null)
|
||||
filter = new QueryFilter(new TermQuery(new Term(
|
||||
IndexDocument.FIELD_FEED_ID, feedId)));
|
||||
IndexSearcher indexSearcher = this.searcher.get();
|
||||
Hits hits = indexSearcher.search(query, filter);
|
||||
synchronized (queryFilterCache) {
|
||||
queryFilterCache.put(feedId, filter);
|
||||
}
|
||||
IndexSearcher indexSearcher = this.searcher.get();
|
||||
Hits hits = indexSearcher.search(query, filter);
|
||||
|
||||
return collectHits(hits, hitcount, offset);
|
||||
|
||||
}
|
||||
|
@ -126,7 +126,10 @@ public class StandardGdataSearcher implements GDataSearcher<String> {
|
|||
}
|
||||
|
||||
static void flushFilterCache() {
|
||||
queryFilterCache.clear();
|
||||
synchronized (queryFilterCache) {
|
||||
queryFilterCache.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -94,10 +94,13 @@ public class GdataCategoryStrategy extends ContentStrategy {
|
|||
|
||||
StringBuilder contentBuilder = new StringBuilder();
|
||||
StringBuilder schemeBuilder = new StringBuilder();
|
||||
String nodeName = node.getNodeName();
|
||||
/*
|
||||
* enable more than one category element
|
||||
* enable more than one category element -- check the node name if
|
||||
* category strategy is used with an element not named "category"
|
||||
*/
|
||||
while (node != null) {
|
||||
while (node != null && nodeName != null
|
||||
&& nodeName.equals(node.getNodeName())) {
|
||||
NamedNodeMap attributeMap = node.getAttributes();
|
||||
if (attributeMap == null)
|
||||
throw new NotIndexableException(
|
||||
|
@ -112,7 +115,7 @@ public class GdataCategoryStrategy extends ContentStrategy {
|
|||
throw new NotIndexableException(
|
||||
"category term attribute not present");
|
||||
contentBuilder.append(termNode.getTextContent()).append(" ");
|
||||
|
||||
|
||||
Node labelNode = attributeMap.getNamedItem(LABEL);
|
||||
if (labelNode != null)
|
||||
contentBuilder.append(labelNode.getTextContent()).append(" ");
|
||||
|
|
|
@ -133,4 +133,34 @@ class GDataIndexDocument implements IndexDocument {
|
|||
return this.optimizeAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
if(obj == null)
|
||||
return false;
|
||||
if(this == obj)
|
||||
return true;
|
||||
if(obj instanceof GDataIndexDocument){
|
||||
GDataIndexDocument other = (GDataIndexDocument)obj;
|
||||
if(this.id == null)
|
||||
return false;
|
||||
return this.id.equals(other.id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
if(this.id == null)
|
||||
return super.hashCode();
|
||||
return this.id.hashCode();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Collection;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
@ -33,6 +34,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.lucene.gdata.data.ServerBaseEntry;
|
||||
import org.apache.lucene.gdata.data.ServerBaseFeed;
|
||||
import org.apache.lucene.gdata.search.GDataSearcher;
|
||||
import org.apache.lucene.gdata.search.SearchComponent;
|
||||
import org.apache.lucene.gdata.search.StandardGdataSearcher;
|
||||
|
@ -115,10 +117,8 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
* add a schema to the index controller and create the indexer. create
|
||||
* directories and check out existing indexes
|
||||
*/
|
||||
protected void addIndexSchema(IndexSchema schema) {
|
||||
if (this.destroyed.get())
|
||||
throw new IllegalStateException(
|
||||
"IndexController has been destroyed");
|
||||
protected void addIndexSchema(final IndexSchema schema) {
|
||||
checkDestroyed();
|
||||
if (schema.getName() == null)
|
||||
throw new IllegalStateException(
|
||||
"schema has no name -- is not associated with any service");
|
||||
|
@ -142,7 +142,7 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
|
||||
}
|
||||
|
||||
protected ServiceIndex createIndexer(IndexSchema schema) throws IOException {
|
||||
protected ServiceIndex createIndexer(final IndexSchema schema) throws IOException {
|
||||
GDataIndexer indexer;
|
||||
File indexLocation = createIndexLocation(schema.getIndexLocation(),
|
||||
schema.getName());
|
||||
|
@ -166,7 +166,7 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
/*
|
||||
* if this fails the server must not startup!!
|
||||
*/
|
||||
protected File createIndexLocation(String path, String name) {
|
||||
protected File createIndexLocation(final String path,final String name) {
|
||||
if (path == null || name == null)
|
||||
throw new GdataIndexerException(
|
||||
"Path or Name of the index location is not set Path: "
|
||||
|
@ -205,7 +205,7 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
return file;
|
||||
}
|
||||
|
||||
protected boolean createIndexDirectory(File file) {
|
||||
protected boolean createIndexDirectory(final File file) {
|
||||
/*
|
||||
* use a lucene filename filter to figure out if there is an existing
|
||||
* index in the defined directory
|
||||
|
@ -218,10 +218,8 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
/**
|
||||
* @see org.apache.lucene.gdata.search.index.IndexEventListener#commitCallBack(java.lang.String)
|
||||
*/
|
||||
public synchronized void commitCallBack(String service) {
|
||||
if (this.destroyed.get())
|
||||
throw new IllegalStateException(
|
||||
"IndexController has been destroyed");
|
||||
public synchronized void commitCallBack(final String service) {
|
||||
checkDestroyed();
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("CommitCallback triggered - register new searcher for service: "+service);
|
||||
/*
|
||||
|
@ -245,7 +243,7 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
* create a new ReferenceCounter for the indexSearcher.
|
||||
* The reference is already incremented before returned
|
||||
*/
|
||||
private ReferenceCounter<IndexSearcher> getNewServiceSearcher(Directory dir)
|
||||
private ReferenceCounter<IndexSearcher> getNewServiceSearcher(final Directory dir)
|
||||
throws IOException {
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Create new ServiceSearcher");
|
||||
|
@ -272,34 +270,58 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
/**
|
||||
* @see org.apache.lucene.gdata.server.registry.EntryEventListener#fireUpdateEvent(org.apache.lucene.gdata.data.ServerBaseEntry)
|
||||
*/
|
||||
public void fireUpdateEvent(ServerBaseEntry entry) {
|
||||
public void fireUpdateEvent(final ServerBaseEntry entry) {
|
||||
createNewIndexerTask(entry, IndexAction.UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.server.registry.EntryEventListener#fireInsertEvent(org.apache.lucene.gdata.data.ServerBaseEntry)
|
||||
*/
|
||||
public void fireInsertEvent(ServerBaseEntry entry) {
|
||||
public void fireInsertEvent(final ServerBaseEntry entry) {
|
||||
createNewIndexerTask(entry, IndexAction.INSERT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.server.registry.EntryEventListener#fireDeleteEvent(org.apache.lucene.gdata.data.ServerBaseEntry)
|
||||
*/
|
||||
public void fireDeleteEvent(ServerBaseEntry entry) {
|
||||
public void fireDeleteEvent(final ServerBaseEntry entry) {
|
||||
createNewIndexerTask(entry, IndexAction.DELETE);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.server.registry.EntryEventListener#fireDeleteAllEntries(org.apache.lucene.gdata.data.ServerBaseFeed)
|
||||
*/
|
||||
public void fireDeleteAllEntries(final ServerBaseFeed feed) {
|
||||
createNewDeleteAllEntriesTask(feed);
|
||||
}
|
||||
|
||||
private void createNewDeleteAllEntriesTask(final ServerBaseFeed feed){
|
||||
checkDestroyed();
|
||||
checkInitialized();
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Deleting all entries for feed dispatch new IndexDocumentBuilder -- "+feed.getId());
|
||||
String serviceName = feed.getServiceConfig().getName();
|
||||
ServiceIndex bean = this.indexerMap.get(serviceName);
|
||||
if (bean == null)
|
||||
throw new RuntimeException("no indexer for service " + serviceName
|
||||
+ " registered");
|
||||
Lock lock = bean.getLock();
|
||||
lock.lock();
|
||||
try{
|
||||
IndexDocumentBuilder<IndexDocument> callable = new IndexFeedDeleteTask(feed.getId());
|
||||
sumbitTask(callable,bean.getIndexer());
|
||||
}finally{
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// TODO add test for this method!!
|
||||
private void createNewIndexerTask(ServerBaseEntry entry, IndexAction action) {
|
||||
if (this.destroyed.get())
|
||||
throw new IllegalStateException(
|
||||
"IndexController has been destroyed");
|
||||
if(!this.isInitialized.get())
|
||||
throw new IllegalStateException(
|
||||
"IndexController has not been initialized");
|
||||
|
||||
private void createNewIndexerTask(final ServerBaseEntry entry, final IndexAction action) {
|
||||
checkDestroyed();
|
||||
checkInitialized();
|
||||
String serviceName = entry.getServiceConfig().getName();
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("New Indexer Task submitted - Action: " + action
|
||||
|
@ -320,15 +342,7 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
boolean commitAfter = bean.incrementActionAndReset(schema.getCommitAfterDocuments());
|
||||
IndexDocumentBuilder<IndexDocument> callable = new IndexDocumentBuilderTask<IndexDocument>(
|
||||
entry, bean.getSchema(), action, commitAfter,bean.getOptimize(schema.getOptimizeAfterCommit()));
|
||||
Future<IndexDocument> task = this.taskExecutor.submit(callable);
|
||||
GDataIndexer indexer = bean.getIndexer();
|
||||
try {
|
||||
indexer.addIndexableDocumentTask(task);
|
||||
} catch (InterruptedException e) {
|
||||
throw new GdataIndexerException(
|
||||
"Can not accept any index tasks -- interrupted. ", e);
|
||||
|
||||
}
|
||||
sumbitTask(callable,bean.getIndexer());
|
||||
} finally {
|
||||
/*
|
||||
* make sure to unlock
|
||||
|
@ -338,15 +352,24 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
|
||||
}
|
||||
|
||||
|
||||
private void sumbitTask(final Callable<IndexDocument> callable, final GDataIndexer indexer){
|
||||
Future<IndexDocument> task = this.taskExecutor.submit(callable);
|
||||
try {
|
||||
indexer.addIndexableDocumentTask(task);
|
||||
} catch (InterruptedException e) {
|
||||
throw new GdataIndexerException(
|
||||
"Can not accept any index tasks -- interrupted. ", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.search.SearchComponent#getServiceSearcher(org.apache.lucene.gdata.server.registry.ProvidedService)
|
||||
*/
|
||||
public GDataSearcher<String> getServiceSearcher(ProvidedService service) {
|
||||
if (this.destroyed.get())
|
||||
throw new IllegalStateException(
|
||||
"IndexController has been destroyed");
|
||||
public GDataSearcher<String> getServiceSearcher(final ProvidedService service) {
|
||||
checkDestroyed();
|
||||
checkInitialized();
|
||||
|
||||
/*
|
||||
* get and increment. searcher will be decremented if GdataSearcher is
|
||||
* closed
|
||||
|
@ -367,10 +390,8 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
* @see org.apache.lucene.gdata.search.SearchComponent#destroy()
|
||||
*/
|
||||
public synchronized void destroy() {
|
||||
if (this.destroyed.get())
|
||||
throw new IllegalStateException(
|
||||
"IndexController has been destroyed");
|
||||
if (!this.isInitialized.get())
|
||||
checkDestroyed();
|
||||
if(!this.isInitialized.get())
|
||||
return;
|
||||
this.destroyed.set(true);
|
||||
this.isInitialized.set(false);
|
||||
|
@ -391,7 +412,19 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
this.indexerMap.clear();
|
||||
}
|
||||
|
||||
static class ServiceIndex {
|
||||
private void checkDestroyed(){
|
||||
if (this.destroyed.get())
|
||||
throw new IllegalStateException(
|
||||
"IndexController has been destroyed");
|
||||
}
|
||||
private void checkInitialized(){
|
||||
if(!this.isInitialized.get())
|
||||
throw new IllegalStateException(
|
||||
"IndexController has not been initialized");
|
||||
}
|
||||
|
||||
|
||||
final static class ServiceIndex {
|
||||
private AtomicInteger actionCount = new AtomicInteger(0);
|
||||
|
||||
private AtomicInteger commitCount = new AtomicInteger(0);
|
||||
|
@ -508,4 +541,6 @@ public class IndexController implements SearchComponent, IndexEventListener,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/**
|
||||
* 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.search.index;
|
||||
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.index.Term;
|
||||
|
||||
/**
|
||||
* This IndexDocumentBuilder deletes a entire feed form the index the builder is
|
||||
* passed to if the feed has any entries in the search index. Each created and
|
||||
* passed IndexFeedDeleteTask forces a commit.
|
||||
*
|
||||
* @author Simon Willnauer
|
||||
*
|
||||
*/
|
||||
public class IndexFeedDeleteTask implements IndexDocumentBuilder<IndexDocument> {
|
||||
private final String feedId;
|
||||
|
||||
IndexFeedDeleteTask(String feedId) {
|
||||
if (feedId == null)
|
||||
throw new IllegalArgumentException("feedId must not be null");
|
||||
this.feedId = feedId;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.search.index.IndexDocumentBuilder#call()
|
||||
*/
|
||||
public IndexDocument call() throws GdataIndexerException {
|
||||
return new FeedDeleteDocument(this.feedId);
|
||||
|
||||
}
|
||||
|
||||
private static class FeedDeleteDocument implements IndexDocument {
|
||||
private final Term deleteTerm;
|
||||
|
||||
FeedDeleteDocument(String feedId) {
|
||||
this.deleteTerm = new Term(FIELD_FEED_ID, feedId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.search.index.IndexDocument#isUpdate()
|
||||
*/
|
||||
public boolean isUpdate() {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.search.index.IndexDocument#isDelete()
|
||||
*/
|
||||
public boolean isDelete() {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.search.index.IndexDocument#isInsert()
|
||||
*/
|
||||
public boolean isInsert() {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.search.index.IndexDocument#getWriteable()
|
||||
*/
|
||||
public Document getWriteable() {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.search.index.IndexDocument#getDeletealbe()
|
||||
*/
|
||||
public Term getDeletealbe() {
|
||||
|
||||
return this.deleteTerm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.search.index.IndexDocument#commitAfter()
|
||||
*/
|
||||
public boolean commitAfter() {
|
||||
/*
|
||||
* force commit after delete a entire feed and its entries
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.search.index.IndexDocument#optimizeAfter()
|
||||
*/
|
||||
public boolean optimizeAfter() {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(obj == null)
|
||||
return false;
|
||||
if (obj instanceof IndexFeedDeleteTask) {
|
||||
IndexFeedDeleteTask other = (IndexFeedDeleteTask) obj;
|
||||
return this.feedId.equals(other.feedId);
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
return this.feedId.hashCode();
|
||||
}
|
||||
|
||||
}
|
|
@ -55,6 +55,7 @@ public class GDataSearchService extends GDataService {
|
|||
/**
|
||||
* @see org.apache.lucene.gdata.server.GDataService#getFeed(org.apache.lucene.gdata.server.GDataRequest, org.apache.lucene.gdata.server.GDataResponse)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BaseFeed getFeed(GDataRequest request, GDataResponse response) throws ServiceException {
|
||||
String translatedQuery = request.getTranslatedQuery();
|
||||
|
@ -85,8 +86,12 @@ public class GDataSearchService extends GDataService {
|
|||
requestFeed.setStartIndex(0);
|
||||
requestFeed.setItemsPerPage(0);
|
||||
requestFeed.setId(request.getFeedId());
|
||||
|
||||
BaseFeed feed = this.storage.getFeed(requestFeed);
|
||||
BaseFeed feed = null;
|
||||
try{
|
||||
feed = this.storage.getFeed(requestFeed);
|
||||
}catch (StorageException e) {
|
||||
throw new ServiceException("Search Failed -- can not get feed, feed not stored ",e,GDataResponse.NOT_FOUND);
|
||||
}
|
||||
for (String entryId : result) {
|
||||
ServerBaseEntry requestEntry = new ServerBaseEntry();
|
||||
requestEntry.setId(entryId);
|
||||
|
|
|
@ -61,7 +61,7 @@ public class GDataService implements Service {
|
|||
|
||||
private static final String XMLMIME = "application/atom+xml";
|
||||
|
||||
private final EntryEventMediator entryEventMediator;
|
||||
protected final EntryEventMediator entryEventMediator;
|
||||
static {
|
||||
generator = new Generator();
|
||||
generator.setName(generatorName);
|
||||
|
|
|
@ -22,94 +22,116 @@ import org.apache.lucene.gdata.data.ServerBaseFeed;
|
|||
import org.apache.lucene.gdata.server.GDataResponse;
|
||||
import org.apache.lucene.gdata.server.GDataService;
|
||||
import org.apache.lucene.gdata.server.ServiceException;
|
||||
import org.apache.lucene.gdata.server.registry.ProvidedService;
|
||||
import org.apache.lucene.gdata.storage.StorageException;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* default implementation of the {@link org.apache.lucene.gdata.server.administration.AdminService} interface.
|
||||
* default implementation of the
|
||||
* {@link org.apache.lucene.gdata.server.administration.AdminService} interface.
|
||||
*
|
||||
* @author Simon Willnauer
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class GDataAdminService extends GDataService implements AdminService {
|
||||
private static final Log LOG = LogFactory.getLog(GDataAdminService.class);
|
||||
|
||||
/**
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public GDataAdminService() throws ServiceException {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.server.administration.AdminService#createFeed(org.apache.lucene.gdata.data.ServerBaseFeed, org.apache.lucene.gdata.data.GDataAccount)
|
||||
* @see org.apache.lucene.gdata.server.administration.AdminService#createFeed(org.apache.lucene.gdata.data.ServerBaseFeed,
|
||||
* org.apache.lucene.gdata.data.GDataAccount)
|
||||
*/
|
||||
public void createFeed(final ServerBaseFeed feed,final GDataAccount account) throws ServiceException {
|
||||
if(feed == null)
|
||||
throw new ServiceException("Can not create feed -- feed is null", GDataResponse.BAD_REQUEST);
|
||||
if(account == null)
|
||||
throw new ServiceException("Can not create feed -- account is null", GDataResponse.UNAUTHORIZED);
|
||||
if(feed.getId() == null)
|
||||
throw new ServiceException("Feed ID is null can not create feed", GDataResponse.BAD_REQUEST);
|
||||
if(account.getName() == null)
|
||||
throw new ServiceException("Account name is null -- can't create feed", GDataResponse.UNAUTHORIZED);
|
||||
try {
|
||||
feed.setUpdated(getCurrentDateTime());
|
||||
feed.setAccount(account);
|
||||
this.storage.storeFeed(feed,account.getName());
|
||||
} catch (StorageException e) {
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Can not save feed -- "+e.getMessage(),e);
|
||||
throw new ServiceException("Can not save feed",e, GDataResponse.SERVER_ERROR);
|
||||
}
|
||||
|
||||
public void createFeed(final ServerBaseFeed feed, final GDataAccount account)
|
||||
throws ServiceException {
|
||||
if (feed == null)
|
||||
throw new ServiceException("Can not create feed -- feed is null",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
if (account == null)
|
||||
throw new ServiceException(
|
||||
"Can not create feed -- account is null",
|
||||
GDataResponse.UNAUTHORIZED);
|
||||
if (feed.getId() == null)
|
||||
throw new ServiceException("Feed ID is null can not create feed",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
if (account.getName() == null)
|
||||
throw new ServiceException(
|
||||
"Account name is null -- can't create feed",
|
||||
GDataResponse.UNAUTHORIZED);
|
||||
try {
|
||||
feed.setUpdated(getCurrentDateTime());
|
||||
feed.setAccount(account);
|
||||
this.storage.storeFeed(feed, account.getName());
|
||||
} catch (StorageException e) {
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Can not save feed -- " + e.getMessage(), e);
|
||||
throw new ServiceException("Can not save feed", e,
|
||||
GDataResponse.BAD_REQUEST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.server.administration.AdminService#updateFeed(org.apache.lucene.gdata.data.ServerBaseFeed, org.apache.lucene.gdata.data.GDataAccount)
|
||||
* @see org.apache.lucene.gdata.server.administration.AdminService#updateFeed(org.apache.lucene.gdata.data.ServerBaseFeed,
|
||||
* org.apache.lucene.gdata.data.GDataAccount)
|
||||
*/
|
||||
public void updateFeed(ServerBaseFeed feed, GDataAccount account) throws ServiceException {
|
||||
if(feed == null)
|
||||
throw new ServiceException("Can not update null feed", GDataResponse.BAD_REQUEST);
|
||||
if(account == null)
|
||||
throw new ServiceException("Can not update feed -- account is null", GDataResponse.UNAUTHORIZED);
|
||||
if(feed.getId() == null)
|
||||
throw new ServiceException("Feed ID is null can not update feed", GDataResponse.BAD_REQUEST);
|
||||
if(account.getName() == null)
|
||||
throw new ServiceException("Account name is null -- can't update feed", GDataResponse.UNAUTHORIZED);
|
||||
try {
|
||||
feed.setAccount(account);
|
||||
feed.setUpdated(getCurrentDateTime());
|
||||
this.storage.updateFeed(feed,account.getName());
|
||||
} catch (StorageException e) {
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Can not update feed -- "+e.getMessage(),e);
|
||||
throw new ServiceException("Can not update feed",e, GDataResponse.SERVER_ERROR);
|
||||
}
|
||||
public void updateFeed(ServerBaseFeed feed, GDataAccount account)
|
||||
throws ServiceException {
|
||||
if (feed == null)
|
||||
throw new ServiceException("Can not update null feed",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
if (account == null)
|
||||
throw new ServiceException(
|
||||
"Can not update feed -- account is null",
|
||||
GDataResponse.UNAUTHORIZED);
|
||||
if (feed.getId() == null)
|
||||
throw new ServiceException("Feed ID is null can not update feed",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
if (account.getName() == null)
|
||||
throw new ServiceException(
|
||||
"Account name is null -- can't update feed",
|
||||
GDataResponse.UNAUTHORIZED);
|
||||
try {
|
||||
feed.setAccount(account);
|
||||
feed.setUpdated(getCurrentDateTime());
|
||||
this.storage.updateFeed(feed, account.getName());
|
||||
} catch (StorageException e) {
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Can not update feed -- " + e.getMessage(), e);
|
||||
throw new ServiceException("Can not update feed", e,
|
||||
GDataResponse.BAD_REQUEST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.server.administration.AdminService#deleteFeed(org.apache.lucene.gdata.data.ServerBaseFeed)
|
||||
*/
|
||||
public void deleteFeed(ServerBaseFeed feed) throws ServiceException {
|
||||
if(feed == null)
|
||||
throw new ServiceException("Can not delete null feed", GDataResponse.BAD_REQUEST);
|
||||
if(feed.getId() == null)
|
||||
throw new ServiceException("Feed ID is null can not delete feed", GDataResponse.BAD_REQUEST);
|
||||
try {
|
||||
this.storage.deleteFeed(feed.getId());
|
||||
} catch (StorageException e) {
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Can not delete feed -- "+e.getMessage(),e);
|
||||
throw new ServiceException("Can not delete feed",e, GDataResponse.SERVER_ERROR);
|
||||
}
|
||||
if (feed == null)
|
||||
throw new ServiceException("Can not delete null feed",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
if (feed.getId() == null)
|
||||
throw new ServiceException("Feed ID is null can not delete feed",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
String serviceid = null;
|
||||
try {
|
||||
serviceid = this.storage.getServiceForFeed(feed.getId());
|
||||
this.storage.deleteFeed(feed.getId());
|
||||
} catch (StorageException e) {
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Can not delete feed -- " + e.getMessage(), e);
|
||||
throw new ServiceException("Can not delete feed", e,
|
||||
GDataResponse.BAD_REQUEST);
|
||||
}
|
||||
ProvidedService service = this.registry.getProvidedService(serviceid);
|
||||
feed.setServiceConfig(service);
|
||||
this.entryEventMediator.allEntriesDeleted(feed);
|
||||
|
||||
}
|
||||
|
||||
|
@ -117,14 +139,16 @@ public class GDataAdminService extends GDataService implements AdminService {
|
|||
* @see org.apache.lucene.gdata.server.administration.AdminService#createAccount(org.apache.lucene.gdata.data.GDataAccount)
|
||||
*/
|
||||
public void createAccount(GDataAccount account) throws ServiceException {
|
||||
if(account == null)
|
||||
throw new ServiceException("Can not save null account", GDataResponse.BAD_REQUEST);
|
||||
if (account == null)
|
||||
throw new ServiceException("Can not save null account",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
try {
|
||||
this.storage.storeAccount(account);
|
||||
} catch (StorageException e) {
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Can not save account -- "+e.getMessage(),e);
|
||||
throw new ServiceException("Can not save account",e, GDataResponse.SERVER_ERROR);
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Can not save account -- " + e.getMessage(), e);
|
||||
throw new ServiceException("Can not save account", e,
|
||||
GDataResponse.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,14 +156,16 @@ public class GDataAdminService extends GDataService implements AdminService {
|
|||
* @see org.apache.lucene.gdata.server.administration.AdminService#deleteAccount(org.apache.lucene.gdata.data.GDataAccount)
|
||||
*/
|
||||
public void deleteAccount(GDataAccount account) throws ServiceException {
|
||||
if(account == null)
|
||||
throw new ServiceException("Can not delete null account", GDataResponse.BAD_REQUEST);
|
||||
if (account == null)
|
||||
throw new ServiceException("Can not delete null account",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
try {
|
||||
this.storage.deleteAccount(account.getName());
|
||||
} catch (StorageException e) {
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Can not save account -- "+e.getMessage(),e);
|
||||
throw new ServiceException("Can not save account",e, GDataResponse.SERVER_ERROR);
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Can not save account -- " + e.getMessage(), e);
|
||||
throw new ServiceException("Can not save account", e,
|
||||
GDataResponse.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,52 +173,59 @@ public class GDataAdminService extends GDataService implements AdminService {
|
|||
* @see org.apache.lucene.gdata.server.administration.AdminService#updateAccount(org.apache.lucene.gdata.data.GDataAccount)
|
||||
*/
|
||||
public void updateAccount(GDataAccount account) throws ServiceException {
|
||||
if(account == null)
|
||||
throw new ServiceException("Can not update null account", GDataResponse.BAD_REQUEST);
|
||||
if (account == null)
|
||||
throw new ServiceException("Can not update null account",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
try {
|
||||
this.storage.updateAccount(account);
|
||||
} catch (StorageException e) {
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Can not save account -- "+e.getMessage(),e);
|
||||
throw new ServiceException("Can not save account",e, GDataResponse.SERVER_ERROR);
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Can not save account -- " + e.getMessage(), e);
|
||||
throw new ServiceException("Can not save account", e,
|
||||
GDataResponse.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.server.administration.AdminService#getAccount(java.lang.String)
|
||||
*/
|
||||
public GDataAccount getAccount(String accountName)throws ServiceException{
|
||||
if(accountName == null)
|
||||
throw new ServiceException("Can not get null account", GDataResponse.BAD_REQUEST);
|
||||
public GDataAccount getAccount(String accountName) throws ServiceException {
|
||||
if (accountName == null)
|
||||
throw new ServiceException("Can not get null account",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
try {
|
||||
return this.storage.getAccount(accountName);
|
||||
} catch (StorageException e) {
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Can not get account -- "+e.getMessage(),e);
|
||||
throw new ServiceException("Can not get account",e, GDataResponse.SERVER_ERROR);
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Can not get account -- " + e.getMessage(), e);
|
||||
throw new ServiceException("Can not get account", e,
|
||||
GDataResponse.BAD_REQUEST);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.gdata.server.administration.AdminService#getFeedOwningAccount(java.lang.String)
|
||||
*/
|
||||
public GDataAccount getFeedOwningAccount(String feedId) throws ServiceException {
|
||||
if(feedId == null)
|
||||
throw new ServiceException("Can not get account - feed id must not be null", GDataResponse.BAD_REQUEST);
|
||||
public GDataAccount getFeedOwningAccount(String feedId)
|
||||
throws ServiceException {
|
||||
if (feedId == null)
|
||||
throw new ServiceException(
|
||||
"Can not get account - feed id must not be null",
|
||||
GDataResponse.BAD_REQUEST);
|
||||
try {
|
||||
String accountName = this.storage.getAccountNameForFeedId(feedId);
|
||||
return this.storage.getAccount(accountName);
|
||||
|
||||
String accountName = this.storage.getAccountNameForFeedId(feedId);
|
||||
return this.storage.getAccount(accountName);
|
||||
|
||||
} catch (StorageException e) {
|
||||
if(LOG.isInfoEnabled())
|
||||
LOG.info("Can not get account for feed Id -- "+e.getMessage(),e);
|
||||
throw new ServiceException("Can not get account for the given feed id",e, GDataResponse.SERVER_ERROR);
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info(
|
||||
"Can not get account for feed Id -- " + e.getMessage(),
|
||||
e);
|
||||
throw new ServiceException(
|
||||
"Can not get account for the given feed id", e,
|
||||
GDataResponse.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.apache.lucene.gdata.server.registry;
|
||||
|
||||
import org.apache.lucene.gdata.data.ServerBaseEntry;
|
||||
import org.apache.lucene.gdata.data.ServerBaseFeed;
|
||||
|
||||
/**
|
||||
* The EntryEventListener interface should be implemented by any class needs to be informed about any changes on entries.
|
||||
|
@ -45,4 +46,10 @@ public interface EntryEventListener {
|
|||
* @param entry
|
||||
*/
|
||||
public abstract void fireDeleteEvent(ServerBaseEntry entry);
|
||||
|
||||
/**
|
||||
* will be invoked on every successful feed delete
|
||||
* @param feed - the feed containing the feed id to delete all entries for
|
||||
*/
|
||||
public abstract void fireDeleteAllEntries(ServerBaseFeed feed);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.gdata.data.ServerBaseEntry;
|
||||
import org.apache.lucene.gdata.data.ServerBaseFeed;
|
||||
|
||||
/**
|
||||
* This class will be informed about every successful entry event and
|
||||
|
@ -40,8 +41,8 @@ public abstract class EntryEventMediator {
|
|||
public abstract EntryEventMediator getEntryEventMediator();
|
||||
|
||||
/**
|
||||
* Registers a {@link EntryEventListener}. This listner will be fired if an
|
||||
* entry update, insert or delete occures
|
||||
* Registers a {@link EntryEventListener}. This listener will be fired if an
|
||||
* entry update, insert or delete occurs
|
||||
*
|
||||
* @param listener -
|
||||
* listener to register
|
||||
|
@ -71,6 +72,15 @@ public abstract class EntryEventMediator {
|
|||
listener.fireInsertEvent(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param feed - the feed to delete all entries for
|
||||
*/
|
||||
public void allEntriesDeleted(final ServerBaseFeed feed){
|
||||
for (EntryEventListener listener : this.entryEventListener) {
|
||||
listener.fireDeleteAllEntries(feed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entry -
|
||||
|
@ -82,6 +92,11 @@ public abstract class EntryEventMediator {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if the listener is already registered.
|
||||
* @param listner - the listener to check
|
||||
* @return <code>true</code> if and only if the given listener is already registered, otherwise <code>false</code>.
|
||||
*/
|
||||
public boolean isListenerRegistered(final EntryEventListener listner){
|
||||
return listner!=null&&this.entryEventListener.contains(listner);
|
||||
}
|
||||
|
|
|
@ -320,7 +320,6 @@ public class GDataServerRegistry extends EntryEventMediator{
|
|||
ScopeVisitor.class))
|
||||
this.registerScopeVisitor((ScopeVisitor) comp);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RegistryException("Can not register component -- "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
|
|
|
@ -166,6 +166,8 @@ public class DB4oController implements StorageController, ScopeVisitor {
|
|||
Db4o.configure().optimizeNativeQueries(false);
|
||||
if (this.runAsServer) {
|
||||
this.server = Db4o.openServer(this.filePath, this.port);
|
||||
if(this.server == null)
|
||||
throw new RuntimeException("Can't create server at confiugred destination -- "+this.filePath);
|
||||
this.server.grantAccess(this.user, this.password);
|
||||
} else {
|
||||
InvocationHandler handler = new ObjectServerDecorator(this.user,
|
||||
|
|
|
@ -46,6 +46,8 @@ import com.google.gdata.data.DateTime;
|
|||
public class DB4oStorage implements Storage {
|
||||
private static final Log LOG = LogFactory.getLog(DB4oStorage.class);
|
||||
|
||||
private static final int RENDER_ACTIVATION_DEPTH = 100;
|
||||
|
||||
private final ObjectContainer container;
|
||||
|
||||
private final StorageController controller;
|
||||
|
@ -309,6 +311,7 @@ public class DB4oStorage implements Storage {
|
|||
for (DB4oEntry entry : sublist) {
|
||||
persistentFeed.getEntries().add(clearDynamicElements(entry.getEntry()));
|
||||
}
|
||||
this.container.activate(persistentFeed,RENDER_ACTIVATION_DEPTH);
|
||||
return persistentFeed;
|
||||
|
||||
}
|
||||
|
@ -361,7 +364,9 @@ public class DB4oStorage implements Storage {
|
|||
throw new StorageException("can not retrieve entry -- id is null");
|
||||
if (LOG.isInfoEnabled())
|
||||
LOG.info("Retrieving entry for entryID: " + entry.getId());
|
||||
return clearDynamicElements(getInternalEntry(entry.getId()).getEntry());
|
||||
DB4oEntry retval = getInternalEntry(entry.getId());
|
||||
this.container.activate(retval.getEntry(),RENDER_ACTIVATION_DEPTH);
|
||||
return clearDynamicElements(retval.getEntry());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -108,5 +108,28 @@ public class IndexDocumentStub implements IndexDocument {
|
|||
public void setOptimizeAfter(boolean optimizeAfter) {
|
||||
this.optimizeAfter = optimizeAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
if(obj == null)
|
||||
return false;
|
||||
if(obj instanceof IndexDocumentStub){
|
||||
IndexDocumentStub other = (IndexDocumentStub)obj;
|
||||
return this.document.getField(IndexDocument.FIELD_ENTRY_ID).stringValue().equals(other.document.getField(IndexDocument.FIELD_ENTRY_ID).stringValue());
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return this.document.getField(IndexDocument.FIELD_ENTRY_ID).stringValue().hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public class TestGdataIndexer extends TestCase {
|
|||
|
||||
private static IndexSchema config;
|
||||
|
||||
private static String FIELD_ID = "id";
|
||||
private static String FIELD_ID = IndexDocument.FIELD_ENTRY_ID;
|
||||
|
||||
static {
|
||||
config = new IndexSchema();
|
||||
|
@ -244,7 +244,8 @@ public void testAddDocument() throws IOException {
|
|||
Hits h = s.search(new TermQuery(delTerm));
|
||||
assertEquals(1, h.length());
|
||||
s.close();
|
||||
|
||||
String testFieldName = "someTestFieldupdate";
|
||||
doc.add(new Field(testFieldName,"someText",Field.Store.YES,Field.Index.TOKENIZED));
|
||||
iDoc = new IndexDocumentStub(doc,delTerm,
|
||||
IndexAction.UPDATE);
|
||||
/*
|
||||
|
@ -261,6 +262,7 @@ public void testAddDocument() throws IOException {
|
|||
s = new IndexSearcher(this.dir);
|
||||
h = s.search(new TermQuery(delTerm));
|
||||
assertEquals(1, h.length());
|
||||
assertNotNull(h.doc(0).getField(testFieldName));
|
||||
s.close();
|
||||
|
||||
iDoc = new IndexDocumentStub(doc,delTerm,
|
||||
|
@ -313,7 +315,7 @@ public void testAddDocument() throws IOException {
|
|||
s.close();
|
||||
|
||||
/*
|
||||
* test insert / del without commit
|
||||
* test insert / del without optimize
|
||||
*/
|
||||
iDoc = new IndexDocumentStub(doc,delTerm,
|
||||
IndexAction.INSERT);
|
||||
|
@ -327,8 +329,31 @@ public void testAddDocument() throws IOException {
|
|||
assertEquals(0, h.length());
|
||||
s.close();
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* test insert / update / del without commit
|
||||
* test insert / del / update without optimize
|
||||
*/
|
||||
iDoc = new IndexDocumentStub(doc,delTerm,
|
||||
IndexAction.INSERT);
|
||||
this.indexer.addDocument(iDoc);
|
||||
iDoc = new IndexDocumentStub(doc,delTerm,
|
||||
IndexAction.DELETE);
|
||||
this.indexer.deleteDocument(iDoc);
|
||||
iDoc = new IndexDocumentStub(doc,delTerm,
|
||||
IndexAction.INSERT);
|
||||
this.indexer.addDocument(iDoc);
|
||||
this.indexer.commit(false);
|
||||
s = new IndexSearcher(this.dir);
|
||||
h = s.search(new TermQuery(delTerm));
|
||||
assertEquals(1, h.length());
|
||||
s.close();
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* test insert / update / del without optimize
|
||||
*/
|
||||
iDoc = new IndexDocumentStub(doc,delTerm,
|
||||
IndexAction.INSERT);
|
||||
|
@ -345,6 +370,8 @@ public void testAddDocument() throws IOException {
|
|||
assertEquals(0, h.length());
|
||||
s.close();
|
||||
|
||||
|
||||
|
||||
iDoc = new IndexDocumentStub(doc,delTerm,
|
||||
IndexAction.UPDATE);
|
||||
try{
|
||||
|
|
Loading…
Reference in New Issue