Skip to content

Commit

Permalink
Merge branch '2.3.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeff Scott Brown committed Nov 27, 2013
2 parents 759554a + 7ee51f6 commit 3f21bba
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 18 deletions.
Expand Up @@ -284,7 +284,7 @@ public GrailsApplication getGrailsApplication() {
@Override
public Object getProperty(String name) {
if (urlDefiningMode) {
getCurrentConstraints().add(new ConstrainedProperty(UrlMapping.class, name, String.class));
getParentConstraints().add(new ConstrainedProperty(UrlMapping.class, name, String.class));
return CAPTURING_WILD_CARD;
}
return super.getProperty(name);
Expand Down Expand Up @@ -402,7 +402,12 @@ Object propertyMissing(String name) {

private Object _invoke(String methodName, Object arg, Object delegate) {
Object[] args = (Object[]) arg;
String mappedURI = establishFullURI(methodName);
List<ConstrainedProperty> currentConstraints = new ArrayList<ConstrainedProperty>();
List<ConstrainedProperty> parentConstraints = getParentConstraints();
if(parentConstraints != null) {
currentConstraints.addAll(parentConstraints);
}
String mappedURI = establishFullURI(methodName, currentConstraints);
final boolean isResponseCode = isResponseCode(mappedURI);
if (mappedURI.startsWith(SLASH) || isResponseCode) {
// Create a new parameter map for this mapping.
Expand Down Expand Up @@ -452,7 +457,7 @@ private Object _invoke(String methodName, Object arg, Object delegate) {
httpMethod = this.httpMethod;
}

ConstrainedProperty[] constraints = getCurrentConstraints().toArray(new ConstrainedProperty[getCurrentConstraints().size()]);
ConstrainedProperty[] constraints = currentConstraints.toArray(new ConstrainedProperty[currentConstraints.size()]);
UrlMapping urlMapping;
if (uri != null) {
try {
Expand Down Expand Up @@ -492,32 +497,32 @@ private Object _invoke(String methodName, Object arg, Object delegate) {
if (namedArguments.containsKey(RESOURCE)) {
Object controller = namedArguments.get(RESOURCE);
String controllerName = controller.toString();
parentResources.push(new ParentResource(controllerName, uri, getCurrentConstraints(), true));
parentResources.push(new ParentResource(controllerName, uri, currentConstraints, true));
try {
invokeLastArgumentIfClosure(args);
} finally {
parentResources.pop();
}
if (controller != null) {

createSingleResourceRestfulMappings(controllerName, pluginName, namespace, version, urlData, getCurrentConstraints(), calculateIncludes(namedArguments, DEFAULT_RESOURCE_INCLUDES));
createSingleResourceRestfulMappings(controllerName, pluginName, namespace, version, urlData, currentConstraints, calculateIncludes(namedArguments, DEFAULT_RESOURCE_INCLUDES));
}
} else if (namedArguments.containsKey(RESOURCES)) {
Object controller = namedArguments.get(RESOURCES);
String controllerName = controller.toString();
parentResources.push(new ParentResource(controllerName, uri, getCurrentConstraints(), false));
parentResources.push(new ParentResource(controllerName, uri, currentConstraints, false));
try {
invokeLastArgumentIfClosure(args);
} finally {
parentResources.pop();
}
if (controller != null) {
createResourceRestfulMappings(controllerName, pluginName, namespace,version,urlData, getCurrentConstraints(), calculateIncludes(namedArguments, DEFAULT_RESOURCES_INCLUDES));
createResourceRestfulMappings(controllerName, pluginName, namespace,version,urlData, currentConstraints, calculateIncludes(namedArguments, DEFAULT_RESOURCES_INCLUDES));
}
} else {

invokeLastArgumentIfClosure(args);
UrlMapping urlMapping = getURLMappingForNamedArgs(namedArguments, urlData, mappedURI, isResponseCode);
UrlMapping urlMapping = getURLMappingForNamedArgs(namedArguments, urlData, mappedURI, isResponseCode, currentConstraints);
configureUrlMapping(urlMapping);
return urlMapping;
}
Expand Down Expand Up @@ -545,7 +550,7 @@ private Object _invoke(String methodName, Object arg, Object delegate) {

Closure callable = (Closure) args[0];
callable.setDelegate(builder);
for (ConstrainedProperty constrainedProperty : getCurrentConstraints()) {
for (ConstrainedProperty constrainedProperty : currentConstraints) {
builder.getConstrainedProperties().put(constrainedProperty.getPropertyName(), constrainedProperty);
}
callable.call();
Expand Down Expand Up @@ -597,7 +602,7 @@ private List<String> calculateIncludes(Map namedArguments, List<String> defaultR
return includes;
}

private String establishFullURI(String uri) {
private String establishFullURI(String uri, List<ConstrainedProperty> currentConstraints) {
if (parentResources.isEmpty()) {
return uri;
}
Expand All @@ -610,7 +615,7 @@ private String establishFullURI(String uri) {
else {
if (parentResource.controllerName != null) {
uriBuilder.append(parentResource.uri).append(SLASH).append(CAPTURING_WILD_CARD);
getCurrentConstraints().add(new ConstrainedProperty(UrlMapping.class, parentResource.controllerName + "Id", String.class));
currentConstraints.add(new ConstrainedProperty(UrlMapping.class, parentResource.controllerName + "Id", String.class));
}
}

Expand Down Expand Up @@ -872,7 +877,7 @@ private boolean isResponseCode(String s) {
}

private UrlMapping getURLMappingForNamedArgs(Map namedArguments,
UrlMappingData urlData, String mapping, boolean isResponseCode) {
UrlMappingData urlData, String mapping, boolean isResponseCode, List<ConstrainedProperty> currentConstraints) {
Object controllerName;
Object actionName;
final Map bindingVariables = binding != null ? binding.getVariables() : null;
Expand All @@ -891,7 +896,7 @@ private UrlMapping getURLMappingForNamedArgs(Map namedArguments,
}

Object uri = getURI(namedArguments, bindingVariables);
ConstrainedProperty[] constraints = getCurrentConstraints().toArray(new ConstrainedProperty[getCurrentConstraints().size()]);
ConstrainedProperty[] constraints = currentConstraints.toArray(new ConstrainedProperty[currentConstraints.size()]);

UrlMapping urlMapping;
if (uri != null) {
Expand Down Expand Up @@ -995,10 +1000,10 @@ private UrlMapping createURLMapping(UrlMappingData urlData, boolean isResponseCo
return new ResponseCodeUrlMapping(urlData, controllerName, actionName, namespace, pluginName, viewName,
null, sc);
}

public List<ConstrainedProperty> getCurrentConstraints() {
ParentResource parentResource = parentResources.peek();
return parentResource == null ? previousConstraints : parentResource.constraints;
public List<ConstrainedProperty> getParentConstraints() {
ParentResource parentResource = parentResources.peek();
return parentResource == null ? previousConstraints : parentResource.constraints;
}

class ParentResource {
Expand Down
@@ -1,16 +1,96 @@
package org.codehaus.groovy.grails.web.mapping

import static org.springframework.http.HttpMethod.*
import grails.web.CamelCaseUrlConverter

import org.springframework.http.HttpMethod
import org.springframework.mock.web.MockServletContext

import spock.lang.Issue
import spock.lang.Specification
import static org.springframework.http.HttpMethod.*

/**
* @author Graeme Rocher
*/
class RestfulResourceMappingSpec extends Specification{

@Issue('GRAILS-10835')
void 'Test multiple nested mappings have correct constrained properties'() {
given: 'A resource mapping with child mappings'
def urlMappingsHolder = getUrlMappingsHolder {
"/books"(resources: "book") {
'/sellers'(resources:'seller') {
'/locations'(resources: 'location')
}
'/authors'(resources:'author')
'/titles'(resources:'title')
}
}

when: 'The URL mappings are obtained'
def urlMappings = urlMappingsHolder.urlMappings
def bookMappings = urlMappings.findAll { it.controllerName == 'book' }
def authorMappings = urlMappings.findAll { it.controllerName == 'author' }
def titleMappings = urlMappings.findAll { it.controllerName == 'title' }
def sellersMappings = urlMappings.findAll { it.controllerName == 'seller' }
def locationsMappings = urlMappings.findAll { it.controllerName == 'location' }

then: 'There are the correct number of mappings'
urlMappings.size() == 35

and: 'Each controller has 7 mappings'
bookMappings.size() == 7
authorMappings.size() == 7
titleMappings.size() == 7
sellersMappings.size() == 7
locationsMappings.size() == 7

and: 'the book mappings have the expected constrained properties'
bookMappings.find { it.actionName == 'index' }.constraints*.propertyName == ['format']
bookMappings.find { it.actionName == 'create' }.constraints*.propertyName == []
bookMappings.find { it.actionName == 'save' }.constraints*.propertyName == ['format']
bookMappings.find { it.actionName == 'show' }.constraints*.propertyName == ['id', 'format']
bookMappings.find { it.actionName == 'edit' }.constraints*.propertyName == ['id']
bookMappings.find { it.actionName == 'update' }.constraints*.propertyName == ['id', 'format']
bookMappings.find { it.actionName == 'delete' }.constraints*.propertyName == ['id', 'format']

and: 'the author mappings have the expected constrained properties'
authorMappings.find { it.actionName == 'index' }.constraints*.propertyName == ['bookId', 'format']
authorMappings.find { it.actionName == 'create' }.constraints*.propertyName == ['bookId']
authorMappings.find { it.actionName == 'save' }.constraints*.propertyName == ['bookId', 'format']
authorMappings.find { it.actionName == 'show' }.constraints*.propertyName == ['bookId', 'id', 'format']
authorMappings.find { it.actionName == 'edit' }.constraints*.propertyName == ['bookId', 'id']
authorMappings.find { it.actionName == 'update' }.constraints*.propertyName == ['bookId', 'id', 'format']
authorMappings.find { it.actionName == 'delete' }.constraints*.propertyName == ['bookId', 'id', 'format']

and: 'the title mappings have the expected constrained properties'
titleMappings.find { it.actionName == 'index' }.constraints*.propertyName == ['bookId', 'format']
titleMappings.find { it.actionName == 'create' }.constraints*.propertyName == ['bookId']
titleMappings.find { it.actionName == 'save' }.constraints*.propertyName == ['bookId', 'format']
titleMappings.find { it.actionName == 'show' }.constraints*.propertyName == ['bookId', 'id', 'format']
titleMappings.find { it.actionName == 'edit' }.constraints*.propertyName == ['bookId', 'id']
titleMappings.find { it.actionName == 'update' }.constraints*.propertyName == ['bookId', 'id', 'format']
titleMappings.find { it.actionName == 'delete' }.constraints*.propertyName == ['bookId', 'id', 'format']

and: 'the seller mappings have the expected constrained properties'
sellersMappings.find { it.actionName == 'index' }.constraints*.propertyName == ['bookId', 'format']
sellersMappings.find { it.actionName == 'create' }.constraints*.propertyName == ['bookId']
sellersMappings.find { it.actionName == 'save' }.constraints*.propertyName == ['bookId', 'format']
sellersMappings.find { it.actionName == 'show' }.constraints*.propertyName == ['bookId', 'id', 'format']
sellersMappings.find { it.actionName == 'edit' }.constraints*.propertyName == ['bookId', 'id']
sellersMappings.find { it.actionName == 'update' }.constraints*.propertyName == ['bookId', 'id', 'format']
sellersMappings.find { it.actionName == 'delete' }.constraints*.propertyName == ['bookId', 'id', 'format']

and: 'the location mappings have the expected constrained properties'
locationsMappings.find { it.actionName == 'index' }.constraints*.propertyName == ['bookId', 'sellerId', 'format']
locationsMappings.find { it.actionName == 'create' }.constraints*.propertyName == ['bookId', 'sellerId']
locationsMappings.find { it.actionName == 'save' }.constraints*.propertyName == ['bookId', 'sellerId', 'format']
locationsMappings.find { it.actionName == 'show' }.constraints*.propertyName == ['bookId', 'sellerId', 'id', 'format']
locationsMappings.find { it.actionName == 'edit' }.constraints*.propertyName == ['bookId', 'sellerId', 'id']
locationsMappings.find { it.actionName == 'update' }.constraints*.propertyName == ['bookId', 'sellerId', 'id', 'format']
locationsMappings.find { it.actionName == 'delete' }.constraints*.propertyName == ['bookId', 'sellerId', 'id', 'format']
}

void "Test that URL mappings with resources 3 levels deep works"() {
given:"A resources definition with nested URL mappings"
def urlMappingsHolder = getUrlMappingsHolder {
Expand Down

0 comments on commit 3f21bba

Please sign in to comment.