/*
* 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();
}
}