/*
* Copyright (c) 2010 Lockheed Martin Corporation
*
* 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.eurekastreams.server.action.execution.directory;
import java.util.List;
import org.apache.commons.logging.Log;
import org.eurekastreams.commons.actions.ExecutionStrategy;
import org.eurekastreams.commons.actions.context.service.ServiceActionContext;
import org.eurekastreams.commons.exceptions.ExecutionException;
import org.eurekastreams.commons.logging.LogFactory;
import org.eurekastreams.commons.search.ProjectionSearchRequestBuilder;
import org.eurekastreams.commons.search.modelview.ModelView;
import org.eurekastreams.server.action.request.directory.GetDirectorySearchResultsRequest;
import org.eurekastreams.server.domain.PagedSet;
import org.eurekastreams.server.service.actions.strategies.directory.DirectorySearchLuceneQueryBuilder;
import org.eurekastreams.server.service.actions.strategies.directory.TransientPropertyPopulator;
import org.hibernate.search.jpa.FullTextQuery;
/**
* Action to search across People, DomainGroups, and Organizations.
*/
public class GetDirectorySearchResultsExecution implements ExecutionStrategy<ServiceActionContext>
{
/**
* Instance of the logger.
*/
private Log log = LogFactory.make();
/**
* The search request builder.
*/
private ProjectionSearchRequestBuilder searchRequestBuilder;
/**
* The transient property populator for search results.
*/
private TransientPropertyPopulator transientPropertyPopulator;
/**
* Strategy to build a Lucene query string for searching the directory.
*/
private DirectorySearchLuceneQueryBuilder queryBuilder;
/**
* Constructor.
*
* @param inQueryBuilder
* the strategy to build a Lucene query string for searching the directory
* @param inSearchRequestBuilder
* the search request builder
* @param inTransientPropertyPopulator
* the strategy to populate additional properties on the search results as they return
*/
public GetDirectorySearchResultsExecution(final DirectorySearchLuceneQueryBuilder inQueryBuilder,
final ProjectionSearchRequestBuilder inSearchRequestBuilder,
final TransientPropertyPopulator inTransientPropertyPopulator)
{
queryBuilder = inQueryBuilder;
searchRequestBuilder = inSearchRequestBuilder;
transientPropertyPopulator = inTransientPropertyPopulator;
}
@SuppressWarnings("unchecked")
@Override
public PagedSet<ModelView> execute(final ServiceActionContext inActionContext) throws ExecutionException
{
long startTime = System.currentTimeMillis();
GetDirectorySearchResultsRequest currentRequest = (GetDirectorySearchResultsRequest) inActionContext
.getParams();
// todo: do more than escape here - remove the advanced chars
String searchText = searchRequestBuilder.escapeAllButWildcardCharacters(currentRequest.getSearchTerm());
// get the current user's Person id.
long userPersonId = inActionContext.getPrincipal().getId();
// build and parse the query, set its paging
String nativeLuceneQuery = queryBuilder.buildNativeQuery(searchText, currentRequest.getWeightedField(),
currentRequest.getOrgShortName(), userPersonId);
FullTextQuery query = searchRequestBuilder.buildQueryFromNativeSearchString(nativeLuceneQuery);
searchRequestBuilder.setPaging(query, currentRequest.getStartIndex(), currentRequest.getEndIndex());
// get the results before query.getResultSize() is called for performance (it avoids a second search)
List<ModelView> results = query.getResultList();
// populate any transient properties
transientPropertyPopulator.populateTransientProperties(results, userPersonId, searchText);
// get the paged set, getting the total now that we've already made the query
PagedSet<ModelView> pagedResults = new PagedSet<ModelView>(currentRequest.getStartIndex(), currentRequest
.getEndIndex(), query.getResultSize(), results);
// set the elapsed time
String elapsedTime = formatElapasedTime(startTime, System.currentTimeMillis());
pagedResults.setElapsedTime(elapsedTime);
log.info("Searched '" + searchText + "' in " + elapsedTime);
return pagedResults;
}
/**
* Determine and format the elapsed time for a server request.
*
* @param startTime
* the starting milliseconds
* @param endTime
* the ending milliseconds
* @return a formatted elapsed time in the format "0.23 seconds"
*/
protected String formatElapasedTime(final long startTime, final long endTime)
{
final int millisecondsPerSecond = 1000;
String elapsedTime = String.format("%1$.2f seconds", (endTime - startTime) / (float) millisecondsPerSecond);
if (elapsedTime == "0.00 seconds")
{
elapsedTime = "0.01 seconds";
}
return elapsedTime;
}
}