/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache Jetspeed" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache" or
* "Apache Jetspeed", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.jetspeed.services.template;
// java.io
import java.io.File;
// java.util
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Locale;
import javax.servlet.ServletConfig;
// turbine.util
import org.apache.turbine.util.Log;
import org.apache.turbine.util.RunData;
// turbine.services
import org.apache.turbine.services.TurbineBaseService;
import org.apache.turbine.services.TurbineServices;
import org.apache.turbine.services.InitializationException;
import org.apache.turbine.services.servlet.TurbineServlet;
import org.apache.turbine.services.jsp.JspService;
import org.apache.turbine.services.resources.TurbineResources;
import org.apache.turbine.services.template.BaseTemplateEngineService;
import org.apache.turbine.services.template.TurbineTemplate;
import org.apache.turbine.services.velocity.TurbineVelocity;
import org.apache.turbine.services.velocity.VelocityService;
import org.apache.turbine.services.localization.LocalizationService;
// jetspeed.capability
import org.apache.commons.configuration.Configuration;
import org.apache.jetspeed.capability.CapabilityMap;
// jetspeed.services
import org.apache.jetspeed.services.resources.JetspeedResources;
import org.apache.jetspeed.services.rundata.JetspeedRunData;
import org.apache.jetspeed.services.Profiler;
import org.apache.jetspeed.services.customlocalization.CustomLocalizationService;
import org.apache.jetspeed.util.ServiceUtil;
/**
* <p>Implements all template location related operations.
* Template location algorithms are different from the Velocity template location,
* since Jetspeed has a specialized template directory structure.
* This is a fix to get us through unti the TurbineTemplateService can locate
* resources by NLS and mediatype. Then it can be removed</p>
*
* <p>The directory structure is currently layout out in the following order:
* /templateType/mediaType/LanguageCode/CountryCode</p>
* <p>Example: /screens/html/en/US/resource.vm</p>
*
* @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
* @author <a href="mailto:rapahel@apache.org">Raphael Luta</a>
* @author <a href="mailto:paulsp@apache.org">Paul Spener</a>
* @author <a href="mailto:kimptoc_mail@yahoo.com">Chris Kimpton</a>
* @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
* @version $Id: JetspeedTemplateLocatorService.java,v 1.17 2003/04/08 21:35:31 morciuch Exp $
*/
public class JetspeedTemplateLocatorService
extends TurbineBaseService
implements TemplateLocatorService
{
private final static String CONFIG_TEMPLATE_ROOT = ".templateRoot";
private final static String CONFIG_PORTLET_GLOBAL_SEARCH = ".portlet.global.search";
private final static String DIR_SCREENS = "/screens";
private final static String DIR_LAYOUTS = "/layouts";
private final static String DIR_PORTLETS = "/portlets";
private final static String DIR_CONTROLS = "/controls";
private final static String DIR_CONTROLLERS = "/controllers";
private final static String DIR_NAVIGATIONS = "/navigations";
private final static String DIR_PARAMETERS = "/parameters";
private final static String DIR_EMAILS = "/emails";
private static final String PATH_SEPARATOR = "/";
// messages
private final static String MSG_MISSING_PARAMETER =
"JetspeedTemplateLocatorService initialization failed. Missing parameter:";
// Template Service Constants
private static final String TEMPLATE_EXTENSION = "template.extension";
private static final String DEFAULT_LAYOUT = "default.layout.template";
// Template services
private static VelocityService velocityService;
private static JspService jspService;
// the template root directories, webapp relative
private String[] templateRoots;
// use the name cache when looking up a template
private boolean useNameCache = true;
// template name cache
private Map templateMap = null;
// include screens when searching for portlet template
private boolean useGlobalPortletSearch = false;
/**
* This is the early initialization method called by the
* Turbine <code>Service</code> framework
* @param conf The <code>ServletConfig</code>
* @exception throws a <code>InitializationException</code> if the service
* fails to initialize
*/
public synchronized void init(ServletConfig conf) throws InitializationException
{
// already initialized
if (getInit())
{
return;
}
initConfiguration();
// initialization done
setInit(true);
}
public void init() throws InitializationException
{
Log.info("Late init for JetspeedTemplateLocatorService called");
while (!getInit())
{
//Not yet...
try
{
Thread.sleep(100);
Log.info("Waiting for init of JetspeedTemplateLocatorService...");
}
catch (InterruptedException ie)
{
Log.error(ie);
}
}
}
/**
* This is the shutdown method called by the
* Turbine <code>Service</code> framework
*/
public void shutdown()
{
}
/**
* Locate a screen template using Jetspeed template location algorithm, searching by
* mediatype and language criteria extracted from the request state in rundata.
*
* @param data The rundata for the request.
* @param template The name of the template.
*
* @return The path relative to the screens directory for the requested screen template,
* or null if not found.
*/
public String locateScreenTemplate(RunData data, String template)
{
List templatePaths = localizeTemplateName(data);
Iterator i = templatePaths.iterator();
String located = null;
while (i.hasNext())
{
String path = (String) i.next();
located = locateTemplate(data, DIR_SCREENS, path, template);
if (null == located)
{
// Try to locate it directly on file system, perhaps it was recently added
useNameCache = false;
located = locateTemplate(data, DIR_SCREENS, path, template);
if (null != located)
{
// add it to the map
templateMap.put(located, null);
}
useNameCache = true;
}
if (null != located)
{
return located;
}
}
if (null == located)
{
//we have not found the requested sreen but still need to return
//something, search for the default screen
i = templatePaths.iterator();
template = "/default." + getTemplateExtension(template);
while (i.hasNext())
{
String path = (String) i.next();
located = locateTemplate(data, DIR_SCREENS, path, template);
if (null != located)
{
return located;
}
}
}
return located;
}
/**
* Locate a layout template using Jetspeed template location algorithm, searching by
* mediatype and language criteria extracted from the request state in rundata.
*
* @param data The rundata for the request.
* @param template The name of the template.
*
* @return The path relative to the layouts directory for the requested layout template,
* or null if not found.
*/
public String locateLayoutTemplate(RunData data, String template)
{
List templatePaths = localizeTemplateName(data);
Iterator i = templatePaths.iterator();
String located = null;
while (i.hasNext())
{
String path = (String) i.next();
located = locateTemplate(data, DIR_LAYOUTS, path, template);
if (null == located)
{
// Try to locate it directly on file system, perhaps it was recently added
useNameCache = false;
located = locateTemplate(data, DIR_LAYOUTS, path, template);
if (null != located)
{
// add it to the map
templateMap.put(located, null);
}
useNameCache = true;
}
if (null != located)
{
return located;
}
}
if (null == located)
{
//we have not found the requested layout but still need to return
//something, search for the default layout
i = templatePaths.iterator();
//template = "/default." + getTemplateExtension(template);
template = getTemplateLayout(getTemplateExtension(template));
while (i.hasNext())
{
String path = (String) i.next();
located = locateTemplate(data, DIR_LAYOUTS, path, template);
if (null != located)
{
return located;
}
}
}
return located;
}
/**
* Locate a controller template using Jetspeed template location algorithm, searching by
* mediatype and language criteria extracted from the request state in rundata.
*
* @param data The rundata for the request.
* @param template The name of the template.
*
* @return The path relative to the controllers directory for the requested controller template,
* or null if not found.
*/
public String locateNavigationTemplate(RunData data, String template)
{
List templatePaths = localizeTemplateName(data);
Iterator i = templatePaths.iterator();
while (i.hasNext())
{
String path = (String) i.next();
String located = locateTemplate(data, DIR_NAVIGATIONS, path, template);
if (null == located)
{
// Try to locate it directly on file system, perhaps it was recently added
useNameCache = false;
located = locateTemplate(data, DIR_NAVIGATIONS, path, template);
if (null != located)
{
// add it to the map
templateMap.put(located, null);
}
useNameCache = true;
}
if (null != located)
{
return located;
}
}
return null;
}
/**
* Locate a portlet template using Jetspeed template location algorithm, searching by
* mediatype and language criteria extracted from the request state in rundata.
*
* @param data The rundata for the request.
* @param template The name of the template.
*
* @return The path relative to the portlets directory for the requested portlet template,
* or null if not found.
*/
public String locatePortletTemplate(RunData data, String template)
{
List templatePaths = localizeTemplateName(data);
Iterator i = templatePaths.iterator();
while (i.hasNext())
{
String path = (String) i.next();
String located = locateTemplate(data, DIR_PORTLETS, path, template);
if (null == located)
{
// Try to locate it directly on file system, perhaps it was recently added
useNameCache = false;
located = locateTemplate(data, DIR_PORTLETS, path, template);
if (null != located)
{
// add it to the map
templateMap.put(located, null);
}
useNameCache = true;
}
if (null != located)
{
return DIR_PORTLETS + located;
}
}
// Use "wide" search when required
if (useGlobalPortletSearch == true)
{
String located = locateScreenTemplate(data, template);
if (located != null)
{
return "/screens" + located;
}
}
return null;
}
/**
* Locate a control template using Jetspeed template location algorithm, searching by
* mediatype and language criteria extracted from the request state in rundata.
*
* @param data The rundata for the request.
* @param template The name of the template.
*
* @return The path relative to the controls directory for the requested control template,
* or null if not found.
*/
public String locateControlTemplate(RunData data, String template)
{
List templatePaths = localizeTemplateName(data);
Iterator i = templatePaths.iterator();
while (i.hasNext())
{
String path = (String) i.next();
String located = locateTemplate(data, DIR_CONTROLS, path, template);
if (null == located)
{
// Try to locate it directly on file system, perhaps it was recently added
useNameCache = false;
located = locateTemplate(data, DIR_CONTROLS, path, template);
if (null != located)
{
// add it to the map
templateMap.put(located, null);
}
useNameCache = true;
}
if (null != located)
{
return DIR_CONTROLS + located;
}
}
return null;
}
/**
* Locate a controller template using Jetspeed template location algorithm, searching by
* mediatype and language criteria extracted from the request state in rundata.
*
* @param data The rundata for the request.
* @param template The name of the template.
*
* @return The path relative to the controllers directory for the requested controller template,
* or null if not found.
*/
public String locateControllerTemplate(RunData data, String template)
{
List templatePaths = localizeTemplateName(data);
Iterator i = templatePaths.iterator();
while (i.hasNext())
{
String path = (String) i.next();
String located = locateTemplate(data, DIR_CONTROLLERS, path, template);
if (null == located)
{
// Try to locate it directly on file system, perhaps it was recently added
useNameCache = false;
located = locateTemplate(data, DIR_CONTROLLERS, path, template);
if (null != located)
{
// add it to the map
templateMap.put(located, null);
}
useNameCache = true;
}
if (null != located)
{
return DIR_CONTROLLERS + located;
}
}
return null;
}
/**
* Locate an email template using Jetspeed template location algorithm, searching by
* mediatype and language criteria extracted from the request state in rundata.
*
* @param data The rundata for the request.
* @param template The name of the template.
*
* @return The path relative to the emails directory for the requested email template,
* or null if not found.
*/
public String locateEmailTemplate(RunData data, String template)
{
CustomLocalizationService locService = (CustomLocalizationService) ServiceUtil.getServiceByName(
LocalizationService.SERVICE_NAME);
return locateEmailTemplate(data, template, locService.getLocale(data));
}
/**
* Locate an email template using Jetspeed template location algorithm, searching by
* mediatype and language.
*
* @param data The rundata for the request.
* @param template The name of the template.
* @param locale The name of the language.
*
* @return The path relative to the emails directory for the requested email template,
* or null if not found.
*/
public String locateEmailTemplate(RunData data, String template, Locale locale)
{
List templatePaths = localizeTemplateName(data, locale);
Iterator i = templatePaths.iterator();
while (i.hasNext())
{
String path = (String) i.next();
String located = locateTemplate(data, DIR_EMAILS, path, template);
if (null == located)
{
// Try to locate it directly on file system, perhaps it was recently added
useNameCache = false;
located = locateTemplate(data, DIR_EMAILS, path, template);
if (null != located)
{
// add it to the map
templateMap.put(located, null);
}
useNameCache = true;
}
if (null != located)
{
return DIR_EMAILS + located;
}
}
return null;
}
/**
* Locate a parameter style template using Jetspeed template location algorithm, searching by
* mediatype and language criteria extracted from the request state in rundata.
*
* @param data The rundata for the request.
* @param template The name of the template.
*
* @return The path relative to the portlets directory for the requested portlet template,
* or null if not found.
*/
public String locateParameterTemplate(RunData data, String template)
{
List templatePaths = localizeTemplateName(data);
Iterator i = templatePaths.iterator();
while (i.hasNext())
{
String path = (String) i.next();
String located = locateTemplate(data, DIR_PARAMETERS, path, template);
if (null == located)
{
// Try to locate it directly on file system, perhaps it was recently added
useNameCache = false;
located = locateTemplate(data, DIR_PARAMETERS, path, template);
if (null != located)
{
// add it to the map
templateMap.put(located, null);
}
useNameCache = true;
}
if (null != located)
{
return DIR_PARAMETERS + located;
}
}
return null;
}
/**
* General template location algorithm. Starts with the most specific resource,
* including mediatype + nls specification, and fallsback to least specific.
*
* @param data The rundata for the request.
* @param resourceType The path specific to the resource type sought (eg /screens).
* @param path The fullest path to the template based on simple NLS/mediatype directory.
* @param template The name of the template.
*
* @return the exact path to the template, or null if not found.
*/
private String locateTemplate(RunData data, String resourceType, String path, String template)
{
String located = null;
// Iterate through each of the template roots
for (int i = 0; i < templateRoots.length; i++)
{
located = locateTemplate(data, resourceType, path, template, templateRoots[i]);
if (located != null)
{
break;
}
}
return located;
}
/**
* General template location algorithm. Starts with the most specific resource,
* including mediatype + nls specification, and fallsback to least specific.
*
* @param data The rundata for the request.
* @param resourceType The path specific to the resource type sought (eg /screens).
* @param path The fullest path to the template based on simple NLS/mediatype directory.
* @param template The name of the template.
* @param templateRoot The template root to be searched.
*
* @return the exact path to the template, or null if not found.
*/
private String locateTemplate(
RunData data,
String resourceType,
String path,
String template,
String templateRoot)
{
String finalPath;
// make sure resourceType doesn't end with "/" but starts with "/"
if (resourceType.endsWith(PATH_SEPARATOR))
{
resourceType = resourceType.substring(0, resourceType.length() - 1);
}
if (!resourceType.startsWith(PATH_SEPARATOR))
{
resourceType = PATH_SEPARATOR + resourceType;
}
// make sure path doesn't end with "/" but starts with "/"
if (path.endsWith(PATH_SEPARATOR))
{
path = path.substring(0, path.length() - 1);
}
if (!path.startsWith(PATH_SEPARATOR))
{
path = PATH_SEPARATOR + path;
}
// make sure template starts with "/"
if (!template.startsWith(PATH_SEPARATOR))
{
template = PATH_SEPARATOR + template;
}
StringBuffer fullPath = new StringBuffer(templateRoot);
if (!templateRoot.endsWith(PATH_SEPARATOR))
{
fullPath.append(PATH_SEPARATOR);
}
fullPath.append(getTemplateExtension(template));
fullPath.append(resourceType);
String basePath = fullPath.toString();
String realPath = null;
String workingPath = null;
do
{
workingPath = path + template;
realPath = TurbineServlet.getRealPath(basePath + workingPath);
// the current template exists, return the corresponding path
if (templateExists(realPath))
{
if (Log.getLogger().isDebugEnabled())
{
Log.debug(
"TemplateLocator: template exists: "
+ realPath
+ " returning "
+ workingPath);
}
return workingPath;
}
// else strip path of one of its components and loop
int pt = path.lastIndexOf(PATH_SEPARATOR);
if (pt > -1)
{
path = path.substring(0, pt);
}
else
{
path = null;
}
}
while (path != null);
return null;
}
/**
* Helper function for template locator to find a localized (NLS) resource.
* Considers both language and country resources as well as all the possible
* media-types for the request
*
* @param data The rundata for the request.
*
* @return The possible paths to a localized template ordered by
* descending preference
*/
private List localizeTemplateName(RunData data)
{
return localizeTemplateName(data, null);
}
/**
* Helper function for template locator to find a localized (NLS) resource.
* Considers both language and country resources as well as all the possible
* media-types for the request
*
* @param data The rundata for the request.
* @param locale The locale for the request.
*
* @return The possible paths to a localized template ordered by
* descending preference
*/
private List localizeTemplateName(RunData data, Locale inLocale)
{
List templates = new ArrayList();
Locale tmplocale = null;
if (inLocale != null)
{
tmplocale = inLocale;
}
else
{
CustomLocalizationService locService = (CustomLocalizationService) ServiceUtil.getServiceByName(
LocalizationService.SERVICE_NAME);
tmplocale = locService.getLocale(data);
}
// Get the locale store it in the user object
if (tmplocale == null)
{
tmplocale =
new Locale(
TurbineResources.getString("locale.default.language", "en"),
TurbineResources.getString("locale.default.country", "US"));
}
data.getUser().setTemp("locale", tmplocale);
StringBuffer templatePath = new StringBuffer();
// retrieve all the possible media types
String type = data.getParameters().getString(Profiler.PARAM_MEDIA_TYPE, null);
List types = new ArrayList();
CapabilityMap cm = ((JetspeedRunData) data).getCapability();
// Grab the Locale from the temporary storage in the User object
Locale locale = (Locale) data.getUser().getTemp("locale");
String language = locale.getLanguage();
String country = locale.getCountry();
if (null != type)
{
types.add(type);
}
else
{
Iterator i = cm.listMediaTypes();
while (i.hasNext())
{
types.add(i.next());
}
}
Iterator typeIterator = types.iterator();
while (typeIterator.hasNext())
{
type = (String) typeIterator.next();
if ((type != null) && (type.length() > 0))
{
templatePath.append(PATH_SEPARATOR).append(type);
}
if ((language != null) && (language.length() > 0))
{
templatePath.append(PATH_SEPARATOR).append(language);
}
if ((country != null) && (country.length() > 0))
{
templatePath.append(PATH_SEPARATOR).append(country);
}
templates.add(templatePath.toString());
}
return templates;
}
/**
* Returns the extension for the specified template
*
* @param template the template name to scan for an extension
* @return the template extension if it exists or the default
* template extension
*/
private String getTemplateExtension(String template)
{
String ext = TurbineTemplate.getDefaultExtension();
int idx = template.lastIndexOf(".");
if (idx > 0)
{
ext = template.substring(idx + 1);
}
return ext;
}
/**
* Checks for the existence of a template resource given a key.
* The key are absolute paths to the templates, and are cached
* in a template cache for performance.
*
* @param key The absolute path to the template resource.
*
* @return True when the template is found, otherwise false.
*/
public boolean templateExists(String templateKey)
{
if (null == templateKey)
{
return false;
}
if (useNameCache == true)
{
return templateMap.containsKey(templateKey);
}
return (new File(templateKey).exists());
}
/**
* Loads the configuration parameters for this service from the
* JetspeedResources.properties file.
*
* @exception throws a <code>InitializationException</code> if the service
* fails to initialize
*/
private void initConfiguration() throws InitializationException
{
templateRoots =
JetspeedResources.getStringArray(
TurbineServices.SERVICE_PREFIX
+ TemplateLocatorService.SERVICE_NAME
+ CONFIG_TEMPLATE_ROOT);
if ((templateRoots == null) || (templateRoots.length == 0))
{
throw new InitializationException(MSG_MISSING_PARAMETER + CONFIG_TEMPLATE_ROOT);
}
templateMap = new HashMap();
for (int i = 0; i < templateRoots.length; i++)
{
String templateRoot = templateRoots[i];
if (!templateRoot.endsWith(PATH_SEPARATOR))
{
templateRoot = templateRoot + PATH_SEPARATOR;
}
if (Log.getLogger().isDebugEnabled())
{
Log.debug("TemplateLocator: Adding templateRoot:" + templateRoot);
}
// traverse starting from the root template directory and add resources
String templateRootPath = TurbineServlet.getRealPath(templateRoot);
if (null != templateRootPath)
{
loadNameCache(templateRootPath, "");
}
}
velocityService =
(VelocityService) TurbineServices.getInstance().getService(
VelocityService.SERVICE_NAME);
jspService = (JspService) TurbineServices.getInstance().getService(JspService.SERVICE_NAME);
useGlobalPortletSearch = JetspeedResources.getBoolean(
TurbineServices.SERVICE_PREFIX
+ TemplateLocatorService.SERVICE_NAME
+ CONFIG_PORTLET_GLOBAL_SEARCH, false);
}
/**
* Loads the template name cache map to accelerate template searches.
*
* @param path The template
* @param name just the name of the resource
*/
private void loadNameCache(String path, String name)
{
File file = new File(path);
if (file.isFile())
{
// add it to the map
templateMap.put(path, null);
}
else
{
if (file.isDirectory())
{
if (!path.endsWith(File.separator))
{
path += File.separator;
}
String list[] = file.list();
// Process all files recursivly
for (int ix = 0; list != null && ix < list.length; ix++)
{
loadNameCache(path + list[ix], list[ix]);
}
}
}
}
/**
* Correctly locate the default layout based on the
* default.layout.template property of the appropriate
* template service.
* @author <a href="mailto:sweaver@rippe.com">Scott Weaver</a>
*/
private String getTemplateLayout(String extension)
{
String dftLayout = "/default." + extension;
Configuration velocityCfg = null;
Configuration jspCfg = null;
if (velocityService != null)
{
velocityCfg = velocityService.getConfiguration();
}
if (jspService != null)
{
jspCfg = jspService.getConfiguration();
}
if (velocityCfg != null
&& velocityCfg.getString(TEMPLATE_EXTENSION).indexOf(extension) > -1)
{
return velocityCfg.getString(DEFAULT_LAYOUT, dftLayout);
}
else if (jspCfg != null && jspCfg.getString(TEMPLATE_EXTENSION).indexOf(extension) > -1)
{
return jspCfg.getString(DEFAULT_LAYOUT, dftLayout);
}
else
{
return dftLayout;
}
}
}