/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.core.xslt.portal; import java.util.concurrent.locks.Lock; import javax.xml.transform.Source; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.enonic.cms.framework.cache.CacheFacade; import com.enonic.cms.framework.cache.CacheManager; import com.enonic.cms.framework.util.GenericConcurrencyLock; import com.enonic.cms.core.portal.livetrace.LivePortalTraceService; import com.enonic.cms.core.portal.livetrace.XsltCompilationTrace; import com.enonic.cms.core.portal.livetrace.XsltCompilationTracer; import com.enonic.cms.core.resource.FileResourceName; import com.enonic.cms.core.resource.FileResourceService; import com.enonic.cms.core.xslt.XsltProcessorException; import com.enonic.cms.core.xslt.base.SaxonXsltProcessorFactory; import com.enonic.cms.core.xslt.functions.portal.PortalXsltFunctionLibrary; import com.enonic.cms.core.xslt.lib.PortalFunctionsMediator; @Component public final class PortalXsltProcessorFactoryImpl extends SaxonXsltProcessorFactory implements PortalXsltProcessorFactory, InitializingBean { private XsltResourceLoader resourceLoader; private XsltTemplatesCache templatesCache; private FileResourceService resourceService; private CacheFacade cacheFacade; private long checkInterval = 5000; private LivePortalTraceService livePortalTraceService; private static final Logger LOG = LoggerFactory.getLogger( PortalXsltProcessorFactory.class ); private static GenericConcurrencyLock<String> concurrencyLock = GenericConcurrencyLock.create(); @Autowired public void setPortalFunctions( final PortalFunctionsMediator portalFunctions ) { addFunctionLibrary( new PortalXsltFunctionLibrary( portalFunctions ) ); } @Override public PortalXsltProcessor createProcessor( final FileResourceName name ) throws XsltProcessorException { final XsltCompilationTrace trace = XsltCompilationTracer.startTracing( livePortalTraceService, name.toString() ); final XsltTrackingUriResolver uriResolver = new XsltTrackingUriResolver( this.resourceLoader ); final XsltTemplatesCacheEntry templates = compileTemplates( name, uriResolver, trace ); final Transformer transformer = createTransformer( templates, uriResolver ); XsltCompilationTracer.stopTracing( trace, livePortalTraceService ); return new PortalXsltProcessorImpl( transformer ); } private XsltTemplatesCacheEntry compileTemplates( final FileResourceName name, final XsltTrackingUriResolver resolver, final XsltCompilationTrace trace ) throws XsltProcessorException { XsltTemplatesCacheEntry entry = this.templatesCache.get( name ); if ( entry != null ) { XsltCompilationTracer.setCached( trace, true ); return entry; } final Lock locker = concurrencyLock.getLock( name.toString() ); try { XsltCompilationTracer.startConcurrencyBlockTimer( trace ); locker.lock(); XsltCompilationTracer.stopConcurrencyBlockTimer( trace ); entry = this.templatesCache.get( name ); if ( entry != null ) { XsltCompilationTracer.setCached( trace, true ); return entry; } final Source xsl = loadResource( name ); final Templates templates = compileTemplate( xsl, resolver ); entry = new XsltTemplatesCacheEntry( name, templates ); entry.addIncludes( resolver.getIncludes() ); this.templatesCache.put( entry ); XsltCompilationTracer.setCached( trace, false ); return entry; } finally { locker.unlock(); } } private Source loadResource( final FileResourceName name ) throws XsltProcessorException { try { return this.resourceLoader.load( name ); } catch ( final TransformerException e ) { throw new XsltProcessorException( e ); } } @Autowired public void setResourceService( final FileResourceService resourceService ) { this.resourceService = resourceService; } @Autowired public void setCacheManager( final CacheManager cacheManager ) { this.cacheFacade = cacheManager.getXsltCache(); } @Value("${cms.cache.xslt.checkInterval}") public void setCheckInterval( final long checkInterval ) { this.checkInterval = checkInterval; } @Autowired public void setLivePortalTraceService( final LivePortalTraceService livePortalTraceService ) { this.livePortalTraceService = livePortalTraceService; } @Override public void afterPropertiesSet() { this.templatesCache = new XsltTemplatesCache( this.cacheFacade, this.resourceService, this.checkInterval ); this.resourceLoader = new XsltResourceLoader( this.resourceService ); } }