Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sdl.dxa.tridion.mapping.impl.DefaultSemanticFieldDataProvider Maven / Gradle / Ivy
package com.sdl.dxa.tridion.mapping.impl;
import com.sdl.dxa.api.datamodel.model.ContentModelData;
import com.sdl.dxa.api.datamodel.model.EntityModelData;
import com.sdl.dxa.api.datamodel.model.KeywordModelData;
import com.sdl.dxa.api.datamodel.model.ViewModelData;
import com.sdl.dxa.api.datamodel.model.util.CanWrapContentAndMetadata;
import com.sdl.dxa.api.datamodel.model.util.ListWrapper;
import com.sdl.dxa.api.datamodel.model.util.ModelDataWrapper;
import com.sdl.dxa.tridion.mapping.ModelBuilderPipeline;
import com.sdl.dxa.tridion.mapping.converter.GenericSemanticModelDataConverter;
import com.sdl.webapp.common.api.WebRequestContext;
import com.sdl.webapp.common.api.mapping.semantic.FieldData;
import com.sdl.webapp.common.api.mapping.semantic.SemanticFieldDataProvider;
import com.sdl.webapp.common.api.mapping.semantic.SemanticMappingException;
import com.sdl.webapp.common.api.mapping.semantic.config.FieldPath;
import com.sdl.webapp.common.api.mapping.semantic.config.SemanticField;
import com.sdl.webapp.common.api.mapping.semantic.config.SemanticSchema;
import com.sdl.webapp.common.api.model.KeywordModel;
import com.sdl.webapp.common.api.model.entity.Link;
import com.sdl.webapp.common.api.model.entity.MediaItem;
import com.sdl.webapp.common.exceptions.DxaException;
import com.sdl.webapp.common.util.TcmUtils;
import com.sdl.webapp.tridion.fields.exceptions.FieldConverterException;
import com.sdl.webapp.tridion.fields.exceptions.UnsupportedTargetTypeException;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.sdl.webapp.common.util.ApplicationContextHolder.getContext;
@Slf 4j
public class DefaultSemanticFieldDataProvider implements SemanticFieldDataProvider {
private ModelDataWrapper dataWrapper;
@Getter
private SemanticSchema semanticSchema;
private GenericSemanticModelDataConverter genericSemanticModelDataConverter;
private ModelBuilderPipeline pipeline;
private int embeddingLevel = 0 ;
private int iteration = 0 ;
private String context = null ;
private DefaultSemanticFieldDataProvider(ModelDataWrapper dataWrapper, SemanticSchema semanticSchema) {
this .dataWrapper = dataWrapper;
this .semanticSchema = semanticSchema;
this .genericSemanticModelDataConverter = getContext().getBean(GenericSemanticModelDataConverter.class );
this .pipeline = getContext().getBean(ModelBuilderPipeline.class );
}
@Nullable
public static DefaultSemanticFieldDataProvider getFor(ViewModelData model, SemanticSchema semanticSchema) {
return getFor((Object) model, semanticSchema);
}
@Nullable
private static DefaultSemanticFieldDataProvider getFor(@NotNull Object model, SemanticSchema semanticSchema) {
if (!(model instanceof CanWrapContentAndMetadata)) {
log.debug("Type {} is not supported by embedded SemanticFieldDataProvider" , model.getClass());
return null ;
}
return new DefaultSemanticFieldDataProvider(((CanWrapContentAndMetadata) model).getDataWrapper(), semanticSchema);
}
@Nullable
public DefaultSemanticFieldDataProvider iteration(Object model, SemanticField semanticField, int index) {
DefaultSemanticFieldDataProvider provider = getFor(model, semanticSchema);
if (provider != null ) {
provider.embeddingLevel = this .embeddingLevel;
provider.iteration = index + 1 ;
provider.context = semanticField.getXPath(this .context) + "[" + provider.iteration + "]" ;
log.trace("Iterating over some list, current index = {}, item = {}, embedding level = {}, context = {}" ,
index, model, this .embeddingLevel, provider.context);
}
return provider;
}
@Nullable
public DefaultSemanticFieldDataProvider embedded(Object value) {
DefaultSemanticFieldDataProvider provider = getFor(value, this .semanticSchema);
if (provider != null ) {
provider.iteration = this .iteration;
provider.context = this .context;
provider.embeddingLevel = this .embeddingLevel + 1 ;
log.trace("Embedding into embedding level = {}, index = {}, item = {}, context = {}" ,
provider.iteration, value, this .embeddingLevel, provider.context);
}
return provider;
}
@Override
public FieldData getFieldData(SemanticField semanticField, TypeDescriptor targetType) throws SemanticMappingException {
log.trace("semanticField: {}, targetType: {}" , semanticField, targetType);
ContentModelData data = semanticField.getPath().isMetadata() ? dataWrapper.getMetadata() : dataWrapper.getContent();
FieldPath path = getCurrentPath(semanticField);
if (path == null ) {
log.warn("Path is null for semantic field {}, embedding level {}" , semanticField, embeddingLevel);
return null ;
}
Optional field = findField(data, path);
if (!field.isPresent()) {
log.debug("No data is found for path {} for semantic field {}" , path, semanticField);
return null ;
}
Object value = genericSemanticModelDataConverter.convert(field.get(), targetType, semanticField, pipeline, this );
return new FieldData(value, semanticField.getXPath(this .context));
}
@Override
public Object getSelfFieldData(TypeDescriptor targetType) throws SemanticMappingException {
Class objectType = targetType.getObjectType();
if (MediaItem.class .isAssignableFrom(objectType) || Link.class .isAssignableFrom(objectType) || String.class .isAssignableFrom(objectType)) {
try {
return genericSemanticModelDataConverter.selfLink(dataWrapper.getWrappedModel(), targetType, pipeline);
} catch (DxaException e) {
throw new SemanticMappingException("Failed self-linking " + targetType, e);
}
}
throw new UnsupportedTargetTypeException(targetType);
}
@Override
public Map getAllFieldData(Class targetType) throws SemanticMappingException {
final Map fieldData = new HashMap<>();
Stream> content = getEntryStream(dataWrapper.getContent());
Stream> metadata = getEntryStream(dataWrapper.getMetadata());
for (Map.Entry entry : Stream.concat(content, metadata).collect(Collectors.toSet()))
{
this .getAllFieldsData(entry, fieldData, targetType);
}
return fieldData;
}
private Stream> getEntryStream(ContentModelData contentModelData) {
return contentModelData != null ? contentModelData.entrySet().stream() : Stream.empty();
}
private void getAllFieldsData(Map.Entry entry, Map fieldData ,Class targetType) throws FieldConverterException {
if ("settings" .equals(entry.getKey())) {
throw new UnsupportedOperationException("'settings' field handling" );
}
Object value = entry.getValue();
if (!fieldData.containsKey(entry.getKey()) && value != null )
{
if (targetType == KeywordModel.class )
{
if (value instanceof KeywordModelData)
{
T keyword = (T) genericSemanticModelDataConverter.convert(value, TypeDescriptor.valueOf(KeywordModel.class ), null , pipeline, this );
fieldData.put(entry.getKey(), keyword);
}
}
else if (targetType == String.class )
{
Optional emdTcmUri = (Optional) getEntityModelDataTcmUriOrNull(value);
fieldData.put(entry.getKey(), emdTcmUri.orElse(
(T) genericSemanticModelDataConverter.convert(value, TypeDescriptor.valueOf(String.class ), null ,
pipeline, this )));
}
}
}
@NotNull
private Optional getEntityModelDataTcmUriOrNull(Object possibleEmd) {
EntityModelData modelData = null ;
if (possibleEmd instanceof EntityModelData) {
modelData = (EntityModelData) possibleEmd;
} else if (possibleEmd instanceof ListWrapper.EntityModelDataListWrapper) {
modelData = ((ListWrapper.EntityModelDataListWrapper) possibleEmd).get(0 );
}
if (modelData == null ) {
return Optional.empty();
}
String localizationId = getContext().getBean(WebRequestContext.class ).getLocalization().getId();
return Optional.of(TcmUtils.buildTcmUri(localizationId, modelData.getId()));
}
@Nullable
private FieldPath getCurrentPath(SemanticField semanticField) {
FieldPath path = semanticField.getPath().getTail();
for (int i = 0 ; i < embeddingLevel && path != null ; i++) {
path = path.getTail();
}
return path;
}
@NotNull
private Optional findField(final ContentModelData data, FieldPath fieldPath) {
if (data == null || data.isEmpty() || fieldPath == null ) {
return Optional.empty();
}
Object field = data.get(fieldPath.getHead());
if (fieldPath.hasTail()) {
if (field instanceof ListWrapper) {
field = ((ListWrapper) field).get(0 );
log.debug("Field with path {} has multiple values, getting first {}" , fieldPath, field);
}
if (field instanceof String && StringUtils.isEmpty((String) field)) {
return Optional.empty();
}
return findField((ContentModelData) field, fieldPath.getTail());
}
return Optional.ofNullable(field);
}
}