/*
* #%L
* BroadleafCommerce Open Admin Platform
* %%
* Copyright (C) 2009 - 2013 Broadleaf Commerce
* %%
* 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.
* #L%
*/
package org.broadleafcommerce.openadmin.server.dao.provider.metadata;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.common.presentation.AdminPresentationMap;
import org.broadleafcommerce.common.presentation.AdminPresentationMapField;
import org.broadleafcommerce.common.presentation.AdminPresentationMapFields;
import org.broadleafcommerce.common.presentation.client.CustomFieldSearchableTypes;
import org.broadleafcommerce.common.presentation.client.SupportedFieldType;
import org.broadleafcommerce.openadmin.dto.BasicFieldMetadata;
import org.broadleafcommerce.openadmin.dto.FieldMetadata;
import org.broadleafcommerce.openadmin.dto.override.FieldMetadataOverride;
import org.broadleafcommerce.openadmin.server.dao.FieldInfo;
import org.broadleafcommerce.openadmin.server.dao.provider.metadata.request.AddMetadataFromFieldTypeRequest;
import org.broadleafcommerce.openadmin.server.dao.provider.metadata.request.AddMetadataRequest;
import org.broadleafcommerce.openadmin.server.dao.provider.metadata.request.OverrideViaAnnotationRequest;
import org.broadleafcommerce.openadmin.server.dao.provider.metadata.request.OverrideViaXmlRequest;
import org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager;
import org.broadleafcommerce.openadmin.server.service.type.FieldProviderResponse;
import org.hibernate.internal.TypeLocatorImpl;
import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.lang.reflect.ParameterizedType;
import java.util.Map;
/**
* @author Jeff Fischer
*/
@Component("blMapFieldsFieldMetadataProvider")
@Scope("prototype")
public class MapFieldsFieldMetadataProvider extends DefaultFieldMetadataProvider {
private static final Log LOG = LogFactory.getLog(MapFieldsFieldMetadataProvider.class);
protected boolean canHandleFieldForConfiguredMetadata(AddMetadataRequest addMetadataRequest, Map<String, FieldMetadata> metadata) {
AdminPresentationMapFields annot = addMetadataRequest.getRequestedField().getAnnotation(AdminPresentationMapFields.class);
return annot != null;
}
protected boolean canHandleFieldForTypeMetadata(AddMetadataFromFieldTypeRequest addMetadataFromFieldTypeRequest, Map<String, FieldMetadata> metadata) {
AdminPresentationMapFields annot = addMetadataFromFieldTypeRequest.getRequestedField().getAnnotation(AdminPresentationMapFields.class);
return annot != null;
}
@Override
public FieldProviderResponse addMetadata(AddMetadataRequest addMetadataRequest, Map<String, FieldMetadata> metadata) {
if (!canHandleFieldForConfiguredMetadata(addMetadataRequest, metadata)) {
return FieldProviderResponse.NOT_HANDLED;
}
AdminPresentationMapFields annot = addMetadataRequest.getRequestedField().getAnnotation(AdminPresentationMapFields.class);
for (AdminPresentationMapField mapField : annot.mapDisplayFields()) {
if (mapField.fieldPresentation().fieldType() == SupportedFieldType.UNKNOWN) {
throw new IllegalArgumentException("fieldType property on AdminPresentation must be set for AdminPresentationMapField");
}
FieldMetadataOverride override = constructBasicMetadataOverride(mapField.fieldPresentation(), null, null);
override.setFriendlyName(mapField.fieldPresentation().friendlyName());
FieldInfo myInfo = new FieldInfo();
myInfo.setName(addMetadataRequest.getRequestedField().getName() + FieldManager.MAPFIELDSEPARATOR + mapField.fieldName());
buildBasicMetadata(addMetadataRequest.getParentClass(), addMetadataRequest.getTargetClass(), metadata, myInfo, override, addMetadataRequest.getDynamicEntityDao());
setClassOwnership(addMetadataRequest.getParentClass(), addMetadataRequest.getTargetClass(), metadata, myInfo);
BasicFieldMetadata basicFieldMetadata = (BasicFieldMetadata) metadata.get(myInfo.getName());
if (!mapField.targetClass().equals(Void.class)) {
if (mapField.targetClass().isInterface()) {
throw new IllegalArgumentException("targetClass on @AdminPresentationMapField must be a concrete class");
}
basicFieldMetadata.setMapFieldValueClass(mapField.targetClass().getName());
}
if (mapField.searchable() != CustomFieldSearchableTypes.NOT_SPECIFIED) {
basicFieldMetadata.setSearchable(mapField.searchable() == CustomFieldSearchableTypes.YES);
}
if (!StringUtils.isEmpty(mapField.manyToField())) {
basicFieldMetadata.setManyToField(mapField.manyToField());
}
AdminPresentationMap annotMap = addMetadataRequest.getRequestedField().getAnnotation(AdminPresentationMap.class);
if (annotMap != null && !StringUtils.isEmpty(annotMap.toOneTargetProperty())) {
basicFieldMetadata.setToOneTargetProperty(annotMap.toOneTargetProperty());
} else if (!StringUtils.isEmpty(annot.toOneTargetProperty())) {
basicFieldMetadata.setToOneTargetProperty(annot.toOneTargetProperty());
}
if (annotMap != null && !StringUtils.isEmpty(annotMap.toOneParentProperty())) {
basicFieldMetadata.setToOneParentProperty(annotMap.toOneParentProperty());
} else if (!StringUtils.isEmpty(annot.toOneParentProperty())) {
basicFieldMetadata.setToOneParentProperty(annot.toOneParentProperty());
}
String mapKeyValueProperty = "key";
if (StringUtils.isNotBlank(myInfo.getMapKey())) {
mapKeyValueProperty = myInfo.getMapKey();
}
if (annotMap != null) {
if (StringUtils.isNotBlank(annotMap.mapKeyValueProperty())) {
mapKeyValueProperty = annotMap.mapKeyValueProperty();
}
}
basicFieldMetadata.setMapKeyValueProperty(mapKeyValueProperty);
}
return FieldProviderResponse.HANDLED;
}
@Override
public FieldProviderResponse addMetadataFromFieldType(AddMetadataFromFieldTypeRequest addMetadataFromFieldTypeRequest, Map<String, FieldMetadata> metadata) {
if (!canHandleFieldForTypeMetadata(addMetadataFromFieldTypeRequest, metadata)) {
return FieldProviderResponse.NOT_HANDLED;
}
//look for any map field metadata that was previously added for the requested field
for (Map.Entry<String, FieldMetadata> entry : addMetadataFromFieldTypeRequest.getPresentationAttributes().entrySet()) {
if (entry.getKey().startsWith(addMetadataFromFieldTypeRequest.getRequestedPropertyName() + FieldManager.MAPFIELDSEPARATOR)) {
TypeLocatorImpl typeLocator = new TypeLocatorImpl(new TypeResolver());
Type myType = null;
//first, check if an explicit type was declared
String valueClass = ((BasicFieldMetadata) entry.getValue()).getMapFieldValueClass();
if (valueClass != null) {
myType = typeLocator.entity(valueClass);
}
if (myType == null) {
SupportedFieldType fieldType = ((BasicFieldMetadata) entry.getValue()).getExplicitFieldType();
Class<?> basicJavaType = getBasicJavaType(fieldType);
if (basicJavaType != null) {
myType = typeLocator.basic(basicJavaType);
}
}
if (myType == null) {
java.lang.reflect.Type genericType = addMetadataFromFieldTypeRequest.getRequestedField().getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) genericType;
Class<?> clazz = (Class<?>) pType.getActualTypeArguments()[1];
Class<?>[] entities = addMetadataFromFieldTypeRequest.getDynamicEntityDao().getAllPolymorphicEntitiesFromCeiling(clazz);
if (!ArrayUtils.isEmpty(entities)) {
myType = typeLocator.entity(entities[entities.length-1]);
}
}
}
if (myType == null) {
throw new IllegalArgumentException("Unable to establish the type for the property (" + entry
.getKey() + ")");
}
//add property for this map field as if it was a normal field
super.addMetadataFromFieldType(new AddMetadataFromFieldTypeRequest(addMetadataFromFieldTypeRequest.getRequestedField(),
addMetadataFromFieldTypeRequest.getTargetClass(),
addMetadataFromFieldTypeRequest.getForeignField(), addMetadataFromFieldTypeRequest.getAdditionalForeignFields(),
addMetadataFromFieldTypeRequest.getMergedPropertyType(), addMetadataFromFieldTypeRequest.getComponentProperties(),
addMetadataFromFieldTypeRequest.getIdProperty(),
addMetadataFromFieldTypeRequest.getPrefix(),
entry.getKey(), myType, addMetadataFromFieldTypeRequest.isPropertyForeignKey(),
addMetadataFromFieldTypeRequest.getAdditionalForeignKeyIndexPosition(),
addMetadataFromFieldTypeRequest.getPresentationAttributes(), entry.getValue(),
((BasicFieldMetadata) entry.getValue()).getExplicitFieldType(),
myType.getReturnedClass(), addMetadataFromFieldTypeRequest.getDynamicEntityDao()), metadata);
}
}
return FieldProviderResponse.HANDLED;
}
@Override
public FieldProviderResponse overrideViaAnnotation(OverrideViaAnnotationRequest overrideViaAnnotationRequest, Map<String, FieldMetadata> metadata) {
//TODO support annotation override
return FieldProviderResponse.NOT_HANDLED;
}
@Override
public FieldProviderResponse overrideViaXml(OverrideViaXmlRequest overrideViaXmlRequest, Map<String, FieldMetadata> metadata) {
//TODO support xml override
return FieldProviderResponse.NOT_HANDLED;
}
@Override
public int getOrder() {
return FieldMetadataProvider.MAP_FIELD;
}
}