Merged 5.2.N (5.2.1) to HEAD (5.2)

128607 mmuller: Fixed some more javadoc errors after reviewing. REPO-466


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@129298 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alexandru Epure
2016-08-09 14:06:08 +00:00
parent 401e679fb8
commit a91104fd15

View File

@@ -25,423 +25,845 @@
*/ */
package org.alfresco.repo.web.scripts; package org.alfresco.repo.web.scripts;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.dom4j.Element; import org.dom4j.Element;
import org.springframework.extensions.config.ConfigImpl; import org.springframework.extensions.config.ConfigImpl;
import org.springframework.extensions.config.ConfigSection; import org.springframework.extensions.config.ConfigSection;
import org.springframework.extensions.config.ConfigService; import org.springframework.extensions.config.ConfigService;
import org.springframework.extensions.config.evaluator.Evaluator; import org.springframework.extensions.config.evaluator.Evaluator;
import org.springframework.extensions.config.xml.XMLConfigService; import org.springframework.extensions.config.xml.XMLConfigService;
import org.springframework.extensions.config.xml.elementreader.ConfigElementReader; import org.springframework.extensions.config.xml.elementreader.ConfigElementReader;
import org.springframework.extensions.surf.extensibility.BasicExtensionModule; import org.springframework.extensions.surf.extensibility.BasicExtensionModule;
import org.springframework.extensions.surf.extensibility.ExtensibilityModel; import org.springframework.extensions.surf.extensibility.ExtensibilityModel;
import org.springframework.extensions.surf.extensibility.HandlesExtensibility; import org.springframework.extensions.surf.extensibility.HandlesExtensibility;
import org.springframework.extensions.surf.extensibility.WebScriptExtensibilityModuleHandler; import org.springframework.extensions.surf.extensibility.WebScriptExtensibilityModuleHandler;
import org.springframework.extensions.surf.extensibility.impl.ExtensibilityModelImpl; import org.springframework.extensions.surf.extensibility.impl.ExtensibilityModelImpl;
import org.springframework.extensions.surf.extensibility.impl.MarkupDirective; import org.springframework.extensions.surf.extensibility.impl.MarkupDirective;
import org.springframework.extensions.webscripts.Authenticator; import org.springframework.extensions.webscripts.Authenticator;
import org.springframework.extensions.webscripts.ExtendedScriptConfigModel; import org.springframework.extensions.webscripts.ExtendedScriptConfigModel;
import org.springframework.extensions.webscripts.ExtendedTemplateConfigModel; import org.springframework.extensions.webscripts.ExtendedTemplateConfigModel;
import org.springframework.extensions.webscripts.ScriptConfigModel; import org.springframework.extensions.webscripts.ScriptConfigModel;
import org.springframework.extensions.webscripts.TemplateConfigModel; import org.springframework.extensions.webscripts.TemplateConfigModel;
import org.springframework.extensions.webscripts.WebScriptPropertyResourceBundle; import org.springframework.extensions.webscripts.WebScriptPropertyResourceBundle;
import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse; import org.springframework.extensions.webscripts.WebScriptResponse;
/** /**
* <p>A simple extensibility {@link org.springframework.extensions.webscripts.Container} for processing WebScripts. This extends the {@link RepositoryContainer} and * <p>A simple extensibility {@link org.springframework.extensions.webscripts.Container} for processing WebScripts. This extends the {@link RepositoryContainer} and
* implements the {@link HandlesExtensibility} interface to provide extensibility capabilities.</p> * implements the {@link HandlesExtensibility} interface to provide extensibility capabilities.</p>
* *
* @author David Draper * @author David Draper
*/ */
public class ExtensibilityContainer extends RepositoryContainer implements HandlesExtensibility public class ExtensibilityContainer extends RepositoryContainer implements HandlesExtensibility
{ {
private static final Log logger = LogFactory.getLog(ExtensibilityContainer.class); private static final Log logger = LogFactory.getLog(ExtensibilityContainer.class);
public boolean isExtensibilitySuppressed() public boolean isExtensibilitySuppressed()
{ {
return false; return false;
} }
/** /**
* <p>Opens a new {@link ExtensibilityModel}, defers execution to the extended {@link RepositoryContainer} and * <p>Opens a new {@link ExtensibilityModel}, defers execution to the extended {@link RepositoryContainer} and
* then closes the {@link ExtensibilityModel}.</p> * then closes the {@link ExtensibilityModel}.</p>
*/ */
@Override @Override
public void executeScript(WebScriptRequest scriptReq, public void executeScript(WebScriptRequest scriptReq,
WebScriptResponse scriptRes, WebScriptResponse scriptRes,
Authenticator auth) throws IOException Authenticator auth) throws IOException
{ {
ExtensibilityModel extModel = this.openExtensibilityModel(); ExtensibilityModel extModel = this.openExtensibilityModel();
try try
{ {
super.executeScript(scriptReq, scriptRes, auth); super.executeScript(scriptReq, scriptRes, auth);
}
finally
{
// It's only necessary to close the model if it's actually been used. Not all WebScripts will make use of the
// model. An example of this would be the StreamContent WebScript. It is important not to attempt to close
// an unused model since the WebScript executed may have already flushed the response if it has overridden
// the default .execute() method.
if (this.modelUsed.get())
{
try
{
this.closeExtensibilityModel(extModel, scriptRes.getWriter());
}
catch (IOException e)
{
logger.error("An error occurred getting the Writer when closing an ExtensibilityModel", e);
}
}
}
} }
finally
{
// It's only necessary to close the model if it's actually been used. Not all WebScripts will make use of the
// model. An example of this would be the StreamContent WebScript. It is important not to attempt to close
// an unused model since the WebScript executed may have already flushed the response if it has overridden
// the default .execute() method.
if (this.modelUsed.get())
{
try
{
this.closeExtensibilityModel(extModel, scriptRes.getWriter());
}
catch (IOException e)
{
logger.error("An error occurred getting the Writer when closing an ExtensibilityModel", e);
}
}
}
}
/** /**
* <p>This keeps track of whether or not the {@link ExtensibilityModel} for the current thread has been used. The * <p>This keeps track of whether or not the {@link ExtensibilityModel} for the current thread has been used. The
* thread local value will only be set to <code>true</code> if the <code>getCurrentExtensibilityModel</code> method * thread local value will only be set to <code>true</code> if the <code>getCurrentExtensibilityModel</code> method
* is called.</p> * is called.</p>
*/ */
private ThreadLocal<Boolean> modelUsed = new ThreadLocal<Boolean>(); private ThreadLocal<Boolean> modelUsed = new ThreadLocal<Boolean>();
/** /**
* <p>A {@link WebScriptExtensibilityModuleHandler} is required for retrieving information on what * <p>A {@link WebScriptExtensibilityModuleHandler} is required for retrieving information on what
* {@link BasicExtensionModule} instances have been configured and the extension files that need * {@link BasicExtensionModule} instances have been configured and the extension files that need
* to be processed. This variable should be set thorugh the Spring application context configuration.</p> * to be processed. This variable should be set thorugh the Spring application context configuration.</p>
*/ */
private WebScriptExtensibilityModuleHandler extensibilityModuleHandler = null; private WebScriptExtensibilityModuleHandler extensibilityModuleHandler = null;
/**
* <p>Sets the {@link WebScriptExtensibilityModuleHandler} for this {@link org.springframework.extensions.webscripts.Container}.</p>
* @param extensibilityModuleHandler WebScriptExtensibilityModuleHandler
*/
public void setExtensibilityModuleHandler(WebScriptExtensibilityModuleHandler extensibilityModuleHandler)
{
this.extensibilityModuleHandler = extensibilityModuleHandler;
}
/** /**
* <p>Maintains a list of all the {@link ExtensibilityModel} instances being used across all the
* available threads.</p> * <p>Sets the {@link WebScriptExtensibilityModuleHandler} for this {@link org.springframework.extensions.webscripts.Container}.</p>
* @param extensibilityModuleHandler WebScriptExtensibilityModuleHandler
*/ */
public void setExtensibilityModuleHandler(WebScriptExtensibilityModuleHandler extensibilityModuleHandler)
{
this.extensibilityModuleHandler = extensibilityModuleHandler;
}
/**
* <p>Maintains a list of all the {@link ExtensibilityModel} instances being used across all the
* available threads.</p>
*/
private ThreadLocal<ExtensibilityModel> extensibilityModel = new ThreadLocal<ExtensibilityModel>(); private ThreadLocal<ExtensibilityModel> extensibilityModel = new ThreadLocal<ExtensibilityModel>();
/** /**
* <p>Creates a new {@link ExtensibilityModel} and sets it on the current thread
* <p>Creates a new {@link ExtensibilityModel} and sets it on the current thread</p>
*/ */
public ExtensibilityModel openExtensibilityModel() public ExtensibilityModel openExtensibilityModel()
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Opening for thread: " + Thread.currentThread().getName()); logger.debug("Opening for thread: " + Thread.currentThread().getName());
} }
this.extendedBundleCache.set(new HashMap<String, WebScriptPropertyResourceBundle>()); this.extendedBundleCache.set(new HashMap<String, WebScriptPropertyResourceBundle>());
this.evaluatedModules.set(null); this.evaluatedModules.set(null);
this.fileBeingProcessed.set(null); this.fileBeingProcessed.set(null);
this.globalConfig.set(null); this.globalConfig.set(null);
this.sections.set(null); this.sections.set(null);
this.sectionsByArea.set(null); this.sectionsByArea.set(null);
ExtensibilityModel model = new ExtensibilityModelImpl(null, this); ExtensibilityModel model = new ExtensibilityModelImpl(null, this);
this.extensibilityModel.set(model); this.extensibilityModel.set(model);
this.modelUsed.set(Boolean.FALSE); this.modelUsed.set(Boolean.FALSE);
return model; return model;
} }
/** /**
* <p>Flushes the {@link ExtensibilityModel} provided and sets its parent as the current {@link ExtensibilityModel} * <p>Flushes the {@link ExtensibilityModel} provided and sets its parent as the current {@link ExtensibilityModel}
* for the current thread.<p>
* for the current thread.</p>
*/ */
public void closeExtensibilityModel(ExtensibilityModel model, Writer out) public void closeExtensibilityModel(ExtensibilityModel model, Writer out)
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Closing for thread: " + Thread.currentThread().getName()); logger.debug("Closing for thread: " + Thread.currentThread().getName());
} }
model.flushModel(out); model.flushModel(out);
this.modelUsed.set(Boolean.FALSE); this.modelUsed.set(Boolean.FALSE);
this.extensibilityModel.set(null); this.extensibilityModel.set(null);
} }
/** /**
* <p>Returns the {@link ExtensibilityModel} for the current thread.</p> * <p>Returns the {@link ExtensibilityModel} for the current thread.</p>
*/ */
public ExtensibilityModel getCurrentExtensibilityModel() public ExtensibilityModel getCurrentExtensibilityModel()
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Getting current for thread: " + Thread.currentThread().getName()); logger.debug("Getting current for thread: " + Thread.currentThread().getName());
} }
this.modelUsed.set(Boolean.TRUE); this.modelUsed.set(Boolean.TRUE);
return this.extensibilityModel.get(); return this.extensibilityModel.get();
} }
/** /**
* <p>This method is implemented to perform no action as it is not necessary for a standalone WebScript * <p>This method is implemented to perform no action as it is not necessary for a standalone WebScript
* container to add dependencies for processing.</p> * container to add dependencies for processing.</p>
*/ */
public void updateExtendingModuleDependencies(String pathBeingProcessed, Map<String, Object> model) public void updateExtendingModuleDependencies(String pathBeingProcessed, Map<String, Object> model)
{ {
// NOT REQUIRED FOR STANDALONE WEBSCRIPT CONTAINER // NOT REQUIRED FOR STANDALONE WEBSCRIPT CONTAINER
} }
/** /**
* <p>A thread-safe cache of extended {@link ResourceBundle} instances for the current request.</p> * <p>A thread-safe cache of extended {@link ResourceBundle} instances for the current request.</p>
*/ */
private ThreadLocal<Map<String, WebScriptPropertyResourceBundle>> extendedBundleCache = new ThreadLocal<Map<String, WebScriptPropertyResourceBundle>>(); private ThreadLocal<Map<String, WebScriptPropertyResourceBundle>> extendedBundleCache = new ThreadLocal<Map<String, WebScriptPropertyResourceBundle>>();
/** /**
* <p>Checks the cache to see if it has cached an extended bundle (that is a basic {@link ResourceBundle} that * <p>Checks the cache to see if it has cached an extended bundle (that is a basic {@link ResourceBundle} that
* has had extension modules applied to it. Extended bundles can only be safely cached once per request as the modules * has had extension modules applied to it. Extended bundles can only be safely cached once per request as the modules
* applied can vary for each request.</p> * applied can vary for each request.</p>
* *
* @param webScriptId The id of the WebScript to retrieve the extended bundle for. * @param webScriptId The id of the WebScript to retrieve the extended bundle for.
* @return A cached bundle or <code>null</code> if the bundle has not previously been cached. * @return A cached bundle or <code>null</code> if the bundle has not previously been cached.
*/ */
public ResourceBundle getCachedExtendedBundle(String webScriptId) public ResourceBundle getCachedExtendedBundle(String webScriptId)
{ {
ResourceBundle cachedExtendedBundle = null; ResourceBundle cachedExtendedBundle = null;
Map<String, WebScriptPropertyResourceBundle> threadLocal = this.extendedBundleCache.get(); Map<String, WebScriptPropertyResourceBundle> threadLocal = this.extendedBundleCache.get();
if (threadLocal != null) if (threadLocal != null)
{ {
cachedExtendedBundle = this.extendedBundleCache.get().get(webScriptId); cachedExtendedBundle = this.extendedBundleCache.get().get(webScriptId);
} }
return cachedExtendedBundle; return cachedExtendedBundle;
} }
/** /**
* <p>Adds a new extended bundle to the cache. An extended bundle is a WebScript {@link ResourceBundle} that has had * <p>Adds a new extended bundle to the cache. An extended bundle is a WebScript {@link ResourceBundle} that has had
* {@link ResourceBundle} instances merged into it from extension modules that have been applied. These can only be cached * {@link ResourceBundle} instances merged into it from extension modules that have been applied. These can only be cached
* for the lifetime of the request as different modules may be applied to the same WebScript for different requests.</p> * for the lifetime of the request as different modules may be applied to the same WebScript for different requests.</p>
* *
* @param webScriptId The id of the WebScript to cache the extended bundle against. * @param webScriptId The id of the WebScript to cache the extended bundle against.
* @param extensionBundle The extended bundle to cache. * @param extensionBundle The extended bundle to cache.
*/ */
public void addExtensionBundleToCache(String webScriptId, WebScriptPropertyResourceBundle extensionBundle) public void addExtensionBundleToCache(String webScriptId, WebScriptPropertyResourceBundle extensionBundle)
{ {
Map<String, WebScriptPropertyResourceBundle> threadLocal = this.extendedBundleCache.get(); Map<String, WebScriptPropertyResourceBundle> threadLocal = this.extendedBundleCache.get();
if (threadLocal == null) if (threadLocal == null)
{ {
// This should never be the case because when a new model is opened this value should be reset // This should never be the case because when a new model is opened this value should be reset
// but we will double-check to avoid the potential of NPEs... // but we will double-check to avoid the potential of NPEs...
threadLocal = new HashMap<String, WebScriptPropertyResourceBundle>(); threadLocal = new HashMap<String, WebScriptPropertyResourceBundle>();
this.extendedBundleCache.set(threadLocal); this.extendedBundleCache.set(threadLocal);
}
threadLocal.put(webScriptId, extensionBundle);
} }
threadLocal.put(webScriptId, extensionBundle);
}
/** /**
* <p>A {@link ThreadLocal} reference to the file currently being processed in the model.
* <p>A {@link ThreadLocal} reference to the file currently being processed in the model.</p>
*/ */
private ThreadLocal<String> fileBeingProcessed = new ThreadLocal<String>(); private ThreadLocal<String> fileBeingProcessed = new ThreadLocal<String>();
/** /**
* <p>Returns the path of the file currently being processed in the model by the current thread. * <p>Returns the path of the file currently being processed in the model by the current thread.
* This information is primarily provided for the purposes of generating debug information.</p> * This information is primarily provided for the purposes of generating debug information.</p>
* *
* @return The path of the file currently being processed. * @return The path of the file currently being processed.
*/ */
public String getFileBeingProcessed() public String getFileBeingProcessed()
{ {
return this.fileBeingProcessed.get(); return this.fileBeingProcessed.get();
} }
/** /**
* <p>Sets the path of the file currently being processed in the model by the current thread. * <p>Sets the path of the file currently being processed in the model by the current thread.
* This information should be collected to assist with providing debug information.</p> * This information should be collected to assist with providing debug information.</p>
* @param file The path of the file currently being processed. * @param file The path of the file currently being processed.
*/ */
public void setFileBeingProcessed(String file) public void setFileBeingProcessed(String file)
{ {
this.fileBeingProcessed.set(file); this.fileBeingProcessed.set(file);
} }
/** /**
* <p>Retrieves an files for the evaluated modules that are extending the WebScript files being processed.</p> * <p>Retrieves an files for the evaluated modules that are extending the WebScript files being processed.</p>
*/ */
public List<String> getExtendingModuleFiles(String pathBeingProcessed) public List<String> getExtendingModuleFiles(String pathBeingProcessed)
{ {
List<String> extendingModuleFiles = new ArrayList<String>(); List<String> extendingModuleFiles = new ArrayList<String>();
for (BasicExtensionModule module: this.getEvaluatedModules()) for (BasicExtensionModule module: this.getEvaluatedModules())
{ {
extendingModuleFiles.addAll(this.extensibilityModuleHandler.getExtendingModuleFiles(module, pathBeingProcessed)); extendingModuleFiles.addAll(this.extensibilityModuleHandler.getExtendingModuleFiles(module, pathBeingProcessed));
}
return extendingModuleFiles;
} }
return extendingModuleFiles;
}
/** /**
* <p>The list of {@link org.springframework.extensions.surf.types.ExtensionModule} instances that have been evaluated as applicable to * <p>The list of {@link org.springframework.extensions.surf.types.ExtensionModule} instances that have been evaluated as applicable to
* this RequestContext. This is set to <code>null</code> when during instantiation and is only * this RequestContext. This is set to <code>null</code> when during instantiation and is only
* properly set the first time the <code>getEvaluatedModules</code> method is invoked. This ensures * properly set the first time the <code>getEvaluatedModules</code> method is invoked. This ensures
* that module evaluation only occurs once per request.</p> * that module evaluation only occurs once per request.</p>
*/ */
private ThreadLocal<List<BasicExtensionModule>> evaluatedModules = new ThreadLocal<List<BasicExtensionModule>>(); private ThreadLocal<List<BasicExtensionModule>> evaluatedModules = new ThreadLocal<List<BasicExtensionModule>>();
/**
* <p>Retrieve the list of {@link org.springframework.extensions.surf.types.ExtensionModule} instances that have been evaluated as applicable
* for the current request. If this list has not yet been populated then use the {@link org.springframework.extensions.surf.extensibility.ExtensibilityModuleHandler}
* configured in the Spring application context to evaluate them.</p>
*
* @return A list of {@link org.springframework.extensions.surf.types.ExtensionModule} instances that are applicable to the current request.
*/
public List<BasicExtensionModule> getEvaluatedModules()
{
List<BasicExtensionModule> evaluatedModules = this.evaluatedModules.get();
if (evaluatedModules == null)
{
if (this.extensibilityModuleHandler == null)
{
if (logger.isErrorEnabled())
{
logger.error("No 'extensibilityModuleHandler' has been configured for this request context. Extensions cannot be processed");
}
evaluatedModules = new ArrayList<BasicExtensionModule>();
this.evaluatedModules.set(evaluatedModules);
}
else
{
evaluatedModules = this.extensibilityModuleHandler.getExtensionModules();
this.evaluatedModules.set(evaluatedModules);
}
}
return evaluatedModules;
}
/** /**
* <p>This is a local {@link ConfigImpl} instance that will only be used when extension modules are employed. It will
* initially be populated with the default "static" global configuration taken from the {@link ConfigService} associated * <p>Retrieve the list of {@link org.springframework.extensions.surf.types.ExtensionModule} instances that have been evaluated as applicable
* with this {@link org.springframework.extensions.surf.RequestContext} but then updated to include global configuration provided by extension modules that
* have been evaluated to be applied to the current request.</p> * for the current request. If this list has not yet been populated then use the {@link org.springframework.extensions.surf.extensibility.ExtensibilityModuleHandler}
* configured in the Spring application context to evaluate them.</p>
*
* @return A list of {@link org.springframework.extensions.surf.types.ExtensionModule} instances that are applicable to the current request.
*/ */
public List<BasicExtensionModule> getEvaluatedModules()
{
List<BasicExtensionModule> evaluatedModules = this.evaluatedModules.get();
if (evaluatedModules == null)
{
if (this.extensibilityModuleHandler == null)
{
if (logger.isErrorEnabled())
{
logger.error("No 'extensibilityModuleHandler' has been configured for this request context. Extensions cannot be processed");
}
evaluatedModules = new ArrayList<BasicExtensionModule>();
this.evaluatedModules.set(evaluatedModules);
}
else
{
evaluatedModules = this.extensibilityModuleHandler.getExtensionModules();
this.evaluatedModules.set(evaluatedModules);
}
}
return evaluatedModules;
}
/**
* <p>This is a local {@link ConfigImpl} instance that will only be used when extension modules are employed. It will
* initially be populated with the default "static" global configuration taken from the {@link ConfigService} associated
* with this {@link org.springframework.extensions.surf.RequestContext} but then updated to include global configuration provided by extension modules that
* have been evaluated to be applied to the current request.</p>
*/
private ThreadLocal<ConfigImpl> globalConfig = new ThreadLocal<ConfigImpl>(); private ThreadLocal<ConfigImpl> globalConfig = new ThreadLocal<ConfigImpl>();
/** /**
* <p>This map represents {@link ConfigSection} instances mapped by area. It will only be used when extension modules are * <p>This map represents {@link ConfigSection} instances mapped by area. It will only be used when extension modules are
* employed. It will initially be populated with the default "static" configuration taken from the {@link ConfigService} associated * employed. It will initially be populated with the default "static" configuration taken from the {@link ConfigService} associated
* with this {@link org.springframework.extensions.surf.RequestContext} but then updated to include configuration provided by extension modules that have been evaluated * with this {@link org.springframework.extensions.surf.RequestContext} but then updated to include configuration provided by extension modules that have been evaluated
* to be applied to the current request.</p> * to be applied to the current request.</p>
*/ */
private ThreadLocal<Map<String, List<ConfigSection>>> sectionsByArea = new ThreadLocal<Map<String,List<ConfigSection>>>(); private ThreadLocal<Map<String, List<ConfigSection>>> sectionsByArea = new ThreadLocal<Map<String,List<ConfigSection>>>();
/** /**
* <p>A list of {@link ConfigSection} instances that are only applicable to the current request. It will only be used when extension modules are * <p>A list of {@link ConfigSection} instances that are only applicable to the current request. It will only be used when extension modules are
* employed. It will initially be populated with the default "static" configuration taken from the {@link ConfigService} associated * employed. It will initially be populated with the default "static" configuration taken from the {@link ConfigService} associated
* with this {@link org.springframework.extensions.surf.RequestContext} but then updated to include configuration provided by extension modules that have been evaluated * with this {@link org.springframework.extensions.surf.RequestContext} but then updated to include configuration provided by extension modules that have been evaluated
* to be applied to the current request.</p> * to be applied to the current request.</p>
*/ */
private ThreadLocal<List<ConfigSection>> sections = new ThreadLocal<List<ConfigSection>>(); private ThreadLocal<List<ConfigSection>> sections = new ThreadLocal<List<ConfigSection>>();
/** /**
* <p>Creates a new {@link ExtendedScriptConfigModel} instance using the local configuration generated for this request. * <p>Creates a new {@link ExtendedScriptConfigModel} instance using the local configuration generated for this request.
* If configuration for the request will be generated if it does not yet exist. It is likely that this method will be * If configuration for the request will be generated if it does not yet exist. It is likely that this method will be
* called multiple times within the context of a single request and although the configuration containers will always * called multiple times within the context of a single request and although the configuration containers will always
* be the same a new {@link ExtendedScriptConfigModel} instance will always be created as the the supplied <code>xmlConfig</code> * be the same a new {@link ExtendedScriptConfigModel} instance will always be created as the the supplied <code>xmlConfig</code>
* string could be different for each call (because each WebScript invoked in the request will supply different * string could be different for each call (because each WebScript invoked in the request will supply different
* configuration.</p> * configuration.</p>
*/ */
public ScriptConfigModel getExtendedScriptConfigModel(String xmlConfig) public ScriptConfigModel getExtendedScriptConfigModel(String xmlConfig)
{ {
if (this.globalConfig.get() == null && this.sectionsByArea.get() == null && this.sections.get() == null) if (this.globalConfig.get() == null && this.sectionsByArea.get() == null && this.sections.get() == null)
{ {
this.getConfigExtensions(); this.getConfigExtensions();
} }
return new ExtendedScriptConfigModel(getConfigService(), xmlConfig, this.globalConfig.get(), this.sectionsByArea.get(), this.sections.get()); return new ExtendedScriptConfigModel(getConfigService(), xmlConfig, this.globalConfig.get(), this.sectionsByArea.get(), this.sections.get());
} }
/** /**
* <p>Creates a new {@link TemplateConfigModel} instance using the local configuration generated for this request. * <p>Creates a new {@link TemplateConfigModel} instance using the local configuration generated for this request.
* If configuration for the request will be generated if it does not yet exist. It is likely that this method will be * If configuration for the request will be generated if it does not yet exist. It is likely that this method will be
* called multiple times within the context of a single request and although the configuration containers will always * called multiple times within the context of a single request and although the configuration containers will always
* be the same a new {@link TemplateConfigModel} instance will always be created as the the supplied <code>xmlConfig</code> * be the same a new {@link TemplateConfigModel} instance will always be created as the the supplied <code>xmlConfig</code>
* string could be different for each call (because each WebScript invoked in the request will supply different * string could be different for each call (because each WebScript invoked in the request will supply different
* configuration.</p> * configuration.</p>
*/ */
public TemplateConfigModel getExtendedTemplateConfigModel(String xmlConfig) public TemplateConfigModel getExtendedTemplateConfigModel(String xmlConfig)
{ {
if (this.globalConfig.get() == null && this.sectionsByArea.get() == null && this.sections.get() == null) if (this.globalConfig.get() == null && this.sectionsByArea.get() == null && this.sections.get() == null)
{ {
this.getConfigExtensions(); this.getConfigExtensions();
}
return new ExtendedTemplateConfigModel(getConfigService(), xmlConfig, this.globalConfig.get(), this.sectionsByArea.get(), this.sections.get());
} }
return new ExtendedTemplateConfigModel(getConfigService(), xmlConfig, this.globalConfig.get(), this.sectionsByArea.get(), this.sections.get());
}
/** /**
* <p>Creates and populates the request specific configuration container objects (<code>globalConfig</code>, <code>sectionsByArea</code> & * <p>Creates and populates the request specific configuration container objects (<code>globalConfig</code>, <code>sectionsByArea</code> &
* <code>sections</code> with a combination of the default static configuration (taken from files accessed by the {@link ConfigService}) and * <code>sections</code> with a combination of the default static configuration (taken from files accessed by the {@link ConfigService}) and
* dynamic configuration taken from extension modules evaluated for the current request. </p> * dynamic configuration taken from extension modules evaluated for the current request. </p>
*/ */
private void getConfigExtensions() private void getConfigExtensions()
{ {
// Extended configuration is only possible if config service is an XMLConfigService... // Extended configuration is only possible if config service is an XMLConfigService...
// //
// ...also, it's only necessary to populate the configuration containers if they have not already been populated. This test should also // ...also, it's only necessary to populate the configuration containers if they have not already been populated. This test should also
// be carried out by the two methods ("getExtendedTemplateConfigModel" & "getExtendedTemplateConfigModel") to prevent duplication // be carried out by the two methods ("getExtendedTemplateConfigModel" & "getExtendedTemplateConfigModel") to prevent duplication
// of effort... but in case other methods attempt to access it we will make these additional tests. // of effort... but in case other methods attempt to access it we will make these additional tests.
if (getConfigService() instanceof XMLConfigService && this.globalConfig == null && this.sectionsByArea == null && this.sections == null) if (getConfigService() instanceof XMLConfigService && this.globalConfig == null && this.sectionsByArea == null && this.sections == null)
{ {
// Cast the config service for ease of access // Cast the config service for ease of access
XMLConfigService xmlConfigService = (XMLConfigService) getConfigService(); XMLConfigService xmlConfigService = (XMLConfigService) getConfigService();
// Get the current configuration from the ConfigService - we don't want to permanently pollute // Get the current configuration from the ConfigService - we don't want to permanently pollute
// the standard configuration with additions from the modules... // the standard configuration with additions from the modules...
this.globalConfig.set(new ConfigImpl((ConfigImpl)xmlConfigService.getGlobalConfig())); // Make a copy of the current global config this.globalConfig.set(new ConfigImpl((ConfigImpl)xmlConfigService.getGlobalConfig())); // Make a copy of the current global config
// Initialise these with the config service values... // Initialise these with the config service values...
this.sectionsByArea.set(new HashMap<String, List<ConfigSection>>(xmlConfigService.getSectionsByArea())); this.sectionsByArea.set(new HashMap<String, List<ConfigSection>>(xmlConfigService.getSectionsByArea()));
this.sections.set(new ArrayList<ConfigSection>(xmlConfigService.getSections())); this.sections.set(new ArrayList<ConfigSection>(xmlConfigService.getSections()));
// Check to see if there are any modules that we need to apply... // Check to see if there are any modules that we need to apply...
List<BasicExtensionModule> evaluatedModules = this.getEvaluatedModules(); List<BasicExtensionModule> evaluatedModules = this.getEvaluatedModules();
if (evaluatedModules != null && !evaluatedModules.isEmpty()) if (evaluatedModules != null && !evaluatedModules.isEmpty())
{ {
for (BasicExtensionModule currModule: evaluatedModules) for (BasicExtensionModule currModule: evaluatedModules)
{ {
for (Element currentConfigElement: currModule.getConfigurations()) for (Element currentConfigElement: currModule.getConfigurations())
{ {
// Set up containers for our request specific configuration - this will contain data taken from the evaluated modules... // Set up containers for our request specific configuration - this will contain data taken from the evaluated modules...
Map<String, ConfigElementReader> parsedElementReaders = new HashMap<String, ConfigElementReader>(); Map<String, ConfigElementReader> parsedElementReaders = new HashMap<String, ConfigElementReader>();
Map<String, Evaluator> parsedEvaluators = new HashMap<String, Evaluator>(); Map<String, Evaluator> parsedEvaluators = new HashMap<String, Evaluator>();
List<ConfigSection> parsedConfigSections = new ArrayList<ConfigSection>(); List<ConfigSection> parsedConfigSections = new ArrayList<ConfigSection>();
// Parse and process the parses configuration... // Parse and process the parses configuration...
String currentArea = xmlConfigService.parseFragment(currentConfigElement, parsedElementReaders, parsedEvaluators, parsedConfigSections); String currentArea = xmlConfigService.parseFragment(currentConfigElement, parsedElementReaders, parsedEvaluators, parsedConfigSections);
for (Map.Entry<String, Evaluator> entry : parsedEvaluators.entrySet()) for (Map.Entry<String, Evaluator> entry : parsedEvaluators.entrySet())
{ {
// add the evaluators to the config service // add the evaluators to the config service
parsedEvaluators.put(entry.getKey(), entry.getValue()); parsedEvaluators.put(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, ConfigElementReader> entry : parsedElementReaders.entrySet())
{
// add the element readers to the config service
parsedElementReaders.put(entry.getKey(), entry.getValue());
}
for (ConfigSection section : parsedConfigSections)
{
// Update local configuration with our updated data...
xmlConfigService.addConfigSection(section, currentArea, this.globalConfig.get(), this.sectionsByArea.get(), this.sections.get());
}
}
}
}
}
} }
/** for (Map.Entry<String, ConfigElementReader> entry : parsedElementReaders.entrySet())
* <p>Adds the <{@code}@markup> directive to the container which allows FreeMarker templates to be extended.</p>
*/
public void addExtensibilityDirectives(Map<String, Object> freeMarkerModel, ExtensibilityModel extModel)
{ {
MarkupDirective mud = new MarkupDirective("markup", extModel);
freeMarkerModel.put("markup", mud); // add the element readers to the config service
parsedElementReaders.put(entry.getKey(), entry.getValue());
} }
for (ConfigSection section : parsedConfigSections)
{
// Update local configuration with our updated data...
xmlConfigService.addConfigSection(section, currentArea, this.globalConfig.get(), this.sectionsByArea.get(), this.sections.get());
}
}
}
}
}
}
/**
* <p>Adds the <{@code}@markup> directive to the container which allows FreeMarker templates to be extended.</p>
*/
public void addExtensibilityDirectives(Map<String, Object> freeMarkerModel, ExtensibilityModel extModel)
{
MarkupDirective mud = new MarkupDirective("markup", extModel);
freeMarkerModel.put("markup", mud);
}
} }