/* * Copyright 2012 - 2017 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.springframework.data.solr.core.mapping; import java.util.Locale; import java.util.Optional; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.expression.BeanFactoryAccessor; import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.mapping.model.BasicPersistentEntity; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.solr.repository.Score; import org.springframework.data.util.TypeInformation; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.util.StringUtils; /** * Solr specific {@link PersistentEntity} implementation holding eg. name of solr core. * * @param <T> * @author Christoph Strobl * @author Francisco Spaeth */ public class SimpleSolrPersistentEntity<T> extends BasicPersistentEntity<T, SolrPersistentProperty> implements SolrPersistentEntity<T>, ApplicationContextAware { private final TypeInformation<T> typeInformation; private final StandardEvaluationContext context; private String solrCoreName; private Float boost; public SimpleSolrPersistentEntity(TypeInformation<T> typeInformation) { super(typeInformation); this.context = new StandardEvaluationContext(); this.typeInformation = typeInformation; this.solrCoreName = derivateSolrCoreName(); this.boost = derivateDocumentBoost(); } /* * (non-Javadoc) * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context.addPropertyAccessor(new BeanFactoryAccessor()); context.setBeanResolver(new BeanFactoryResolver(applicationContext)); context.setRootObject(applicationContext); } private String derivateSolrCoreName() { String derivativeSolrCoreName = this.typeInformation.getType().getSimpleName().toLowerCase(Locale.ENGLISH); Optional<SolrDocument> solrDocument = findAnnotation(SolrDocument.class); if (solrDocument.isPresent()) { if (StringUtils.hasText(solrDocument.get().solrCoreName())) { derivativeSolrCoreName = solrDocument.get().solrCoreName(); } } return derivativeSolrCoreName; } private Float derivateDocumentBoost() { Optional<SolrDocument> solrDocument = findAnnotation(SolrDocument.class); if (solrDocument.isPresent() && !Float.isNaN(solrDocument.get().boost())) { return solrDocument.get().boost(); } return null; } /* * (non-Javadoc) * @see org.springframework.data.solr.core.mapping.SolrPersistentEntity#getSolrCoreName() */ @Override public String getSolrCoreName() { return this.solrCoreName; } /* * (non-Javadoc) * @see org.springframework.data.solr.core.mapping.SolrPersistentEntity#isBoosted() */ @Override public boolean isBoosted() { return boost != null; } /* * (non-Javadoc) * @see org.springframework.data.solr.core.mapping.SolrPersistentEntity#getBoost() */ @Override public Float getBoost() { return boost; } /* * (non-Javadoc) * @see org.springframework.data.solr.core.mapping.SolrPersistentEntity#hasScoreProperty() */ @Override public boolean hasScoreProperty() { return getScoreProperty() != null; } /* * (non-Javadoc) * @see org.springframework.data.solr.core.mapping.SolrPersistentEntity#getScoreProperty() */ @Override public Optional<SolrPersistentProperty> getScoreProperty() { return getPersistentProperty(Score.class); } /* * (non-Javadoc) * @see org.springframework.data.mapping.model.BasicPersistentEntity#verify() */ @Override public void verify() { super.verify(); verifyScoreFieldUniqueness(); verifyDynamicPropertyMapping(); } private void verifyScoreFieldUniqueness() { doWithProperties(new ScoreFieldUniquenessHandler()); } private void verifyDynamicPropertyMapping() { doWithProperties(DynamicFieldMappingHandler.INSTANCE); } /** * Handler to inspect {@link SolrPersistentProperty} instances and check that max one can be mapped as {@link Score} * property. * * @author Christpoh Strobl * @since 1.4 */ private static class ScoreFieldUniquenessHandler implements PropertyHandler<SolrPersistentProperty> { private static final String AMBIGUOUS_FIELD_MAPPING = "Ambiguous score field mapping detected! Both %s and %s marked as target for score value. Disambiguate using @Score annotation!"; private SolrPersistentProperty scoreProperty; /* * (non-Javadoc) * @see org.springframework.data.mapping.PropertyHandler#doWithPersistentProperty(org.springframework.data.mapping.PersistentProperty) */ public void doWithPersistentProperty(SolrPersistentProperty persistentProperty) { assertUniqueness(persistentProperty); } private void assertUniqueness(SolrPersistentProperty property) { if (property.isScoreProperty()) { if (scoreProperty != null) { throw new MappingException( String.format(AMBIGUOUS_FIELD_MAPPING, property.getFieldName(), scoreProperty.getFieldName())); } scoreProperty = property; } } } /** * Handler to inspect {@link SolrPersistentProperty} instances and check usage of {@link Dynamic}. * * @author Christoph Strobl * @since 1.5 */ private enum DynamicFieldMappingHandler implements PropertyHandler<SolrPersistentProperty> { INSTANCE; private static final String DYNAMIC_PROPERTY_NOT_A_MAP = "Invalid mapping information for property '%s' with mapped name '%s'. @Dynamic can only be applied on Map based types!"; private static final String DYNAMIC_PROPERTY_NOT_CONTAINING_WILDCARD = "Invalid mapping information for property '%s' with mapped name '%s'. Dynamic property needs to specify wildcard."; @Override public void doWithPersistentProperty(SolrPersistentProperty property) { if (property.isDynamicProperty()) { if (!property.isMap()) { throw new MappingException( String.format(DYNAMIC_PROPERTY_NOT_A_MAP, property.getName(), property.getFieldName())); } if (!property.containsWildcard()) { throw new MappingException( String.format(DYNAMIC_PROPERTY_NOT_CONTAINING_WILDCARD, property.getName(), property.getFieldName())); } } } } }