/* * 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.config.process; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collection; import java.util.Iterator; import java.util.Map; import org.compass.annotations.SearchableDynamicName; import org.compass.annotations.SearchableDynamicValue; import org.compass.core.accessor.AccessorUtils; import org.compass.core.accessor.Getter; import org.compass.core.accessor.PropertyAccessor; import org.compass.core.accessor.PropertyAccessorFactory; import org.compass.core.config.CompassSettings; import org.compass.core.converter.ConverterLookup; import org.compass.core.converter.mapping.support.DynamicFormatDelegateConverter; import org.compass.core.engine.naming.PropertyNamingStrategy; import org.compass.core.mapping.AliasMapping; import org.compass.core.mapping.CompassMapping; import org.compass.core.mapping.Mapping; import org.compass.core.mapping.MappingException; import org.compass.core.mapping.osem.ClassDynamicPropertyMapping; import org.compass.core.mapping.osem.ClassMapping; import org.compass.core.util.AnnotationUtils; import org.compass.core.util.StringUtils; /** * @author kimchy */ public class DynamicPropertyProcessor implements MappingProcessor { public CompassMapping process(CompassMapping compassMapping, PropertyNamingStrategy namingStrategy, ConverterLookup converterLookup, CompassSettings settings) throws MappingException { // initalize the property accessor registry PropertyAccessorFactory propertyAccessorFactory = new PropertyAccessorFactory(); propertyAccessorFactory.configure(settings); for (AliasMapping aliasMapping : compassMapping.getMappings()) { if (aliasMapping instanceof ClassMapping) { ClassMapping classMapping = (ClassMapping) aliasMapping; for (Iterator<Mapping> it = classMapping.mappingsIt(); it.hasNext();) { Mapping m = it.next(); if (m instanceof ClassDynamicPropertyMapping) { processDynamicMapping((ClassDynamicPropertyMapping) m, settings, propertyAccessorFactory, converterLookup); } } } } return compassMapping; } private void processDynamicMapping(ClassDynamicPropertyMapping dynamicPropertyMapping, CompassSettings settings, PropertyAccessorFactory propertyAccessorFactory, ConverterLookup converterLookup) { PropertyAccessor pAccessor = propertyAccessorFactory.getPropertyAccessor(dynamicPropertyMapping.getAccessor(), settings); Class getterType = dynamicPropertyMapping.getGetter().getReturnType(); Class dynaType = getterType; if (getterType.isArray()) { dynaType = getterType.getComponentType(); dynamicPropertyMapping.setObjectType(ClassDynamicPropertyMapping.ObjectType.ARRAY); } else if (Collection.class.isAssignableFrom(getterType)) { dynamicPropertyMapping.setObjectType(ClassDynamicPropertyMapping.ObjectType.COLLECTION); dynaType = AccessorUtils.getCollectionParameter(dynamicPropertyMapping.getGetter()); } else if (Map.class.isAssignableFrom(getterType)) { dynamicPropertyMapping.setObjectType(ClassDynamicPropertyMapping.ObjectType.MAP); } else { dynamicPropertyMapping.setObjectType(ClassDynamicPropertyMapping.ObjectType.PLAIN); } if (dynamicPropertyMapping.getObjectType() == ClassDynamicPropertyMapping.ObjectType.MAP) { Class keyType = AccessorUtils.getMapKeyParameter(dynamicPropertyMapping.getGetter()); Class valueType = AccessorUtils.getMapValueParameter(dynamicPropertyMapping.getGetter()); if (dynamicPropertyMapping.getNameProperty() != null && keyType == null) { throw new MappingException("Dynamic property mapping [" + dynamicPropertyMapping.getName() + "] defined in alias [" + dynamicPropertyMapping.getDefinedInAlias() + "] defines name property but Map is not generified to find it"); } if (dynamicPropertyMapping.getValueProperty() != null && valueType == null) { throw new MappingException("Dynamic property mapping [" + dynamicPropertyMapping.getName() + "] defined in alias [" + dynamicPropertyMapping.getDefinedInAlias() + "] defines value property but Map is not generified to find it"); } if (keyType != null) { if (dynamicPropertyMapping.getNameProperty() != null) { dynamicPropertyMapping.setNameGetter(pAccessor.getGetter(keyType, dynamicPropertyMapping.getNameProperty())); } else { processSearchableDynamicName(dynamicPropertyMapping, settings, propertyAccessorFactory, keyType, converterLookup); } } if (valueType != null) { if (dynamicPropertyMapping.getValueProperty() != null) { dynamicPropertyMapping.setValueGetter(pAccessor.getGetter(valueType, dynamicPropertyMapping.getValueProperty())); } else { processSearchableDynamicValue(dynamicPropertyMapping, settings, propertyAccessorFactory, valueType, converterLookup); } } if (dynamicPropertyMapping.getValueGetter() != null) { if (AccessorUtils.isMapValueParameterArray(dynamicPropertyMapping.getGetter())) { dynamicPropertyMapping.setMapValueType(ClassDynamicPropertyMapping.ValueType.ARRAY); } else if (AccessorUtils.isMapValueParameterCollection(dynamicPropertyMapping.getGetter())) { dynamicPropertyMapping.setMapValueType(ClassDynamicPropertyMapping.ValueType.COLLECTION); } else { dynamicPropertyMapping.setMapValueType(ClassDynamicPropertyMapping.ValueType.PLAIN); } processValueType(dynamicPropertyMapping, dynamicPropertyMapping.getValueGetter().getReturnType()); } else { // can't be a complex array within an object, since no getter dynamicPropertyMapping.setMapValueType(ClassDynamicPropertyMapping.ValueType.PLAIN); if (AccessorUtils.isMapValueParameterArray(dynamicPropertyMapping.getGetter())) { dynamicPropertyMapping.setValueType(ClassDynamicPropertyMapping.ValueType.ARRAY); } else if (AccessorUtils.isMapValueParameterCollection(dynamicPropertyMapping.getGetter())) { dynamicPropertyMapping.setValueType(ClassDynamicPropertyMapping.ValueType.COLLECTION); } else if (valueType != null) { processValueType(dynamicPropertyMapping, valueType); } } } else { if (dynamicPropertyMapping.getNameProperty() != null) { dynamicPropertyMapping.setNameGetter(pAccessor.getGetter(dynaType, dynamicPropertyMapping.getNameProperty())); } else if (dynaType != null) { processSearchableDynamicName(dynamicPropertyMapping, settings, propertyAccessorFactory, dynaType, converterLookup); } if (dynamicPropertyMapping.getValueProperty() != null) { dynamicPropertyMapping.setValueGetter(pAccessor.getGetter(dynaType, dynamicPropertyMapping.getValueProperty())); } else { processSearchableDynamicValue(dynamicPropertyMapping, settings, propertyAccessorFactory, dynaType, converterLookup); } // ok, we set the value getter, we can now derive the value type Getter valueGetter = dynamicPropertyMapping.getValueGetter(); processValueType(dynamicPropertyMapping, valueGetter.getReturnType()); } if (dynamicPropertyMapping.getNameFormat() != null) { dynamicPropertyMapping.setNameConverter(new DynamicFormatDelegateConverter(dynamicPropertyMapping.getNameFormat(), converterLookup)); } if (dynamicPropertyMapping.getValueFormat() != null) { dynamicPropertyMapping.setValueConverter(new DynamicFormatDelegateConverter(dynamicPropertyMapping.getValueFormat(), converterLookup)); } } private void processValueType(ClassDynamicPropertyMapping dynamicPropertyMapping, Class valueType) { if (valueType.isArray()) { dynamicPropertyMapping.setValueType(ClassDynamicPropertyMapping.ValueType.ARRAY); } else if (Collection.class.isAssignableFrom(valueType)) { dynamicPropertyMapping.setValueType(ClassDynamicPropertyMapping.ValueType.COLLECTION); } else { dynamicPropertyMapping.setValueType(ClassDynamicPropertyMapping.ValueType.PLAIN); } } private void processSearchableDynamicValue(ClassDynamicPropertyMapping dynamicPropertyMapping, CompassSettings settings, PropertyAccessorFactory propertyAccessorFactory, Class dynaType, ConverterLookup converterLookup) { SearchableDynamicValue dynamicValue = null; Method method = AnnotationUtils.findAnnotatedMethod(SearchableDynamicValue.class, dynaType); if (method != null) { dynamicValue = method.getAnnotation(SearchableDynamicValue.class); dynamicPropertyMapping.setValueGetter(propertyAccessorFactory.getPropertyAccessor("property", settings).getGetter(method.getDeclaringClass(), method.getName())); } else { Field field = AnnotationUtils.findAnnotatedField(SearchableDynamicValue.class, dynaType); if (field != null) { dynamicValue = field.getAnnotation(SearchableDynamicValue.class); dynamicPropertyMapping.setValueGetter(propertyAccessorFactory.getPropertyAccessor("field", settings).getGetter(field.getDeclaringClass(), field.getName())); } } if (dynamicValue != null) { if (dynamicPropertyMapping.getValueConverterName() == null && StringUtils.hasText(dynamicValue.converter())) { dynamicPropertyMapping.setValueConverterName(dynamicValue.converter()); } if (dynamicPropertyMapping.getValueFormat() == null && StringUtils.hasText(dynamicValue.format())) { dynamicPropertyMapping.setValueFormat(dynamicValue.format()); } if (dynamicPropertyMapping.getResourcePropertyMapping().getNullValue().length() == 0 && StringUtils.hasText(dynamicValue.nullValue())) { dynamicPropertyMapping.getResourcePropertyMapping().setNullValue(dynamicValue.nullValue()); } } } private void processSearchableDynamicName(ClassDynamicPropertyMapping dynamicPropertyMapping, CompassSettings settings, PropertyAccessorFactory propertyAccessorFactory, Class dynaType, ConverterLookup converterLookup) { SearchableDynamicName dynamicName = null; Method method = AnnotationUtils.findAnnotatedMethod(SearchableDynamicName.class, dynaType); if (method != null) { dynamicName = method.getAnnotation(SearchableDynamicName.class); dynamicPropertyMapping.setNameGetter(propertyAccessorFactory.getPropertyAccessor("property", settings).getGetter(method.getDeclaringClass(), method.getName())); } else { Field field = AnnotationUtils.findAnnotatedField(SearchableDynamicName.class, dynaType); if (field != null) { dynamicName = field.getAnnotation(SearchableDynamicName.class); dynamicPropertyMapping.setNameGetter(propertyAccessorFactory.getPropertyAccessor("field", settings).getGetter(field.getDeclaringClass(), field.getName())); } } if (dynamicName != null) { if (dynamicPropertyMapping.getNamePrefix() == null && StringUtils.hasText(dynamicName.prefix())) { dynamicPropertyMapping.setNamePrefix(dynamicName.prefix()); } if (dynamicPropertyMapping.getNameConverterName() == null && StringUtils.hasText(dynamicName.converter())) { dynamicPropertyMapping.setNameConverterName(dynamicName.converter()); } if (dynamicPropertyMapping.getNameFormat() == null && StringUtils.hasText(dynamicName.format())) { dynamicPropertyMapping.setNameFormat(dynamicName.format()); } } } }