org.seedstack.business.internal.assembler.dsl.LegacyDtoInfoResolver Maven / Gradle / Ivy
/*
* Copyright © 2013-2018, The SeedStack authors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.seedstack.business.internal.assembler.dsl;
import static org.seedstack.shed.reflect.ReflectUtils.makeAccessible;
import java.lang.annotation.Annotation;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Priority;
import javax.inject.Inject;
import org.seedstack.business.assembler.MatchingEntityId;
import org.seedstack.business.assembler.MatchingFactoryParameter;
import org.seedstack.business.domain.AggregateRoot;
import org.seedstack.business.domain.DomainRegistry;
import org.seedstack.business.internal.BusinessErrorCode;
import org.seedstack.business.internal.BusinessException;
import org.seedstack.business.spi.BaseDtoInfoResolver;
import org.seedstack.business.spi.DtoInfoResolver;
import org.seedstack.business.spi.DtoInfoResolverPriority;
import org.seedstack.shed.cache.Cache;
import org.seedstack.shed.cache.CacheParameters;
import org.seedstack.shed.reflect.Classes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of the {@link DtoInfoResolver} based on the {@link MatchingEntityId} and
* {@link MatchingFactoryParameter} annotation.
*
* @see MatchingEntityId
* @see MatchingFactoryParameter
*/
@Priority(DtoInfoResolverPriority.MATCHING_ANNOTATIONS)
class LegacyDtoInfoResolver extends BaseDtoInfoResolver {
private static final Logger LOGGER = LoggerFactory.getLogger(LegacyDtoInfoResolver.class);
private static final Class extends Annotation> MATCHING_ENTITY_ID = MatchingEntityId.class;
private static final Class extends Annotation> MATCHING_FACT_PARAM = MatchingFactoryParameter.class;
private static final Cache, DtoInfo>> dtoInfo = Cache.create(
new CacheParameters, DtoInfo>>()
.setInitialSize(256)
.setMaxSize(1024)
.setLoadingFunction(LegacyDtoInfoResolver::resolveDtoInfo)
);
@Inject
LegacyDtoInfoResolver(DomainRegistry domainRegistry) {
super(domainRegistry);
}
@Override
public boolean supports(D dto) {
return getDtoInfo(dto).supported;
}
@Override
public I resolveId(D dto, Class aggregateIdClass) {
ParameterHolder parameterHolder = getIdParameterHolder(dto, aggregateIdClass);
return createIdentifier(aggregateIdClass, parameterHolder.uniqueElement(dto),
parameterHolder.parameters(dto));
}
@Override
public I resolveId(D dto, Class aggregateIdClass, int position) {
ParameterHolder parameterHolder = getIdParameterHolder(dto, aggregateIdClass);
return createIdentifier(aggregateIdClass, parameterHolder.uniqueElementForAggregate(dto, position),
parameterHolder.parametersOfAggregateRoot(dto, position));
}
@Override
public > A resolveAggregate(D dto, Class aggregateRootClass) {
return createFromFactory(aggregateRootClass, getAggregateParameterHolder(dto).parameters(dto));
}
@Override
public > A resolveAggregate(D dto, Class aggregateRootClass, int position) {
return createFromFactory(aggregateRootClass,
getAggregateParameterHolder(dto).parametersOfAggregateRoot(dto, position));
}
private ParameterHolder getIdParameterHolder(D dto, Class aggregateIdClass) {
ParameterHolder parameterHolder = getDtoInfo(dto).idParameterHolder;
if (parameterHolder.isEmpty()) {
throw BusinessException.createNew(BusinessErrorCode.NO_IDENTITY_CAN_BE_RESOLVED_FROM_DTO)
.put("dtoClass", dto.getClass()
.getName())
.put("aggregateIdClass", aggregateIdClass);
}
return parameterHolder;
}
private ParameterHolder getAggregateParameterHolder(D dto) {
return getDtoInfo(dto).aggregateParameterHolder;
}
@SuppressWarnings("unchecked")
private DtoInfo getDtoInfo(D dto) {
return (DtoInfo) dtoInfo.get(dto.getClass());
}
private static DtoInfo resolveDtoInfo(Class dtoClass) {
final ParameterHolder idParameterHolder = new ParameterHolder<>((Class) dtoClass);
final ParameterHolder aggregateParameterHolder = new ParameterHolder<>((Class) dtoClass);
final AtomicBoolean supported = new AtomicBoolean(false);
LOGGER.debug("Resolving DTO information on {}", dtoClass);
Classes.from(dtoClass)
.traversingSuperclasses()
.methods()
.forEach(method -> {
makeAccessible(method);
MatchingEntityId idAnnotation = method.getAnnotation(MatchingEntityId.class);
if (idAnnotation != null) {
if (idAnnotation.typeIndex() >= 0) {
if (idAnnotation.index() >= 0) {
idParameterHolder.addTupleParameter(MATCHING_ENTITY_ID,
idAnnotation.typeIndex(), idAnnotation.index(), method);
} else {
idParameterHolder.addTupleValue(MATCHING_ENTITY_ID, idAnnotation.typeIndex(),
method);
}
} else {
if (idAnnotation.index() >= 0) {
idParameterHolder.addParameter(MATCHING_ENTITY_ID, idAnnotation.index(), method);
} else {
idParameterHolder.addValue(MATCHING_ENTITY_ID, method);
}
}
supported.set(true);
}
MatchingFactoryParameter factoryAnnotation = method
.getAnnotation(MatchingFactoryParameter.class);
if (factoryAnnotation != null) {
if (factoryAnnotation.typeIndex() >= 0) {
if (factoryAnnotation.index() >= 0) {
aggregateParameterHolder.addTupleParameter(MATCHING_FACT_PARAM,
factoryAnnotation.typeIndex(), factoryAnnotation.index(), method);
} else {
aggregateParameterHolder.addTupleValue(MATCHING_FACT_PARAM,
factoryAnnotation.typeIndex(), method);
}
} else {
if (factoryAnnotation.index() >= 0) {
aggregateParameterHolder.addParameter(MATCHING_FACT_PARAM,
factoryAnnotation.index(), method);
} else {
aggregateParameterHolder.addValue(MATCHING_FACT_PARAM, method);
}
}
supported.set(true);
}
});
if (supported.get()) {
return new DtoInfo<>(true, idParameterHolder.freeze(), aggregateParameterHolder.freeze());
} else {
return new DtoInfo<>(false, null, null);
}
}
private static class DtoInfo {
final boolean supported;
final ParameterHolder idParameterHolder;
final ParameterHolder aggregateParameterHolder;
private DtoInfo(boolean supported, ParameterHolder idParameterHolder,
ParameterHolder aggregateParameterHolder) {
this.supported = supported;
this.idParameterHolder = idParameterHolder;
this.aggregateParameterHolder = aggregateParameterHolder;
}
}
}