/*
* Copyright (c) 2009-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.commons.search;
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.search.Explanation;
import org.eurekastreams.commons.reflection.ReflectiveInstantiator;
import org.eurekastreams.commons.search.modelview.ModelView;
import org.hibernate.transform.ResultTransformer;
/**
* Transformer to convert object/alias arrays to ModelViews.
*/
public class ProjectionToModelViewTransformer implements ResultTransformer
{
/**
* The property name that Hibernate uses to store the Hibernate Class of the entity.
*/
private static final String HIBERNATE_CLASS_PROPERTY_NAME = "_hibernate_class";
/**
* Logger.
*/
private Log log = LogFactory.getLog(ProjectionToModelViewTransformer.class);
/**
* UID.
*/
private static final long serialVersionUID = 4477869354898040873L;
/**
* ReflectiveInstantiator to instantiate ModelViews.
*/
private ReflectiveInstantiator reflectiveInstantiator;
/**
* The mapping of DomainEntity to ModelView.
*/
private Map<Class< ? >, Class< ? >> modelToViewClassMap;
/**
* Constructor taking the DomainEntity -> ModelView mapping map. When results are returned from Lucene of a
* DomainEntity type, the map contains the type of object to transform to.
*
* @param theModelToViewMap
* the mapping of DomainEntity to ModelView
* @param inReflectiveInstantiator
* the reflection instantiator to use to instantiate the ModelViews
*
*/
public ProjectionToModelViewTransformer(final Map<Class< ? >, Class< ? >> theModelToViewMap,
final ReflectiveInstantiator inReflectiveInstantiator)
{
modelToViewClassMap = theModelToViewMap;
reflectiveInstantiator = inReflectiveInstantiator;
}
/**
* Required override - used in case of special handling on lists such as removing duplicates, etc.
*
* @param list
* the list to transform
* @return the passed-in list
*/
@SuppressWarnings("unchecked")
@Override
public List transformList(final List list)
{
return list;
}
/**
* Transform the array of objects and column aliases to a ModelView using reflection and the ModelView's ability to
* import a property Map.
*
* @param tuple
* array of properties
* @param aliases
* array of Strings representing the property aliases in tuple
*
* @return a ModelView representation of the input property/alias arrays
*/
@Override
public Object transformTuple(final Object[] tuple, final String[] aliases)
{
Map<String, Object> properties = getMapFromTuplesAndAliases(tuple, aliases);
// find out what the entity class is
Class< ? > entityClass = (Class< ? >) properties.get(HIBERNATE_CLASS_PROPERTY_NAME);
// get the appropriate model view class from the lookup map
if (!modelToViewClassMap.containsKey(entityClass))
{
String message = "Unhandled entity class: " + entityClass.getName()
+ ", cannot determine which ModelView subclass to instantiate.";
log.error(message);
throw new IllegalArgumentException(message);
}
Class< ? > modelClass = modelToViewClassMap.get(entityClass);
// instantiate, load the properties, and return the ModelView
ModelView modelView = (ModelView) reflectiveInstantiator.instantiateObject(modelClass);
modelView.loadProperties(properties);
// If the ComplexExplanation is included, populate the ModelView with
// it. These properties can't be imported by the ModelView because that
// class needs to only deal with simple objects that GWT can support -
// ComplexExplanation not being one of them.
if (properties.containsKey("__HSearch_Explanation"))
{
Explanation explanation = (Explanation) properties.get("__HSearch_Explanation");
modelView.setSearchIndexExplanationString(explanation.toString());
}
return modelView;
}
/**
* Convert the input tuple and aliases to a key-value mapping.
*
* @param tuple
* values returned from Hibernate Search.
*
* @param aliases
* result keys returned from Hibernate Search.
*
* @return a key-value mapping of the Hibernate search tupple/aliases.
*/
protected Map<String, Object> getMapFromTuplesAndAliases(final Object[] tuple, final String[] aliases)
{
Map<String, Object> result = new HashMap<String, Object>(tuple.length);
for (int i = 0; i < tuple.length; i++)
{
result.put(aliases[i], tuple[i]);
}
return result;
}
}