blob: 1360a43e29921566d0f5502785def0d8f98d5389 [file] [log] [blame]
package org.apache.tapestry.resolver;
import org.apache.hivemind.Resource;
import org.apache.hivemind.util.ContextResource;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.TapestryUtils;
import org.apache.tapestry.asset.AssetFactory;
import org.apache.tapestry.web.WebContextResource;
import java.util.Locale;
/**
* Implementation of {@link IComponentResourceResolver}.
*/
public class ComponentResourceResolverImpl implements IComponentResourceResolver {
/**
* Used to find resources under the context WEB-INF/ directory.
*/
private static final String WEB_INF = "WEB-INF/";
private AssetFactory _classpathAssetFactory;
private AssetFactory _contextAssetFactory;
/** Application id of the current tapestry app - as in applicationId.application */
private String _applicationId;
/** Root web context directory */
private Resource _contextRoot;
/** The location of the WEB-INF context directory */
private Resource _webInfLocation;
/** The location of the application within the WEB-INF/ folder */
private Resource _webInfAppLocation;
/**
* Called by hivemind automatically.
*/
public void initializeService()
{
_webInfLocation = _contextRoot.getRelativeResource(WEB_INF);
_webInfAppLocation = _webInfLocation.getRelativeResource(_applicationId + "/");
}
public Resource findComponentResource(IComponent component, IRequestCycle cycle, String path, String extension, Locale locale)
{
Resource base = component.getSpecification().getSpecificationLocation();
String baseName = path == null ? extractBaseName(base) : path;
Resource resource = null;
// have to do explicit check for context resource first
// as it might be a classpath based spec and then we need to manually figure out
// the best location to start from as context paths always get resolved first
// before classpath resources
if (WebContextResource.class.isInstance(base) || ContextResource.class.isInstance(base))
{
resource = base.getRelativeResource(baseName + extension);
if (resource != null)
return localizeResource(resource, locale);
}
resource = findComponentClassResource(component, cycle, baseName, extension, locale);
// In some cases the generic classpath resource path is fine - such as bundled component properties
if (resource == null)
{
resource = base.getRelativeResource(baseName + extension);
if (resource != null)
resource = localizeResource(resource, locale);
}
return resource;
}
String extractBaseName(Resource baseResourceLocation)
{
String fileName = baseResourceLocation.getName();
int dotx = fileName.lastIndexOf('.');
return dotx > -1 ? fileName.substring(0, dotx) : fileName;
}
Resource localizeResource(Resource resource, Locale locale)
{
if (locale == null)
return resource;
Resource localized = resource.getLocalization(locale);
if (localized != null && localized.getResourceURL() != null)
return localized;
return resource;
}
Resource findComponentClassResource(IComponent component, IRequestCycle cycle, String baseName, String extension, Locale locale)
{
Resource base = component.getSpecification().getSpecificationLocation();
String componentPackages = component.getNamespace().getPropertyValue("org.apache.tapestry.component-class-packages");
// this relies on finding things from the component class name
if (componentPackages == null)
return null;
String className = component.getSpecification().getComponentClassName();
if (className == null)
return null;
String[] packages = TapestryUtils.split(componentPackages);
for (int i=0; i < packages.length; i++)
{
// find matching package in class
int index = className.lastIndexOf(packages[i]);
if (index < 0)
continue;
// First try context
String templateName = className.substring((index + packages[i].length()) + 1, className.length()).replaceAll("\\.", "/");
templateName = templateName + extension;
if (_contextAssetFactory.assetExists(component.getSpecification(), _webInfAppLocation, templateName, locale))
{
return _contextAssetFactory.createAsset(_webInfAppLocation, component.getSpecification(), templateName, locale, component.getLocation()).getResourceLocation();
} else if (_contextAssetFactory.assetExists(component.getSpecification(), _webInfLocation, templateName, locale))
{
return _contextAssetFactory.createAsset(_webInfLocation, component.getSpecification(), templateName, locale, component.getLocation()).getResourceLocation();
}
// else classpath
String resourceName = baseName + extension;
if (_classpathAssetFactory.assetExists(component.getSpecification(), base, resourceName, locale))
{
return _classpathAssetFactory.createAsset(base, component.getSpecification(), resourceName, locale, component.getLocation()).getResourceLocation();
}
// if all else fails try package name context paths
String[] packageSegments = packages[i].split("\\.");
if (packageSegments != null && packageSegments.length > 0)
{
// start with last segment and slowly build the path up with all of them
String packagePath = "";
for (int s=packageSegments.length - 1; s > -1; s--)
{
packagePath += packageSegments[s] + "/";
String templatePath = packagePath + templateName;
if (_contextAssetFactory.assetExists(component.getSpecification(), _webInfAppLocation, templatePath, locale))
{
return _contextAssetFactory.createAsset(_webInfAppLocation, component.getSpecification(), templatePath, locale, component.getLocation()).getResourceLocation();
} else if (_contextAssetFactory.assetExists(component.getSpecification(), _webInfLocation, templatePath, locale))
{
return _contextAssetFactory.createAsset(_webInfLocation, component.getSpecification(), templatePath, locale, component.getLocation()).getResourceLocation();
}
}
}
}
return null;
}
public void setContextRoot(Resource contextRoot)
{
_contextRoot = contextRoot;
}
public void setClasspathAssetFactory(AssetFactory classpathAssetFactory)
{
_classpathAssetFactory = classpathAssetFactory;
}
public void setContextAssetFactory(AssetFactory contextAssetFactory)
{
_contextAssetFactory = contextAssetFactory;
}
public void setApplicationId(String applicationId)
{
_applicationId = applicationId;
}
}