/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat, Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.search.impl;
import java.lang.reflect.Method;
import org.hibernate.search.SearchException;
import org.hibernate.search.Environment;
import org.hibernate.search.cfg.SearchMapping;
import org.hibernate.search.cfg.spi.SearchConfiguration;
import org.hibernate.search.annotations.Factory;
import org.hibernate.search.util.impl.ClassLoaderHelper;
import org.hibernate.search.util.impl.ReflectionHelper;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.util.logging.impl.LoggerFactory;
/**
* package class extracting the SearchMappingFactory if needed
*/
public class SearchMappingBuilder {
private static final Log LOG = LoggerFactory.make();
private SearchMappingBuilder() {
}
/**
* This factory method takes a SearchConfiguration object
* and returns a SearchMapping object which defines
* the programmatic model for indexing entities and fields.
*
* Throws SearchException:
* 1) No @Factory found
* 2) Multiple @Factory found
* 3) hibernate.search.model_mapping defines a class that cannot be found
* 4) Cannot invoke the @Factory method to get new instance of SearchMapping
*
* @param cfg the search configuration
* @return SearchMapping
*/
public static SearchMapping getSearchMapping(SearchConfiguration cfg) {
//try SearchConfiguration object first and then properties
Object modelMappingProperty = cfg.getProgrammaticMapping();
if ( modelMappingProperty == null) {
modelMappingProperty = cfg.getProperties().get( Environment.MODEL_MAPPING );
}
if ( modelMappingProperty == null) {
return null;
}
SearchMapping mapping = null;
Object programmaticConfig = modelMappingProperty;
if (programmaticConfig instanceof SearchMapping) {
mapping = (SearchMapping) programmaticConfig;
return mapping;
}
Class<?> clazz = getProgrammaticMappingClass(programmaticConfig);
Method[] methods = clazz.getDeclaredMethods();
int count = 0;
for (Method method : methods) {
if (method.isAnnotationPresent(Factory.class)) {
count++;
ReflectionHelper.setAccessible( method );
mapping = getNewInstanceOfSearchMapping(clazz, method);
}
}
validateMappingFactoryDefinition(count, clazz);
return mapping;
}
private static SearchMapping getNewInstanceOfSearchMapping(Class<?> clazz, Method method) {
SearchMapping mapping = null;
try {
LOG.debugf("invoking factory method [ %s.%s ] to get search mapping instance", clazz.getName(), method.getName());
Object instance = clazz.newInstance();
mapping = (SearchMapping) method.invoke(instance);
} catch (Exception e) {
throw new SearchException("Unable to call the factory method: " + clazz.getName() + "." + method.getName(), e);
}
return mapping;
}
private static void validateMappingFactoryDefinition(int count, Class<?> factory) {
if (count == 0) {
throw new SearchException("No @Factory method defined for building programmatic api on " + factory);
}
if (count > 1) {
throw new SearchException("Multiple @Factory methods defined. Only one factory method required. " + factory);
}
}
private static Class<?> getProgrammaticMappingClass(Object programmaticConfig) {
Class<?> clazz = null;
if (programmaticConfig instanceof String) {
final String className = ( String ) programmaticConfig;
try {
clazz = ClassLoaderHelper.classForName( className, SearchMappingBuilder.class.getClassLoader() );
} catch (ClassNotFoundException e) {
throw new SearchException("Unable to find " + Environment.MODEL_MAPPING + "=" + className, e);
}
} else if (programmaticConfig instanceof Class){
clazz = (Class<?>) programmaticConfig;
}
else {
throw new SearchException(Environment.MODEL_MAPPING + " is of an unknown type: " + programmaticConfig.getClass() );
}
if (clazz == null) {
throw new SearchException("No programmatic factory defined");
}
return clazz;
}
}