/* * Copyright (c) 2008. All rights reserved. */ package ro.isdc.wro.manager.factory; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ro.isdc.wro.WroRuntimeException; import ro.isdc.wro.cache.CacheKey; import ro.isdc.wro.cache.CacheStrategy; import ro.isdc.wro.cache.CacheValue; import ro.isdc.wro.cache.factory.CacheKeyFactory; import ro.isdc.wro.cache.factory.DefaultCacheKeyFactory; import ro.isdc.wro.cache.impl.LruMemoryCacheStrategy; import ro.isdc.wro.config.metadata.DefaultMetaDataFactory; import ro.isdc.wro.config.metadata.MetaDataFactory; import ro.isdc.wro.manager.WroManager; import ro.isdc.wro.model.WroModel; import ro.isdc.wro.model.factory.WroModelFactory; import ro.isdc.wro.model.factory.XmlModelFactory; import ro.isdc.wro.model.group.DefaultGroupExtractor; import ro.isdc.wro.model.group.GroupExtractor; import ro.isdc.wro.model.group.processor.Injector; import ro.isdc.wro.model.resource.locator.factory.DefaultUriLocatorFactory; import ro.isdc.wro.model.resource.locator.factory.UriLocatorFactory; import ro.isdc.wro.model.resource.processor.factory.DefaultProcessorsFactory; import ro.isdc.wro.model.resource.processor.factory.ProcessorsFactory; import ro.isdc.wro.model.resource.support.DefaultResourceAuthorizationManager; import ro.isdc.wro.model.resource.support.ResourceAuthorizationManager; import ro.isdc.wro.model.resource.support.change.ResourceWatcher; import ro.isdc.wro.model.resource.support.hash.HashStrategy; import ro.isdc.wro.model.resource.support.hash.SHA1HashStrategy; import ro.isdc.wro.model.resource.support.naming.NamingStrategy; import ro.isdc.wro.model.resource.support.naming.NoOpNamingStrategy; import ro.isdc.wro.util.DestroyableLazyInitializer; import ro.isdc.wro.util.Transformer; /** * Default implementation of {@link WroManagerFactory} which creates default locators and processors and handles the * injection logic by creating an {@link Injector} and injecting where it is appropriate. * * @author Alex Objelean * @created Created on Dec 30, 2009 */ public class BaseWroManagerFactory implements WroManagerFactory { private static final Logger LOG = LoggerFactory.getLogger(BaseWroManagerFactory.class); private GroupExtractor groupExtractor; private WroModelFactory modelFactory; private CacheStrategy<CacheKey, CacheValue> cacheStrategy; private HashStrategy hashStrategy; /** * A list of model transformers. Allows manager to mutate the model before it is being parsed and processed. */ private List<Transformer<WroModel>> modelTransformers; private UriLocatorFactory uriLocatorFactory; private ProcessorsFactory processorsFactory; private NamingStrategy namingStrategy; private ResourceAuthorizationManager authorizationManager; private CacheKeyFactory cacheKeyFactory; private MetaDataFactory metaDataFactory; private ResourceWatcher resourceWatcher; /** * Handles the lazy synchronized creation of the manager */ private final DestroyableLazyInitializer<WroManager> managerInitializer = new DestroyableLazyInitializer<WroManager>() { @Override protected WroManager initialize() { final WroManager.Builder managerBuilder = new WroManager.Builder(); if (modelFactory == null) { modelFactory = newModelFactory(); } if (groupExtractor == null) { groupExtractor = newGroupExtractor(); } if (cacheStrategy == null) { cacheStrategy = newCacheStrategy(); } if (hashStrategy == null) { hashStrategy = newHashStrategy(); } if (modelTransformers == null) { modelTransformers = newModelTransformers(); } if (processorsFactory == null) { processorsFactory = newProcessorsFactory(); } if (uriLocatorFactory == null) { uriLocatorFactory = newUriLocatorFactory(); } // use NoOp as default naming strategy if (namingStrategy == null) { namingStrategy = newNamingStrategy(); } if (authorizationManager == null) { authorizationManager = newAuthorizationManager(); } if (cacheKeyFactory == null) { cacheKeyFactory = newCacheKeyFactory(); } if (metaDataFactory == null) { metaDataFactory = newMetaDataFactory(); } if (groupExtractor != null) { managerBuilder.setGroupExtractor(groupExtractor); } if (cacheStrategy != null) { managerBuilder.setCacheStrategy(cacheStrategy); } if (hashStrategy != null) { managerBuilder.setHashStrategy(hashStrategy); } if (uriLocatorFactory != null) { managerBuilder.setLocatorFactory(uriLocatorFactory); } if (processorsFactory != null) { managerBuilder.setProcessorsFactory(processorsFactory); } if (namingStrategy != null) { managerBuilder.setNamingStrategy(namingStrategy); } if (modelTransformers != null) { managerBuilder.setModelTransformers(modelTransformers); } if (modelFactory != null) { managerBuilder.setModelFactory(modelFactory); } if (authorizationManager != null) { managerBuilder.setAuthorizationManager(authorizationManager); } if (cacheKeyFactory != null) { managerBuilder.setCacheKeyFactory(cacheKeyFactory); } if (metaDataFactory != null) { managerBuilder.setMetaDataFactory(metaDataFactory); } if (resourceWatcher == null) { resourceWatcher = new ResourceWatcher(); } final WroManager manager = managerBuilder.build(); onAfterInitializeManager(manager); return manager; } }; /** * Creates default singleton instance of manager, by initializing manager dependencies with default values * (processors). */ public final WroManager create() { return managerInitializer.get(); } /** * @return default implementation of {@link ResourceAuthorizationManager}. */ protected ResourceAuthorizationManager newAuthorizationManager() { return new DefaultResourceAuthorizationManager(); } /** * Allows factory to do additional manager configuration after it was initialzed. One use-case is to configure * callbacks. Default implementation does nothing. Do not set anything else except callbacks in this method, otherwise * the initialization will not be performed properly. * * @param manager * initialized instance of {@link WroManager}. */ protected void onAfterInitializeManager(final WroManager manager) { } /** * @param namingStrategy * the namingStrategy to set */ public BaseWroManagerFactory setNamingStrategy(final NamingStrategy namingStrategy) { this.namingStrategy = namingStrategy; return this; } /** * @return default implementation of modelTransformers. */ protected List<Transformer<WroModel>> newModelTransformers() { return this.modelTransformers; } /** * Override to provide a different or modified default factory implementation. * * @return {@link ProcessorsFactory} object. */ protected ProcessorsFactory newProcessorsFactory() { return new DefaultProcessorsFactory(); } /** * Override to provide a different or modified factory. * * @return {@link UriLocatorFactory} object. */ protected UriLocatorFactory newUriLocatorFactory() { return new DefaultUriLocatorFactory(); } /** * @return {@link HashStrategy} instance. */ protected HashStrategy newHashStrategy() { return new SHA1HashStrategy(); } /** * @return default {@link NamingStrategy} to be used by this {@link WroManagerFactory} */ protected NamingStrategy newNamingStrategy() { return new NoOpNamingStrategy(); } /** * {@inheritDoc} */ public void onCachePeriodChanged(final long period) { try { managerInitializer.get().onCachePeriodChanged(period); } catch (final WroRuntimeException e) { LOG.warn("[FAIL] Unable to reload cache, probably because invoked outside of context"); } } /** * {@inheritDoc} */ public void onModelPeriodChanged(final long period) { try { managerInitializer.get().onModelPeriodChanged(period); } catch (final WroRuntimeException e) { LOG.warn("[FAIL] Unable to reload model, probably because invoked outside of context"); } } /** * @return {@link CacheStrategy} instance for resources' group caching. */ protected CacheStrategy<CacheKey, CacheValue> newCacheStrategy() { return new LruMemoryCacheStrategy<CacheKey, CacheValue>(); } /** * @return {@link GroupExtractor} implementation. */ protected GroupExtractor newGroupExtractor() { return new DefaultGroupExtractor(); } /** * @return default implementation of {@link CacheKeyFactory}. */ protected CacheKeyFactory newCacheKeyFactory() { return new DefaultCacheKeyFactory(); } /** * @param servletContext * {@link ServletContext} which could be useful for creating dynamic {@link WroModel}. * @return {@link WroModelFactory} implementation */ protected WroModelFactory newModelFactory() { try { LOG.debug("Trying to use SmartWroModelFactory as default model factory"); final Class<? extends WroModelFactory> smartFactoryClass = Class.forName( "ro.isdc.wro.extensions.model.factory.SmartWroModelFactory").asSubclass(WroModelFactory.class); return smartFactoryClass.newInstance(); } catch (final Exception e) { LOG.debug("SmartWroModelFactory is not available. Using default model factory."); LOG.debug("Reason: {}", e.getMessage()); } return new XmlModelFactory(); } /** * @return default implementation of {@link MetaDataFactory} used when no {@link MetaDataFactory} is set. */ protected MetaDataFactory newMetaDataFactory() { return new DefaultMetaDataFactory(); } /** * @param groupExtractor * the groupExtractor to set */ public BaseWroManagerFactory setGroupExtractor(final GroupExtractor groupExtractor) { this.groupExtractor = groupExtractor; return this; } /** * @param modelFactory * the modelFactory to set */ public BaseWroManagerFactory setModelFactory(final WroModelFactory modelFactory) { this.modelFactory = modelFactory; return this; } /** * @param hashBuilder * the hashBuilder to set */ public BaseWroManagerFactory setHashStrategy(final HashStrategy hashStrategy) { this.hashStrategy = hashStrategy; return this; } public void setCacheKeyFactory(final CacheKeyFactory cacheKeyFactory) { this.cacheKeyFactory = cacheKeyFactory; } /** * @param modelTransformers * the modelTransformers to set */ public BaseWroManagerFactory setModelTransformers(final List<Transformer<WroModel>> modelTransformers) { this.modelTransformers = modelTransformers; return this; } /** * Add a single model transformer. */ public BaseWroManagerFactory addModelTransformer(final Transformer<WroModel> modelTransformer) { if (modelTransformers == null) { modelTransformers = new ArrayList<Transformer<WroModel>>(); } this.modelTransformers.add(modelTransformer); return this; } /** * @param cacheStrategy * the cacheStrategy to set */ public BaseWroManagerFactory setCacheStrategy(final CacheStrategy<CacheKey, CacheValue> cacheStrategy) { this.cacheStrategy = cacheStrategy; return this; } /** * @param uriLocatorFactory * the uriLocatorFactory to set */ public BaseWroManagerFactory setUriLocatorFactory(final UriLocatorFactory uriLocatorFactory) { this.uriLocatorFactory = uriLocatorFactory; return this; } /** * @param processorsFactory * the processorsFactory to set */ public BaseWroManagerFactory setProcessorsFactory(final ProcessorsFactory processorsFactory) { this.processorsFactory = processorsFactory; return this; } public BaseWroManagerFactory setResourceAuthorizationManager(final ResourceAuthorizationManager authorizationManager) { this.authorizationManager = authorizationManager; return this; } public void setMetaDataFactory(final MetaDataFactory metaDataFactory) { this.metaDataFactory = metaDataFactory; } public BaseWroManagerFactory setResourceWatcher(final ResourceWatcher resourceWatcher) { this.resourceWatcher = resourceWatcher; return this; } /** * {@inheritDoc} */ public void destroy() { managerInitializer.destroy(); } }