Skip to content

Commit 0022d46

Browse files
Graeme RocherGraeme Rocher
authored andcommitted
Part of the fix for GRAILS-7694 "Support loading static resources from 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.
1 parent 79bf18d commit 0022d46

File tree

5 files changed

+147
-8
lines changed

5 files changed

+147
-8
lines changed

grails-core/src/main/groovy/org/codehaus/groovy/grails/core/io/DefaultResourceLocator.java

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717

1818
import grails.util.Environment;
1919
import org.codehaus.groovy.grails.io.support.GrailsResourceUtils;
20+
import org.codehaus.groovy.grails.plugins.BinaryGrailsPlugin;
21+
import org.codehaus.groovy.grails.plugins.GrailsPlugin;
22+
import org.codehaus.groovy.grails.plugins.GrailsPluginManager;
23+
import org.codehaus.groovy.grails.plugins.PluginManagerAware;
2024
import org.springframework.context.ResourceLoaderAware;
25+
import org.springframework.core.io.ByteArrayResource;
2126
import org.springframework.core.io.FileSystemResourceLoader;
2227
import org.springframework.core.io.Resource;
2328
import org.springframework.core.io.ResourceLoader;
@@ -39,7 +44,8 @@
3944
* @since 1.4
4045
*
4146
*/
42-
public class DefaultResourceLocator implements ResourceLocator, ResourceLoaderAware{
47+
public class DefaultResourceLocator implements ResourceLocator, ResourceLoaderAware, PluginManagerAware{
48+
private static final Resource NULL_RESOURCE = new ByteArrayResource("null".getBytes());
4349
public static final String WILDCARD = "*";
4450
public static final String FILE_SEPARATOR = File.separator;
4551
public static final String CLOSURE_MARKER = "$";
@@ -50,6 +56,7 @@ public class DefaultResourceLocator implements ResourceLocator, ResourceLoaderAw
5056
private Map<String, Resource> classNameToResourceCache = new ConcurrentHashMap<String, Resource>();
5157
private Map<String, Resource> uriToResourceCache = new ConcurrentHashMap<String, Resource>();
5258
private ResourceLoader defaultResourceLoader = new FileSystemResourceLoader();
59+
private GrailsPluginManager pluginManager;
5360

5461
public void setSearchLocation(String searchLocation) {
5562
ResourceLoader resourceLoader = getDefaultResourceLoader();
@@ -94,15 +101,14 @@ public Resource findResourceForURI(String uri) {
94101
Resource resource = uriToResourceCache.get(uri);
95102
if(resource == null) {
96103

104+
PluginResourceInfo info = inferPluginNameFromURI(uri);
97105
String uriWebAppRelative = WEB_APP_DIR + uri;
98106
for (String resourceSearchDirectory : resourceSearchDirectories) {
99107
Resource res = resolveExceptionSafe(resourceSearchDirectory + uriWebAppRelative);
100108
if(res.exists()) {
101109
resource = res;
102-
uriToResourceCache.put(uri, resource);
103110
}
104-
else if(!Environment.isWarDeployed()){
105-
PluginResourceInfo info = inferPluginNameFromURI(uri);
111+
else if(!Environment.isWarDeployed()) {
106112
Resource dir = resolveExceptionSafe(resourceSearchDirectory);
107113
if(dir.exists() && info != null) {
108114
try {
@@ -111,7 +117,6 @@ else if(!Environment.isWarDeployed()){
111117
Resource pluginFile = dir.createRelative(WEB_APP_DIR + info.uri);
112118
if(pluginFile.exists()) {
113119
resource = pluginFile;
114-
uriToResourceCache.put(uri, resource);
115120
}
116121
}
117122
} catch (IOException e) {
@@ -120,8 +125,37 @@ else if(!Environment.isWarDeployed()){
120125
}
121126
}
122127
}
128+
129+
if(resource == null && info != null) {
130+
resource = findResourceInBinaryPlugins(info);
131+
}
132+
133+
if(resource != null) {
134+
uriToResourceCache.put(uri, resource);
135+
}
136+
else if(Environment.isWarDeployed()) {
137+
uriToResourceCache.put(uri, NULL_RESOURCE);
138+
}
123139
}
124-
return resource;
140+
return resource == NULL_RESOURCE ? null : resource;
141+
}
142+
143+
protected Resource findResourceInBinaryPlugins(PluginResourceInfo info) {
144+
if(pluginManager != null) {
145+
String fullPluginName = info.pluginName;
146+
GrailsPlugin[] allPlugins = pluginManager.getAllPlugins();
147+
BinaryGrailsPlugin binaryPlugin = null;
148+
for (GrailsPlugin plugin : allPlugins) {
149+
if(plugin.getFileSystemName().equals(fullPluginName) && (plugin instanceof BinaryGrailsPlugin)) {
150+
binaryPlugin = (BinaryGrailsPlugin) plugin;
151+
}
152+
}
153+
154+
if(binaryPlugin != null) {
155+
return binaryPlugin.getResource(info.uri);
156+
}
157+
}
158+
return null;
125159
}
126160

127161
private PluginResourceInfo inferPluginNameFromURI(String uri) {
@@ -189,6 +223,10 @@ public void setResourceLoader(ResourceLoader resourceLoader) {
189223
}
190224
}
191225

226+
public void setPluginManager(GrailsPluginManager pluginManager) {
227+
this.pluginManager = pluginManager;
228+
}
229+
192230
class PluginResourceInfo {
193231
String pluginName;
194232
String uri;

grails-core/src/main/groovy/org/codehaus/groovy/grails/plugins/BinaryGrailsPlugin.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,27 @@ public BinaryGrailsPluginDescriptor getBinaryDescriptor() {
145145
return descriptor;
146146
}
147147

148+
149+
/**
150+
* Resolves a static resource contained within this binary plugin
151+
*
152+
* @param path The relative path to the static resource
153+
* @return The resource or null if it doesn't exist
154+
*/
155+
public Resource getResource(String path) {
156+
final Resource descriptorResource = descriptor.getResource();
157+
158+
try {
159+
Resource resource = descriptorResource.createRelative("static" + path);
160+
if(resource.exists()) {
161+
return resource;
162+
}
163+
} catch (IOException e) {
164+
return null;
165+
}
166+
return null;
167+
}
168+
148169
/**
149170
* Obtains all properties for this binary plugin for the given locale.
150171
*

grails-core/src/main/groovy/org/codehaus/groovy/grails/plugins/publishing/PluginPackager.groovy

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,20 @@ class PluginPackager {
211211
copy(file:"${basedir}/plugin.xml", tofile:"${metaInf}/grails-plugin.xml")
212212
move(file:"${classesDir}/gsp/views.properties", todir:metaInf, failonerror:false)
213213
mkdir(dir:"${metaInf}/grails-app/i18n")
214-
copy(todir:"${metaInf}/grails-app/i18n", failonerror:false) {
215-
fileset(dir:"${resourcesDir}/grails-app/i18n")
214+
if(new File("${resourcesDir}/grails-app/i18n").exists()) {
215+
copy(todir:"${metaInf}/grails-app/i18n", includeEmptyDirs:false,failonerror:false) {
216+
fileset(dir:"${resourcesDir}/grails-app/i18n")
217+
}
218+
}
219+
mkdir(dir:"${metaInf}/static")
220+
copy(todir:"${metaInf}/static", includeEmptyDirs:false, failonerror:false) {
221+
fileset(dir:"${basedir}/web-app") {
222+
exclude name:"plugins/**"
223+
exclude name:"**/WEB-INF/**"
224+
exclude name:"**/META-INF/**"
225+
exclude name:"**/*.gsp"
226+
exclude name:"**/*.jsp"
227+
}
216228
}
217229
mkdir(dir:"${metaInf}/scripts")
218230
copy(todir:"${metaInf}/scripts") {
@@ -224,6 +236,7 @@ class PluginPackager {
224236
fileset(dir:"${basedir}/src", excludes:"groovy/**,java/**")
225237
}
226238

239+
227240
jar(destfile:destinationFile) {
228241
fileset(dir:classesDir, excludes:excludeList.join(','))
229242
manifest {

grails-core/src/test/groovy/org/codehaus/groovy/grails/core/io/ResourceLocatorSpec.groovy

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ import org.springframework.core.io.ResourceLoader
55
import org.codehaus.groovy.grails.support.StaticResourceLoader
66
import org.codehaus.groovy.grails.support.MockResourceLoader
77
import org.codehaus.groovy.grails.support.MockStringResourceLoader
8+
import org.codehaus.groovy.grails.plugins.BinaryGrailsPlugin
9+
import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
10+
import org.codehaus.groovy.grails.plugins.TestBinaryGrailsPlugin
11+
import org.springframework.core.io.ByteArrayResource
12+
import org.codehaus.groovy.grails.plugins.BinaryGrailsPluginDescriptor
13+
import org.codehaus.groovy.grails.plugins.MockBinaryPluginResource
14+
import org.codehaus.groovy.grails.plugins.MockGrailsPluginManager
815

916
/**
1017
* Created by IntelliJ IDEA.
@@ -34,6 +41,36 @@ class ResourceLocatorSpec extends Specification{
3441
res == null
3542
}
3643

44+
void "test find resource from binary plugin"() {
45+
given: "Resource locator with mock resource loader and a plugin manager"
46+
def loader = new MockStringResourceLoader()
47+
def resourceLocator = new MockResourceLocator(defaultResourceLoader: loader)
48+
def manager = new MockGrailsPluginManager()
49+
manager.registerMockPlugin(getBinaryPlugin())
50+
resourceLocator.pluginManager = manager
51+
52+
when: "A binary plugin resource is queried"
53+
def res = resourceLocator.findResourceForURI("/plugins/test-binary-1.0/css/main.css")
54+
55+
then: "The resource is found"
56+
assert res != null
57+
58+
}
59+
60+
BinaryGrailsPlugin getBinaryPlugin() {
61+
def str = '''
62+
<plugin name='testBinary'>
63+
<class>org.codehaus.groovy.grails.plugins.TestBinaryGrailsPlugin</class>
64+
</plugin>
65+
'''
66+
67+
def xml = new XmlSlurper().parseText(str)
68+
69+
def resource = new MockBinaryPluginResource(str.bytes)
70+
def descriptor = new BinaryGrailsPluginDescriptor(resource, xml)
71+
resource.relativesResources['static/css/main.css'] = new ByteArrayResource(''.bytes)
72+
def binaryPlugin = new BinaryGrailsPlugin(TestBinaryGrailsPlugin, descriptor, new DefaultGrailsApplication())
73+
}
3774
}
3875
class MockResourceLocator extends DefaultResourceLocator {
3976
ResourceLoader defaultResourceLoader

grails-core/src/test/groovy/org/codehaus/groovy/grails/plugins/BinaryPluginSpec.groovy

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,36 @@ foo.bar=one
7171

7272

7373
}
74+
75+
def "Test load static resource from binary plugin"() {
76+
given:
77+
def str = '''
78+
<plugin name='testBinary'>
79+
<class>org.codehaus.groovy.grails.plugins.TestBinaryGrailsPlugin</class>
80+
<resources>
81+
<resource>org.codehaus.groovy.grails.plugins.TestBinaryResource</resource>
82+
</resources>
83+
</plugin>
84+
'''
85+
86+
def xml = new XmlSlurper().parseText(str)
87+
88+
89+
when:
90+
def resource = new MockBinaryPluginResource(str.bytes)
91+
def descriptor = new BinaryGrailsPluginDescriptor(resource, xml)
92+
resource.relativesResources['static/css/main.css'] = new ByteArrayResource(''.bytes)
93+
def binaryPlugin = new BinaryGrailsPlugin(TestBinaryGrailsPlugin, descriptor, new DefaultGrailsApplication())
94+
def cssResource = binaryPlugin.getResource("/css/main.css")
95+
96+
then:
97+
cssResource != null
98+
when:
99+
cssResource = binaryPlugin.resolveView("/css/foo.css")
100+
101+
then:
102+
cssResource == null
103+
}
74104
}
75105
class TestBinaryGrailsPlugin {
76106
def version = 1.0

0 commit comments

Comments
 (0)