5.4.3. Customizing Feedables

A feedable is an object which is generated from the data of a content bean and which the CAE Feeder sends to the Search Engine for indexing. Customizing feedables means that you define which content of a content bean is mapped to fields of the feedable and is therefore added to the index if a corresponding Solr index field exists. The following paragraphs describe the involved classes.

The FeedableContentBeanEvaluator creates feedables from ContentBean objects. You can find the configuration in the file caefeeder-triggers.xml, which is located in the classpath /framework/spring/caefeeder.

<bean name="contentEvaluator" class=
"com.coremedia.amaro.cae.feeder.FeedableContentBeanEvaluator">
  <property name="contentBeanFactory" ref="contentBeanFactory"/>
  <property name="keyTransformer" ref="feederKeyTransformer"/>
  <property name="feedableFactory" ref="feedableFactory"/>
  <property name="feedablePopulator"
            ref="errorHandlingFeedablePopulator"/>
</bean>

Example 5.5. Definition of FeedableContentBeanEvaluator


An implementation of com.coremedia.cap.feeder.persistentcache.KeyTransformer is used to create identifiers for Search Engine documents in the index. The default KeyTransformer implementation creates identifiers of the same format as the IdProvider of the CoreMedia CAE.

Example: a content bean for the content with the numerical id 42 is represented by an Apache Solr document with the value contentbean:42 in the field id. Search applications can use the IdProvider to get a content bean for the identifier again.

The FeedableContentBeanEvaluator uses an implementation of com.coremedia.cap.feeder.populate.FeedablePopulator to fill the elements of the feedable with the values of a content bean. By default, a BeanMappingFeedablePopulator is used which maps Java bean properties of ContentBean objects to elements of the created feedable as configured.

If required, you can configure additional FeedablePopulator implementations in the property populators of the bean compositeFeedablePopulator. The property takes a list of FeedablePopulator<T> beans, which makes it possible to combine data from different implementations into the same feedable. The type parameter <T> of a configured FeedablePopulator bean must be ContentBean, Content or a super type of these. You can find some existing FeedablePopulator implementations in package com.coremedia.cap.feeder.populate. For example, you may configure an additional PropertyPathFeedablePopulator to index certain nested values of struct properties.

If a bean property's get method throws an exception, the CAE Feeder will index a so-called error document in the index as placeholder. Error documents can be recognized by the value ERROR in the index field feederstate. The stack trace of the exception is stored in the index field feederinfo. Do not forget to always add a feederstate:SUCCESS clause to your queries to find successfully indexed documents. Bean feeding will by default automatically be retried after 10 minutes or if a dependency is invalidated that was accessed before the exception was thrown. Errors are handled by an instance of class com.coremedia.cap.feeder.populate.ErrorHandlingFeedablePopulator which wraps all FeedablePopulator instances. It is available in the Spring Context as bean errorHandlingFeedablePopulator and can be customized as described in its API documentation.

Defining the Properties for Indexing

The BeanMappingFeedablePopulator class has two properties that you can use for customizing the mapping between content bean properties and Feedable.

  • beanPropertiesByClass

  • beanMappings

beanMappings offers more powerful options. You can, for example, add a property converter implementation that maps to a specific type.

Using beanPropertiesByClass

This configuration provides a simple way for bean properties which are mapped to feedable elements with the same name. The values of these bean properties are written to an index field with the same name, if it exists. Furthermore, the bean property values will always be appended to the textbody index field.

In more detail, the property beanPropertiesByClass of the BeanMappingFeedablePopulator takes a java.util.Map object, which maps bean classes to comma-separated strings of their indexed bean properties. This map is available in the Spring application context under the name caeFeederBeanPropertiesByClass and can be customized.

The following example defines the mapping for content beans of classes com.coremedia.example.contentbeans.Text and com.coremedia.example.contentbeans.Download. For content beans of class Text and subclasses, the Java bean properties headline and text map to elements of the feedable. When constructing a feedable the BeanMappingFeedablePopulator calls the property methods getHeadline and getText of class Text to retrieve the values for these elements.

<customize:append id="caeFeederBeanPropertiesByClassCustomizer"
                  bean="caeFeederBeanPropertiesByClass">
  <map>
    <entry key="com.coremedia.example.contentbeans.Text"
           value="headline,text"/>
    <entry key="com.coremedia.example.contentbeans.Download"
           value="data"/>
  </map>
</customize:append>
Using beanMappings

A more powerful configuration is available with the property beanMappings of the BeanMappingFeedablePopulator. The new options are:

  • Define to which search field a content bean property is mapped

  • Define that a content bean property should not be mapped to the textBody field of Solr

  • Define your own property converter

  • Define a default value when a property returns null

  • Adding parameters to a feedable

The property beanMappings takes a list of mappings where each mapping applies to one bean class. You can customize this list of mappings as shown below. A mapping for a single bean class is represented by a com.coremedia.cap.feeder.bean.BeanFeedableMapping. Each BeanFeedableMapping contains a list of mappings for Java bean properties of the bean class in the property beanPropertyMappings. A mapping for a single Java bean property to an element of the Feedable is represented by a com.coremedia.cap.feeder.bean.BeanPropertyFeedableElementMapping. See Example 5.6, “Example Content Bean to Feedable Mapping” for an example.

[Note]Note

A content bean can inherit from or extend other content beans. In this case, you might have different BeanFeedableMapping elements that match for an instance of a content bean. If so, the order of the BeanFeedableMapping elements in the list of mappings is important: The first mapping of a property that matches overwrites all following mappings that match.

Example 5.6, “Example Content Bean to Feedable Mapping” defines a mapping for the superclass of all content beans com.coremedia.objectserver.beans.ContentBean. The bean property content.modificationDate maps to the feedable element named freshness. The default Solr index schema defines an index field with that name, to which the bean property's value is written. The bean property uses the syntax of Spring framework's bean wrapper for nested properties. When constructing a feedable the BeanMappingFeedablePopulator calls the property methods getContent().getModificationDate() of class ContentBean to retrieve the value for the element. Furthermore, the value is not added to the textbody index field.

Keep in mind, that if you define a mapping for freshness for any other content bean class and add it behind this example mapping to the list of mappings, it would be overwritten by our example definition and you would get a warning in the log file. So, avoid this.

<customize:append id="caeFeederBeanMappingsCustomizer"
                  bean="caeFeederBeanMappings">
  <list>
    <ref local="exampleBeanFeedableMapping"/>
  </list>
</customize:append>

<bean id="exampleBeanFeedableMapping"
      class="com.coremedia.cap.feeder.bean.BeanFeedableMapping">
  <property name="beanClass"
            value="com.coremedia.objectserver.beans.ContentBean"/>
  <property name="beanPropertyMappings">
    <list>
      <bean class="com.coremedia.cap.feeder.bean.
                   BeanPropertyFeedableElementMapping">
        <property name="beanProperty"
                  value="content.modificationDate"/>
        <property name="feedableElement" value="freshness"/>
        <property name="textBody" value="false"/>
      </bean>
    </list>
  </property>
</bean>

Example 5.6. Example Content Bean to Feedable Mapping


See the API documentation for a description of all properties of the classes BeanMappingFeedablePopulator, BeanFeedableMapping and BeanPropertyFeedableElementMapping in package com.coremedia.cap.feeder.bean.

Mapping of Property Types

The CAE Feeder supports String, Number, Date, XML and binary element types. The following table describes the default mapping from Java bean property value classes to element types:

property value class element type
com.coremedia.cap.common.Blob Binary
java.util.Date and java.util.Calendar Date
com.coremedia.xml.Markup XML
java.lang.Number and primitive number types Number
java.lang.String String
java.lang.Collection with elements of above types depends on collection's element type

Table 5.2. Feedable Element Types for Java Bean Properties


Values of other classes map to String elements with the value of their toString method. Collections must contain elements of one type, otherwise the value of the elements' toString method will be used.

Collection elements can be used to feed multi-value fields in Apache Solr.

You can configure a property converter to convert the value to one of the supported types. A property converter implements the interface com.coremedia.cap.feeder.bean.PropertyConverter and can be configured with the propertyConverter property of the BeanPropertyFeedableElementMapping. Property converters are for example useful when indexing collection properties. The property converter implementations com.coremedia.cap.feeder.bean.CollectionPropertyConverter and com.coremedia.cap.feeder.bean.CollectionToStringPropertyConverter can be used for this purpose. Please see the Javadoc for details.

Furthermore, it is possible to configure a default value which should be indexed if a bean property is null or a configured PropertyConverter returns null. A default value can be configured with the defaultValue property of the BeanPropertyFeedableElementMapping. Again, please see the Javadoc for details.