/*
* This code is distributed under The GNU Lesser General Public License (LGPLv3)
* Please visit GNU site for LGPLv3 http://www.gnu.org/copyleft/lesser.html
*
* Copyright Denis Pavlov 2009
* Web: http://www.genericdtoassembler.org
* SVN: https://svn.code.sf.net/p/geda-genericdto/code/trunk/
* SVN (mirror): http://geda-genericdto.googlecode.com/svn/trunk/
*/
package com.inspiresoftware.lib.dto.geda.assembler;
import com.inspiresoftware.lib.dto.geda.assembler.meta.PipeMetadata;
import com.inspiresoftware.lib.dto.geda.dsl.*;
import com.inspiresoftware.lib.dto.geda.exception.UnableToCreateInstanceException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* Builder for creating chains of metadata for annotations.
*
* @author DPavlov
*/
class MetadataChainDSLBuilder implements MetadataChainBuilder {
private final DtoEntityContext context;
MetadataChainDSLBuilder(final Registry registry, final Class dtoClass, final Class entityClass) {
final DtoContext ctx = registry.has(dtoClass);
if (ctx != null) {
this.context = ctx.has(entityClass);
} else {
this.context = null;
}
}
/**
* Build metadata chain for this field.
* @param dtoField fiel to build pipe for
* @return metadata chain.
* @throws com.inspiresoftware.lib.dto.geda.exception.UnableToCreateInstanceException when collections/map pipe cannot create data readers/writers
*/
public List<PipeMetadata> build(final Field dtoField) throws UnableToCreateInstanceException {
if (this.context == null) {
return null;
}
final Object fieldContext = this.context.has(dtoField.getName());
if (fieldContext == null) {
return null;
}
if (fieldContext instanceof DtoFieldContext) {
final DtoFieldContext field = (DtoFieldContext) fieldContext;
if (field.getValueOfVirtual()) {
return buildVirtualFieldChain(dtoField, field);
} else {
return buildFieldChain(dtoField, field);
}
} else if (fieldContext instanceof DtoCollectionContext) {
return buildCollectionChain(dtoField, (DtoCollectionContext) fieldContext);
} else if (fieldContext instanceof DtoMapContext) {
return buildMapChain(dtoField, (DtoMapContext) fieldContext);
}
return null;
}
private List<PipeMetadata> buildVirtualFieldChain(final Field dtoField, final DtoFieldContext dtoFieldContext) {
final String[] bindings = { "#this#" + dtoField.getName() };
final List<PipeMetadata> metas = new ArrayList<PipeMetadata>(bindings.length);
for (int index = 0; index < bindings.length; index++) {
metas.add(new FieldPipeMetadata(
dtoField.getName(),
bindings[index],
dtoFieldContext.getValueOfDtoBeanKey(),
getStringFromArray(dtoFieldContext.getValueOfEntityBeanKeys(), index),
dtoFieldContext.getValueOfReadOnly(),
dtoFieldContext.getValueOfConverter(),
false,
null,
null
));
}
return metas;
}
private List<PipeMetadata> buildFieldChain(final Field dtoField, final DtoFieldContext dtoFieldContext) {
final String[] bindings = createFieldBindingChain(getBindingFromAnnotationOrFieldName(dtoFieldContext.getValueOfEntityField(), dtoField.getName()));
final List<PipeMetadata> metas = new ArrayList<PipeMetadata>(bindings.length);
for (int index = 0; index < bindings.length; index++) {
metas.add(new FieldPipeMetadata(
dtoField.getName(),
bindings[index],
dtoFieldContext.getValueOfDtoBeanKey(),
getStringFromArray(dtoFieldContext.getValueOfEntityBeanKeys(), index),
dtoFieldContext.getValueOfReadOnly(),
dtoFieldContext.getValueOfConverter(),
dtoFieldContext.getValueOfDtoParent(),
dtoFieldContext.getValueOfDtoParent() ? dtoFieldContext.getValueOfDtoParentPrimaryKey() : null,
dtoFieldContext.getValueOfDtoParent() ? dtoFieldContext.getValueOfDtoParentRetriever() : null
));
}
return metas;
}
@SuppressWarnings("unchecked")
private static List<PipeMetadata> buildCollectionChain(final Field dtoField, final DtoCollectionContext dtoCollContext)
throws UnableToCreateInstanceException {
final String[] bindings = createFieldBindingChain(getBindingFromAnnotationOrFieldName(dtoCollContext.getValueOfEntityField(), dtoField.getName()));
final List<PipeMetadata> metas = new ArrayList<PipeMetadata>(bindings.length);
for (int index = 0; index < bindings.length; index++) {
metas.add(new CollectionPipeMetadata(
dtoField.getName(),
bindings[index],
dtoCollContext.getValueOfDtoBeanKey(),
getStringFromArray(dtoCollContext.getValueOfEntityBeanKeys(), index),
dtoCollContext.getValueOfReadOnly(),
dtoCollContext.getValueOfDtoCollectionClass(),
dtoCollContext.getValueOfDtoCollectionClassKey(),
dtoCollContext.getValueOfEntityCollectionClass(),
dtoCollContext.getValueOfEntityCollectionClassKey(),
dtoCollContext.getValueOfEntityGenericType(),
dtoCollContext.getValueOfEntityGenericTypeKey(),
dtoCollContext.getValueOfDtoToEntityMatcher(),
dtoCollContext.getValueOfDtoToEntityMatcherKey()
));
}
return metas;
}
@SuppressWarnings("unchecked")
private static List<PipeMetadata> buildMapChain(final Field dtoField, final DtoMapContext dtoMapContext) throws UnableToCreateInstanceException {
final String[] bindings = createFieldBindingChain(getBindingFromAnnotationOrFieldName(dtoMapContext.getValueOfEntityField(), dtoField.getName()));
final List<PipeMetadata> metas = new ArrayList<PipeMetadata>(bindings.length);
for (int index = 0; index < bindings.length; index++) {
metas.add(new MapPipeMetadata(
dtoField.getName(),
bindings[index],
dtoMapContext.getValueOfDtoBeanKey(),
getStringFromArray(dtoMapContext.getValueOfEntityBeanKeys(), index),
dtoMapContext.getValueOfReadOnly(),
dtoMapContext.getValueOfDtoMapClass(),
dtoMapContext.getValueOfDtoMapClassKey(),
dtoMapContext.getValueOfEntityMapOrCollectionClass(),
dtoMapContext.getValueOfEntityMapOrCollectionClassKey(),
dtoMapContext.getValueOfEntityGenericType(),
dtoMapContext.getValueOfEntityGenericTypeKey(),
dtoMapContext.getValueOfEntityCollectionMapKey(),
dtoMapContext.getValueOfUseEntityMapKey(),
dtoMapContext.getValueOfDtoToEntityMatcher(),
dtoMapContext.getValueOfDtoToEntityMatcherKey()
));
}
return metas;
}
private static String getBindingFromAnnotationOrFieldName(final String annotation, final String fieldName) {
if (annotation == null || annotation.length() == 0) {
return fieldName;
}
return annotation;
}
private static String[] createFieldBindingChain(final String binding) {
if (binding.indexOf('.') == -1) {
return new String[] { binding };
}
return binding.split("\\.");
}
private static String getStringFromArray(final String[] array, final int index) {
if (array != null && index < array.length) {
return array[index];
}
return "";
}
}