Web 8, SI4T and Storage Extensions

The release of SDL Web 8 has seen the biggest overhaul of the Content Delivery stack since Tridion 2011 and much of it has been applauded much, as the new Micro Services architecture and with it the ability to scale, deploy and be distributed in general, gives many more architectural options than just having an API in your web application connecting you to a database.

Building this while guaranteeing backward compatibility with the Tridion 2011/2013 CD stack is more than a major task and I for one am happy to see that that feat was pulled off really well. That is, unless you have overridden the default DAOFactory classes in your Deployer Storage Extensions, as is the case with the SI4T Storage Extensions. When testing SI4T with Web 8, it turned out that loading of the SI4T Storage Extension did not work in every scenario. This has to do with the subtler points of Spring Bean Class loading.

The reason to override and extend the default DAOFactories in the first place is to achieve multiple goals: first of all, we need to hook into the transactional mechanism of the DAO Factories; in case a Tridion deployment fails, the subsequent indexing action should then also fail. This is done by overriding the commitTransaction method of the DAOFactory, which coincidentally also achieves the second goal: we can normally deploy content while we are also pushing that content into a search index at the same time.

In the CD stack you can then configure your own DAOFactory extending from either the native FSDAOFactory or the JPADAOFactory or you can create a completely new one by just implementing the DAOFactory interface as is explained in the SDL docs.

In the CD Storage Configuration file, you simply change the class name on the Storage elements:

<Storage Type="filesystem" Class="com.tridion.storage.si4t.FSSearchDAOFactory" Id="defaultFile"                           
     defaultFilesystem="false" defaultStorage="false">

The Deployer’s Storage Factory Configuration Loader will then pick it up and use that class to deploy content and do what ever other magic you want it to do.

Prior to Web 8, all the DAOFactory classes (except the JPADAOFactory class) were loaded by simply doing a clazz.getConstructor().newInstance() call, which worked fine in all situations where a DAOFactory class was present. In Web 8 however, the class loading code was changed to load all Factory classes through Spring Bean class loading, using a construct like: (DAOFactory)this.applicationContext.getBean((Class)daoFactory,….) . This also works, unless you find yourself in one of the following scenarios:

  • You use a combination of regular DAOFactories and extended ones, as in the example below:

    <Storage Type="filesystem" 
        Class="com.tridion.storage.filesystem.FSDAOFactory"                      
        Id="myFSId" defaultFilesystem="true" defaultStorage="true">
        
    		
    <Storage Type="filesystem" 
        Class="com.tridion.storage.si4t.FSSearchDAOFactory" 												    
        Id="myFSSearchId" defaultFilesystem="false" defaultStorage="false">
            
            
    	
    
  • You’re on Web 8 version 8.1.0, build 1218 and you use extended DAO Factories. In that case, adding extended DAOFactory classes won’t work. Thanks to a very fast response time from SDL R&D, you can install hotfixes ‘8.1.0.1418 – SI4T did not work with SDL Web 8’ or ‘8.1.0.1467 This cumulative hotfix addresses the following problems: SI4T did not work with SDL Web 8’ to fix it. Web 8 versions 8.1.1 and up already have to code fixes in them.

A fix for the first scenario was a little harder to find. The main reason for that is that the SI4T Storage Extension extends the native DAOFactories. If Spring’s getBean is called and finds in essence to classes with a shared signature, you get ye ole ‘NoUniqueBeanException’, meaning that Spring thinks you have one and the same class twice on your classpath and that Spring then doesn’t know which class to instantiate. To solve this, a little voodoo was needed. We annotated the extended classes with the @Primary attribute and ensured that normal DAOFactory classes could stil continue working alongside the extended ones:


@Component ("FSSearchDAOFactory")
@Qualifier ("FSSearchDAOFactory")
@Scope ("prototype")
// Primary hides the other DAO factories. Hence, see this.configure()
@Primary
public class FSSearchDAOFactory extends FSDAOFactory {
//...
    @Override
    public void configure (Configuration configuration) throws ConfigurationException {
        super.configure(configuration);

        final String daoFactoryClassName = configuration.getAttribute(DAO_FACTORY_CLASS_ATTRIBUTE);

        if (daoFactoryClassName.equalsIgnoreCase(FSDAOFactory.class.getCanonicalName())) {
            LOG.info("This seems to be a normal FSDAOFactory ( {} ) for Storage Id: '{}', so not triggering and configuring the extension.", daoFactoryClassName, this.storageId);
            this.isExtendedDaoFactory = false;
            return;
        }
        searchIndexProcessor.configureStorageInstance(storageId, configuration);
    }
    
    @Override
    public void commitTransaction (String transactionId) throws StorageException {       
            if (this.isExtendedDaoFactory) {
                super.commitTransaction(transactionId);   
                searchIndexProcessor.triggerIndexing(transactionId, this.storageId);
            } else {
                LOG.info("Not triggering any special stuff, as this instance for storage Id '{}' needs to behave like the normal DAOFactory",this.storageId);
                super.commitTransaction(transactionId);
            }
    }
}

These fixes for SDL Web 8 are contained in SI4T Storage Extensions version 1.2 and can be found on our releases page. If you use SI4T-Solr, it is also recommended to use that latest version as well.

One thought on “Web 8, SI4T and Storage Extensions

  1. Pingback: SI4T-Solr 1.2 for Web 8 Released | SDL Tridion Developer

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>