/*
* Copyright (c) 2009-2011 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.search.directory;
import java.util.ArrayList;
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.eurekastreams.commons.search.modelview.ModelView;
import org.eurekastreams.server.domain.DomainGroup;
import org.eurekastreams.server.domain.Person;
import org.eurekastreams.server.persistence.mappers.DomainMapper;
import org.eurekastreams.server.search.modelview.DomainGroupModelView;
import org.eurekastreams.server.search.modelview.PersonModelView;
import org.hibernate.transform.ResultTransformer;
/**
* Result transformer that transforms tuples of directory object (person, group) property names and values into
* ModelViews using cache/db mappers.
*/
public class CachedModelViewResultTransformer implements ResultTransformer
{
/**
* Logger.
*/
private Log log = LogFactory.getLog(CachedModelViewResultTransformer.class);
/**
* Serial version uid.
*/
private static final long serialVersionUID = -3492085599171644653L;
/**
* The property name that Hibernate uses to store the Hibernate Class of the entity.
*/
private static final String HIBERNATE_CLASS_PROPERTY_NAME = "_hibernate_class";
/**
* The property name of the id.
*/
private static final String HIBERNATE_ID_PROPERTY_NAME = "__HSearch_id";
/**
* The mapper to get the domain groups by ids.
*/
private DomainMapper<List<Long>, List<DomainGroupModelView>> getDomainGroupsByIdsMapper;
/**
* The mapper to get the people by Ids.
*/
private DomainMapper<List<Long>, List<PersonModelView>> getPeopleByIdsMapper;
/**
* Handle list transformation, receiving a list of Maps of property name to value.
*
* @param inCollection
* list of maps (property name to value)
* @return a list of ModelViews from the input list of maps (property name to value)
*/
@Override
@SuppressWarnings("unchecked")
public List transformList(final List inCollection)
{
log.trace("transformList.");
// keep track of the order - we need to return the ModelViews in the same order as the mapped entities
Map<String, Integer> positionList = new HashMap<String, Integer>();
// group the different types to consolidate the fetches
List<Long> groupIds = new ArrayList<Long>();
List<Long> peopleIds = new ArrayList<Long>();
int listPos = 0;
for (Object mapObj : inCollection)
{
Map<String, Object> map = (Map<String, Object>) mapObj;
Class< ? > clazz = (Class< ? >) map.get(HIBERNATE_CLASS_PROPERTY_NAME);
Long entityId = (Long) map.get(HIBERNATE_ID_PROPERTY_NAME);
if (clazz == DomainGroup.class)
{
groupIds.add(entityId);
positionList.put("G" + entityId, listPos);
listPos++;
}
else if (clazz == Person.class)
{
peopleIds.add(entityId);
positionList.put("P" + entityId, listPos);
listPos++;
}
}
ModelView[] results = new ModelView[inCollection.size()];
if (groupIds.size() > 0)
{
if (log.isDebugEnabled())
{
log.debug("Checking cache/db for Groups:" + groupIds.toString());
}
for (ModelView group : getDomainGroupsByIdsMapper.execute(groupIds))
{
results[positionList.get("G" + group.getEntityId())] = group;
}
}
if (peopleIds.size() > 0)
{
if (log.isDebugEnabled())
{
log.debug("Checking cache/db for People:" + peopleIds.toString());
}
for (ModelView person : getPeopleByIdsMapper.execute(peopleIds))
{
results[positionList.get("P" + person.getEntityId())] = person;
}
}
// NOTE: don't use Arrays.asList here - there's a GWT serialization bug that surfaces with the return value
ArrayList<ModelView> returnList = new ArrayList<ModelView>();
int arraySize = results.length;
for (int i = 0; i < arraySize; i++)
{
// discard nulls for any unknown entities or unhandled entity types
if (results[i] != null)
{
returnList.add(results[i]);
}
else
{
Map<String, Object> map = (Map<String, Object>) inCollection.get(i);
Class< ? > clazz = (Class< ? >) map.get(HIBERNATE_CLASS_PROPERTY_NAME);
Long entityId = (Long) map.get(HIBERNATE_ID_PROPERTY_NAME);
log.warn("Null entry in transformed list discarded. Index " + i + " contained an entry of type "
+ clazz.getName() + " with id " + entityId + ". Possible duplicate or unhandled entity type ");
}
}
return returnList;
}
/**
* Transform the input list of properties into a Map of property to value. transformList will group these and
* request the ModelViews in bulk.
*
* @param inTuple
* the field values
* @param inAliases
* the field names
* @return a list of Maps of field name to value.
*/
@Override
public Object transformTuple(final Object[] inTuple, final String[] inAliases)
{
return getMapFromTuplesAndAliases(inTuple, inAliases);
}
/**
* 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;
}
/**
* Set the GetDomainGroupsByIds mapper.
*
* @param inGetDomainGroupsByIdsMapper
* the getDomainGroupsByIdsMapper to set
*/
public void setGetDomainGroupsByIdsMapper(
final DomainMapper<List<Long>, List<DomainGroupModelView>> inGetDomainGroupsByIdsMapper)
{
this.getDomainGroupsByIdsMapper = inGetDomainGroupsByIdsMapper;
}
/**
* Set the DomainMapper<List<Long>, List<PersonModelView>>mapper.
*
* @param inGetPeopleByIdsMapper
* the getPeopleByIdsMapper to set
*/
public void setGetPeopleByIdsMapper(final DomainMapper<List<Long>, List<PersonModelView>> inGetPeopleByIdsMapper)
{
this.getPeopleByIdsMapper = inGetPeopleByIdsMapper;
}
}