/*
* Copyright 2004-2009 the original author or authors.
*
* 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.compass.core.accessor;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.compass.core.CompassException;
import org.compass.core.config.CompassConfigurable;
import org.compass.core.config.CompassEnvironment;
import org.compass.core.config.CompassSettings;
import org.compass.core.config.ConfigurationException;
import org.compass.core.mapping.MappingException;
import org.compass.core.util.ClassUtils;
/**
* A factory that creates a {@link PropertyAccessor}.
* <p/>
* Acts as a registry for property accessors, with two default implementations,
* {@link BasicPropertyAccessor} registered under "property", and {@link DirectPropertyAccessor}
* registered under "field".
* <p/>
* Allows for configuration of new property accessors, and register them under new/same names.
* Configuration is using the {@link org.compass.core.config.CompassEnvironment.PropertyAccessor}.
*
* @author kimchy
*/
public class PropertyAccessorFactory implements CompassConfigurable {
private static final Log log = LogFactory.getLog(PropertyAccessorFactory.class);
private Map<String, PropertyAccessor> propertyAccessorsRegistry = new HashMap<String, PropertyAccessor>();
/**
* Configures the property accessor registry, using the two default ones (field and property),
* and any external registered ones.
*/
public void configure(CompassSettings settings) throws CompassException {
PropertyAccessor propertyAccessor = new BasicPropertyAccessor();
if (propertyAccessor instanceof CompassConfigurable) {
((CompassConfigurable) propertyAccessor).configure(settings);
}
propertyAccessorsRegistry.put("property", propertyAccessor);
propertyAccessor = new DirectPropertyAccessor();
if (propertyAccessor instanceof CompassConfigurable) {
((CompassConfigurable) propertyAccessor).configure(settings);
}
propertyAccessorsRegistry.put("field", propertyAccessor);
Map<String, CompassSettings> paGroups = settings.getSettingGroups(CompassEnvironment.PropertyAccessor.PREFIX);
for (Map.Entry<String, CompassSettings> entry : paGroups.entrySet()) {
String paName = entry.getKey();
if (log.isDebugEnabled()) {
log.debug("Property Accessor [" + paName + "] building...");
}
CompassSettings paSettings = entry.getValue();
propertyAccessor = (PropertyAccessor) paSettings.getSettingAsInstance(CompassEnvironment.PropertyAccessor.TYPE);
if (propertyAccessor == null) {
throw new ConfigurationException("Must define type for property accessor [" + paName + "]");
}
if (propertyAccessor instanceof CompassConfigurable) {
((CompassConfigurable) propertyAccessor).configure(settings);
}
propertyAccessorsRegistry.put(paName, propertyAccessor);
}
}
/**
* Returns a new property accessor that match the given type. If the type is <code>null</code>
* will return the {@link BasicPropertyAccessor}. If the type can be found in the pre
* configured registry of property accessors, will return it. If nothing is found in
* the registry will try to instanciate it using the type as the class name.
*/
public PropertyAccessor getPropertyAccessor(String type, CompassSettings settings) throws MappingException {
if (type == null) {
PropertyAccessor propertyAccessor =
propertyAccessorsRegistry.get(CompassEnvironment.PropertyAccessor.DEFAULT_GROUP);
if (propertyAccessor != null) {
return propertyAccessor;
}
return propertyAccessorsRegistry.get("property");
}
PropertyAccessor propertyAccessor = propertyAccessorsRegistry.get(type);
if (propertyAccessor != null) {
return propertyAccessor;
}
Class accessorClass;
try {
accessorClass = ClassUtils.forName(type, settings.getClassLoader());
} catch (ClassNotFoundException cnfe) {
throw new MappingException("Could not find PropertyAccessor class [" + type + "] or bounded under name [" + type + "]", cnfe);
}
try {
propertyAccessor = (PropertyAccessor) accessorClass.newInstance();
if (propertyAccessor instanceof CompassConfigurable) {
((CompassConfigurable) propertyAccessor).configure(settings);
}
return propertyAccessor;
} catch (Exception e) {
throw new MappingException("Could not instantiate PropertyAccessor class [" + type + "]", e);
}
}
}