/**
* (C) Copyright 2013 Jabylon (http://www.jabylon.org) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
/**
*
*/
package org.jabylon.index.properties.impl;
import java.io.IOException;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Version;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.util.ObjectNotFoundException;
import org.jabylon.cdo.connector.RepositoryConnector;
import org.jabylon.common.resolver.URIResolver;
import org.jabylon.index.properties.IndexActivator;
import org.jabylon.index.properties.QueryService;
import org.jabylon.index.properties.SearchResult;
import org.jabylon.index.properties.jobs.impl.ReorgIndexJob;
import org.jabylon.properties.Project;
import org.jabylon.properties.ProjectLocale;
import org.jabylon.properties.ProjectVersion;
import org.jabylon.properties.PropertyFileDescriptor;
import org.jabylon.properties.ResourceFolder;
import org.jabylon.properties.Workspace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Johannes Utzig (jutzig.dev@googlemail.com)
*
*/
@Component
@Service
public class QueryServiceImpl implements QueryService {
private static final Logger logger = LoggerFactory.getLogger(QueryServiceImpl.class);
@Reference
private URIResolver uriResolver;
private volatile IndexSearcher searcher;
private volatile IndexReader reader;
@Reference
private RepositoryConnector RepositoryConnector;
@Deactivate
public void deactivate() {
try {
if(reader!=null)
reader.close();
if(searcher!=null)
searcher.close();
} catch (IOException e) {
logger.error("Failed to close the index",e);
}
}
public void bindUriResolver(URIResolver uriResolver) {
this.uriResolver = uriResolver;
}
public void unbindUriResolver(URIResolver uriResolver) {
this.uriResolver = null;
}
public void bindRepositoryConnector(RepositoryConnector repositoryConnector) {
RepositoryConnector = repositoryConnector;
}
public void unbindRepositoryConnector(RepositoryConnector repositoryConnector) {
RepositoryConnector = repositoryConnector;
}
/*
* (non-Javadoc)
*
* @see
* org.jabylon.index.properties.QueryService#search(java.lang.String)
*/
@Override
public SearchResult search(String search, String scopeURI) {
search = search.toLowerCase();
Query q = constructQuery(uriResolver.resolve(scopeURI), search);
return search(q,1000);
}
private Query constructQuery(Object scope, String search) {
BooleanQuery query = new BooleanQuery();
if (query instanceof Workspace) {
//nothing to do
} else if (scope instanceof Project) {
Project project = (Project) scope;
query.add(createProjectQuery(project),Occur.MUST);
} else if (scope instanceof ProjectVersion) {
ProjectVersion version = (ProjectVersion) scope;
query.add(createProjectQuery(version.getParent()), Occur.MUST);
query.add(createVersionQuery(version), Occur.MUST);
} else if (scope instanceof ProjectLocale) {
ProjectLocale locale = (ProjectLocale) scope;
query.add(createProjectQuery(locale.getParent().getParent()), Occur.MUST);
query.add(createVersionQuery(locale.getParent()), Occur.MUST);
query.add(createLocaleQuery(locale), Occur.MUST);
}
else if (scope instanceof ResourceFolder) {
ResourceFolder folder = (ResourceFolder) scope;
ProjectLocale locale = folder.getProjectLocale();
query.add(createProjectQuery(locale.getParent().getParent()), Occur.MUST);
query.add(createVersionQuery(locale.getParent()), Occur.MUST);
query.add(createLocaleQuery(locale), Occur.MUST);
query.add(new PrefixQuery(new Term(QueryService.FIELD_FULL_PATH,folder.fullPath().path())), Occur.MUST);
}
else if (scope instanceof PropertyFileDescriptor) {
PropertyFileDescriptor descriptor = (PropertyFileDescriptor) scope;
query.add(createProjectQuery(descriptor.getProjectLocale().getParent().getParent()), Occur.MUST);
query.add(createVersionQuery(descriptor.getProjectLocale().getParent()), Occur.MUST);
query.add(createLocaleQuery(descriptor.getProjectLocale()), Occur.MUST);
query.add(createDescriptorQuery(descriptor), Occur.MUST);
}
MultiFieldQueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_35, new String[] {FIELD_COMMENT, FIELD_KEY, FIELD_ANALYZED_KEY, FIELD_VALUE, FIELD_MASTER_VALUE, FIELD_MASTER_COMMENT}, new StandardAnalyzer(Version.LUCENE_35));
try {
Query userQuery = queryParser.parse(search);
query.add(userQuery, Occur.MUST);
} catch (ParseException e) {
throw new RuntimeException(e.getMessage(),e);
}
return query;
}
private TermQuery createLocaleQuery(ProjectLocale locale) {
return new TermQuery(new Term(FIELD_LOCALE, locale.getLocale().toString()));
}
private TermQuery createVersionQuery(ProjectVersion version) {
return new TermQuery(new Term(FIELD_VERSION, version.getName()));
}
private TermQuery createProjectQuery(Project project) {
TermQuery query = new TermQuery(new Term(FIELD_PROJECT, project.getName()));
return query;
}
private TermQuery createDescriptorQuery(PropertyFileDescriptor descriptor) {
return new TermQuery(new Term(FIELD_FULL_PATH, descriptor.fullPath().toString()));
}
@Override
public SearchResult search(Query query, int maxHits) {
Directory directory = IndexActivator.getDefault().getOrCreateDirectory();
try {
if(reader==null)
{
synchronized (this) {
//double checked locking
if(reader==null)
reader = IndexReader.open(directory);
}
}
else
{
IndexReader newReader = IndexReader.openIfChanged(reader,true);
if(newReader!=reader && newReader!=null)
{
reader.close();
reader = newReader;
if(searcher!=null)
searcher.close();
searcher = null;
}
}
if(searcher==null)
{
synchronized (this) {
//double checked locking
if(searcher==null)
searcher = new IndexSearcher(reader);
}
}
TopDocs result = searcher.search(query, maxHits);
return new SearchResult(searcher, result);
} catch (CorruptIndexException e) {
logger.error("Error during search "+query,e);
} catch (IOException e) {
logger.error("Error during search "+query,e);
}
return null;
}
@Override
public PropertyFileDescriptor getDescriptor(Document doc) {
String cdoID = doc.get(FIELD_CDO_ID);
CDOID id = CDOIDUtil.read(cdoID);
Object object = null;
try {
object = uriResolver.resolve(id);
} catch (ObjectNotFoundException e) {
return null;
}
if (object instanceof PropertyFileDescriptor) {
PropertyFileDescriptor descriptor = (PropertyFileDescriptor) object;
return descriptor;
}
return null;
}
@Override
public void rebuildIndex(IProgressMonitor monitor) throws CorruptIndexException, IOException {
ReorgIndexJob.indexWorkspace(RepositoryConnector, monitor);
}
}