Skip to content

Commit

Permalink
Part of the fix for GRAILS-7694 "Support loading static resources fro…
Browse files Browse the repository at this point in the history
…m binary plugins via the resources plugins". This basically extends ResourceLocator with the ability to find resources inside binary plugins. Resources plugin can now use grailsResourceLocator if present to find resources to pass through mappers.
  • Loading branch information
Graeme Rocher authored and Graeme Rocher committed Jul 13, 2011
1 parent 79bf18d commit 0022d46
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 8 deletions.
Expand Up @@ -17,7 +17,12 @@

import grails.util.Environment;
import org.codehaus.groovy.grails.io.support.GrailsResourceUtils;
import org.codehaus.groovy.grails.plugins.BinaryGrailsPlugin;
import org.codehaus.groovy.grails.plugins.GrailsPlugin;
import org.codehaus.groovy.grails.plugins.GrailsPluginManager;
import org.codehaus.groovy.grails.plugins.PluginManagerAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
Expand All @@ -39,7 +44,8 @@
* @since 1.4
*
*/
public class DefaultResourceLocator implements ResourceLocator, ResourceLoaderAware{
public class DefaultResourceLocator implements ResourceLocator, ResourceLoaderAware, PluginManagerAware{
private static final Resource NULL_RESOURCE = new ByteArrayResource("null".getBytes());
public static final String WILDCARD = "*";
public static final String FILE_SEPARATOR = File.separator;
public static final String CLOSURE_MARKER = "$";
Expand All @@ -50,6 +56,7 @@ public class DefaultResourceLocator implements ResourceLocator, ResourceLoaderAw
private Map<String, Resource> classNameToResourceCache = new ConcurrentHashMap<String, Resource>();
private Map<String, Resource> uriToResourceCache = new ConcurrentHashMap<String, Resource>();
private ResourceLoader defaultResourceLoader = new FileSystemResourceLoader();
private GrailsPluginManager pluginManager;

public void setSearchLocation(String searchLocation) {
ResourceLoader resourceLoader = getDefaultResourceLoader();
Expand Down Expand Up @@ -94,15 +101,14 @@ public Resource findResourceForURI(String uri) {
Resource resource = uriToResourceCache.get(uri);
if(resource == null) {

PluginResourceInfo info = inferPluginNameFromURI(uri);
String uriWebAppRelative = WEB_APP_DIR + uri;
for (String resourceSearchDirectory : resourceSearchDirectories) {
Resource res = resolveExceptionSafe(resourceSearchDirectory + uriWebAppRelative);
if(res.exists()) {
resource = res;
uriToResourceCache.put(uri, resource);
}
else if(!Environment.isWarDeployed()){
PluginResourceInfo info = inferPluginNameFromURI(uri);
else if(!Environment.isWarDeployed()) {
Resource dir = resolveExceptionSafe(resourceSearchDirectory);
if(dir.exists() && info != null) {
try {
Expand All @@ -111,7 +117,6 @@ else if(!Environment.isWarDeployed()){
Resource pluginFile = dir.createRelative(WEB_APP_DIR + info.uri);
if(pluginFile.exists()) {
resource = pluginFile;
uriToResourceCache.put(uri, resource);
}
}
} catch (IOException e) {
Expand All @@ -120,8 +125,37 @@ else if(!Environment.isWarDeployed()){
}
}
}

if(resource == null && info != null) {
resource = findResourceInBinaryPlugins(info);
}

if(resource != null) {
uriToResourceCache.put(uri, resource);
}
else if(Environment.isWarDeployed()) {
uriToResourceCache.put(uri, NULL_RESOURCE);
}
}
return resource;
return resource == NULL_RESOURCE ? null : resource;
}

protected Resource findResourceInBinaryPlugins(PluginResourceInfo info) {
if(pluginManager != null) {
String fullPluginName = info.pluginName;
GrailsPlugin[] allPlugins = pluginManager.getAllPlugins();
BinaryGrailsPlugin binaryPlugin = null;
for (GrailsPlugin plugin : allPlugins) {
if(plugin.getFileSystemName().equals(fullPluginName) && (plugin instanceof BinaryGrailsPlugin)) {
binaryPlugin = (BinaryGrailsPlugin) plugin;
}
}

if(binaryPlugin != null) {
return binaryPlugin.getResource(info.uri);
}
}
return null;
}

private PluginResourceInfo inferPluginNameFromURI(String uri) {
Expand Down Expand Up @@ -189,6 +223,10 @@ public void setResourceLoader(ResourceLoader resourceLoader) {
}
}

public void setPluginManager(GrailsPluginManager pluginManager) {
this.pluginManager = pluginManager;
}

class PluginResourceInfo {
String pluginName;
String uri;
Expand Down
Expand Up @@ -145,6 +145,27 @@ public BinaryGrailsPluginDescriptor getBinaryDescriptor() {
return descriptor;
}


/**
* Resolves a static resource contained within this binary plugin
*
* @param path The relative path to the static resource
* @return The resource or null if it doesn't exist
*/
public Resource getResource(String path) {
final Resource descriptorResource = descriptor.getResource();

try {
Resource resource = descriptorResource.createRelative("static" + path);
if(resource.exists()) {
return resource;
}
} catch (IOException e) {
return null;
}
return null;
}

/**
* Obtains all properties for this binary plugin for the given locale.
*
Expand Down
Expand Up @@ -211,8 +211,20 @@ class PluginPackager {
copy(file:"${basedir}/plugin.xml", tofile:"${metaInf}/grails-plugin.xml")
move(file:"${classesDir}/gsp/views.properties", todir:metaInf, failonerror:false)
mkdir(dir:"${metaInf}/grails-app/i18n")
copy(todir:"${metaInf}/grails-app/i18n", failonerror:false) {
fileset(dir:"${resourcesDir}/grails-app/i18n")
if(new File("${resourcesDir}/grails-app/i18n").exists()) {
copy(todir:"${metaInf}/grails-app/i18n", includeEmptyDirs:false,failonerror:false) {
fileset(dir:"${resourcesDir}/grails-app/i18n")
}
}
mkdir(dir:"${metaInf}/static")
copy(todir:"${metaInf}/static", includeEmptyDirs:false, failonerror:false) {
fileset(dir:"${basedir}/web-app") {
exclude name:"plugins/**"
exclude name:"**/WEB-INF/**"
exclude name:"**/META-INF/**"
exclude name:"**/*.gsp"
exclude name:"**/*.jsp"
}
}
mkdir(dir:"${metaInf}/scripts")
copy(todir:"${metaInf}/scripts") {
Expand All @@ -224,6 +236,7 @@ class PluginPackager {
fileset(dir:"${basedir}/src", excludes:"groovy/**,java/**")
}


jar(destfile:destinationFile) {
fileset(dir:classesDir, excludes:excludeList.join(','))
manifest {
Expand Down
Expand Up @@ -5,6 +5,13 @@ import org.springframework.core.io.ResourceLoader
import org.codehaus.groovy.grails.support.StaticResourceLoader
import org.codehaus.groovy.grails.support.MockResourceLoader
import org.codehaus.groovy.grails.support.MockStringResourceLoader
import org.codehaus.groovy.grails.plugins.BinaryGrailsPlugin
import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
import org.codehaus.groovy.grails.plugins.TestBinaryGrailsPlugin
import org.springframework.core.io.ByteArrayResource
import org.codehaus.groovy.grails.plugins.BinaryGrailsPluginDescriptor
import org.codehaus.groovy.grails.plugins.MockBinaryPluginResource
import org.codehaus.groovy.grails.plugins.MockGrailsPluginManager

/**
* Created by IntelliJ IDEA.
Expand Down Expand Up @@ -34,6 +41,36 @@ class ResourceLocatorSpec extends Specification{
res == null
}

void "test find resource from binary plugin"() {
given: "Resource locator with mock resource loader and a plugin manager"
def loader = new MockStringResourceLoader()
def resourceLocator = new MockResourceLocator(defaultResourceLoader: loader)
def manager = new MockGrailsPluginManager()
manager.registerMockPlugin(getBinaryPlugin())
resourceLocator.pluginManager = manager

when: "A binary plugin resource is queried"
def res = resourceLocator.findResourceForURI("/plugins/test-binary-1.0/css/main.css")

then: "The resource is found"
assert res != null

}

BinaryGrailsPlugin getBinaryPlugin() {
def str = '''
<plugin name='testBinary'>
<class>org.codehaus.groovy.grails.plugins.TestBinaryGrailsPlugin</class>
</plugin>
'''

def xml = new XmlSlurper().parseText(str)

def resource = new MockBinaryPluginResource(str.bytes)
def descriptor = new BinaryGrailsPluginDescriptor(resource, xml)
resource.relativesResources['static/css/main.css'] = new ByteArrayResource(''.bytes)
def binaryPlugin = new BinaryGrailsPlugin(TestBinaryGrailsPlugin, descriptor, new DefaultGrailsApplication())
}
}
class MockResourceLocator extends DefaultResourceLocator {
ResourceLoader defaultResourceLoader
Expand Down
Expand Up @@ -71,6 +71,36 @@ foo.bar=one


}

def "Test load static resource from binary plugin"() {
given:
def str = '''
<plugin name='testBinary'>
<class>org.codehaus.groovy.grails.plugins.TestBinaryGrailsPlugin</class>
<resources>
<resource>org.codehaus.groovy.grails.plugins.TestBinaryResource</resource>
</resources>
</plugin>
'''

def xml = new XmlSlurper().parseText(str)


when:
def resource = new MockBinaryPluginResource(str.bytes)
def descriptor = new BinaryGrailsPluginDescriptor(resource, xml)
resource.relativesResources['static/css/main.css'] = new ByteArrayResource(''.bytes)
def binaryPlugin = new BinaryGrailsPlugin(TestBinaryGrailsPlugin, descriptor, new DefaultGrailsApplication())
def cssResource = binaryPlugin.getResource("/css/main.css")

then:
cssResource != null
when:
cssResource = binaryPlugin.resolveView("/css/foo.css")

then:
cssResource == null
}
}
class TestBinaryGrailsPlugin {
def version = 1.0
Expand Down

0 comments on commit 0022d46

Please sign in to comment.