/**
* Licensed to Neo Technology under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Neo Technology licenses this file to you 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.neo4j.neoclipse.search;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.search.ui.ISearchQuery;
import org.eclipse.search.ui.ISearchResult;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.graphdb.index.IndexManager;
import org.neo4j.neoclipse.Activator;
import org.neo4j.neoclipse.graphdb.GraphCallable;
import org.neo4j.neoclipse.graphdb.GraphDbServiceManager;
import org.neo4j.neoclipse.view.ErrorMessage;
import org.neo4j.neoclipse.view.UiHelper;
/**
* This class represents a search query for Neo objects.
*
* @author Peter Hänsgen
* @author Anders Nawroth
*/
public class NeoSearchQuery implements ISearchQuery
{
/**
* The found matches.
*/
private final NeoSearchResult result;
private final IndexSearch search;
/**
* The constructor.
*/
public NeoSearchQuery( final IndexSearch search )
{
this.search = search;
// initialize an empty result
result = new NeoSearchResult( this );
}
/**
* Returns a String form of the search expression.
*/
public String getExpression()
{
return search.getValueOrQuery();
}
/**
* Returns true.
*/
@Override
public boolean canRerun()
{
return true;
}
/**
* Returns true.
*/
@Override
public boolean canRunInBackground()
{
return true;
}
/**
* Returns a label.
*/
@Override
public String getLabel()
{
return "Neo4j Search";
}
/**
* Returns the search result.
*/
@Override
public ISearchResult getSearchResult()
{
return result;
}
/**
* Executes the search.
*/
@Override
public IStatus run( final IProgressMonitor monitor ) throws OperationCanceledException
{
final GraphDbServiceManager gsm = Activator.getDefault().getGraphDbServiceManager();
if ( !gsm.isRunning() )
{
return new Status( IStatus.ERROR, Activator.PLUGIN_ID, "There is no active Neo4j service." );
}
try
{
gsm.submitTask( new GraphCallable<Boolean>()
{
@Override
public Boolean call( final GraphDatabaseService graphDb )
{
final Iterable<PropertyContainer> matches = getMatchingNodesFromIndices( monitor, graphDb );
UiHelper.asyncExec( new Runnable()
{
@Override
public void run()
{
result.setMatches( matches );
}
} );
return true;
}
}, "run search" ).get();
if ( monitor.isCanceled() )
{
return new Status( IStatus.CANCEL, Activator.PLUGIN_ID, "Cancelled." );
}
else
{
return new Status( IStatus.OK, Activator.PLUGIN_ID, "OK" );
}
}
catch ( Exception e )
{
String message = ErrorMessage.getErrorMessage( e );
if ( message.indexOf( "org.apache.lucene.index.CorruptIndexException: Unknown format version" ) != -1 )
{
ErrorMessage.showDialog( "Search error", "The index can't be read as the Neo4j database "
+ "isn't compatible with this version of Neoclipse." );
}
else
{
ErrorMessage.showDialog( "Search error", e );
}
}
return null;
}
private Iterable<PropertyContainer> getMatchingNodesFromIndices( final IProgressMonitor monitor,
final GraphDatabaseService graphDb )
{
List<PropertyContainer> matches = new LinkedList<PropertyContainer>();
IndexManager indexManager = graphDb.index();
for ( String indexName : search.getNodeIndexNames() )
{
if ( !indexManager.existsForNodes( indexName ) )
{
continue;
}
Index<Node> nodeIndex = indexManager.forNodes( indexName );
Iterable<Node> hits;
switch ( search.getMode() )
{
case EXACT_MATCH:
hits = nodeIndex.get( search.getKey(), search.getValueOrQuery() );
break;
case QUERY:
String key = search.getKey();
hits = nodeIndex.query( key, search.getValueOrQuery() );
break;
default:
hits = null;
}
for ( Node hit : hits )
{
matches.add( hit );
}
}
for ( String indexName : search.getRelationshipIndexNames() )
{
if ( !indexManager.existsForRelationships( indexName ) )
{
continue;
}
Index<Relationship> relIndex = indexManager.forRelationships( indexName );
IndexHits<Relationship> hits;
switch ( search.getMode() )
{
case EXACT_MATCH:
hits = relIndex.get( search.getKey(), search.getValueOrQuery() );
break;
case QUERY:
hits = relIndex.query( search.getKey(), search.getValueOrQuery() );
break;
default:
hits = null;
}
for ( Relationship hit : hits )
{
matches.add( hit );
}
}
return matches;
}
}