Skip to content

Commit

Permalink
allow writing to the async response from promises by providing the ab…
Browse files Browse the repository at this point in the history
…ility to lookup the response from the executing thread
  • Loading branch information
graemerocher committed Mar 14, 2013
1 parent 1b47565 commit 88b2152
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 18 deletions.
8 changes: 8 additions & 0 deletions grails-async/src/main/groovy/grails/async/PromiseFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import groovy.lang.Closure;
import org.grails.async.decorator.PromiseDecorator;
import org.grails.async.decorator.PromiseDecoratorLookupStrategy;

import java.util.List;
import java.util.Map;
Expand All @@ -30,6 +31,13 @@
*/
public interface PromiseFactory {

/**
* Adds a PromiseDecoratorLookupStrategy. The strategy implementation must be stateless, do not add a strategy that contains state
*
* @param lookupStrategy The lookup strategy
*/
void addPromiseDecoratorLookupStrategy(PromiseDecoratorLookupStrategy lookupStrategy);

/**
* Creates a promise with a value pre-bound to it
* @param value The value
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.grails.async.decorator

/**
* A lookup strategy for PromiseDecorator instances
*
* @author Graeme Rocher
* @since 2.3
*/
public interface PromiseDecoratorLookupStrategy {

List<PromiseDecorator> findDecorators()
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
import grails.async.*;
import groovy.lang.Closure;
import org.grails.async.decorator.PromiseDecorator;
import org.grails.async.decorator.PromiseDecoratorLookupStrategy;

import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
* Abstract implementation of the {@link grails.async.PromiseFactory} interface, subclasses should extend
Expand All @@ -30,6 +32,13 @@
*/
public abstract class AbstractPromiseFactory implements PromiseFactory{

protected Collection<PromiseDecoratorLookupStrategy> lookupStrategies = new ConcurrentLinkedQueue<PromiseDecoratorLookupStrategy>();

@Override
public void addPromiseDecoratorLookupStrategy(PromiseDecoratorLookupStrategy lookupStrategy) {
lookupStrategies.add(lookupStrategy);
}

@Override
public <T> Promise<T> createBoundPromise(T value) {
return new BoundPromise<T>(value);
Expand All @@ -40,13 +49,22 @@ public <T> Promise<T> createBoundPromise(T value) {
*/
@Override
public <T> Promise<T> createPromise(Closure<T> c, List<PromiseDecorator> decorators) {
if (!decorators.isEmpty()) {
for(PromiseDecorator d : decorators) {
c = applyDecorators(c, decorators);

return createPromise(c);
}

protected Closure applyDecorators(Closure c, List<PromiseDecorator> decorators) {
List<PromiseDecorator> allDecorators = decorators != null ? new ArrayList<PromiseDecorator>(decorators): new ArrayList<PromiseDecorator>();
for (PromiseDecoratorLookupStrategy lookupStrategy : lookupStrategies) {
allDecorators.addAll(lookupStrategy.findDecorators());
}
if (!allDecorators.isEmpty()) {
for(PromiseDecorator d : allDecorators) {
c = d.decorate(c);
}
}

return createPromise(c);
return c;
}

/**
Expand All @@ -62,16 +80,12 @@ public <T> Promise<List<T>> createPromise(List<Closure<T>> closures) {
*/
@Override
public <T> Promise<List<T>> createPromise(List<Closure<T>> closures, List<PromiseDecorator> decorators) {
if(decorators != null && !decorators.isEmpty()) {
List<Closure<T>> newClosures = new ArrayList<Closure<T>>(closures.size());
for (Closure<T> closure : closures) {
for (PromiseDecorator decorator : decorators) {
closure = decorator.decorate(closure);
}
newClosures.add(closure);
}
closures = newClosures;

List<Closure<T>> newClosures = new ArrayList<Closure<T>>(closures.size());
for (Closure<T> closure : closures) {
newClosures.add( applyDecorators(closure, decorators));
}
closures = newClosures;
PromiseList<T> promiseList = new PromiseList<T>();

for (Closure<T> closure : closures) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@ class GparsPromiseFactory extends AbstractPromiseFactory{
@Override
def <T> Promise<T> createPromise(Closure<T>... closures) {
if (closures.length == 1) {
return new GparsPromise(closures[0])
final callable = closures[0]
return new GparsPromise(applyDecorators(callable, null))
}
else {
def promiseList = new PromiseList()
for(p in closures) {
applyDecorators(p, null)
promiseList << p
}
return promiseList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.codehaus.groovy.grails.plugins.web.async

import grails.async.Promises
import grails.util.GrailsUtil
import org.codehaus.groovy.grails.plugins.web.async.mvc.AsyncActionResultTransformer

Expand All @@ -38,6 +39,7 @@ class ControllersAsyncGrailsPlugin {
}

def doWithDynamicMethods = {
Promises.promiseFactory.addPromiseDecoratorLookupStrategy(new WebRequestPromiseDecoratorLookupStrategy())
def original = HttpServletRequest.metaClass.getMetaMethod("startAsync", null)
if (original == null) {
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,6 @@ class GrailsAsyncContext implements AsyncContext {
}
try {
runnable.run()

for (PersistenceContextInterceptor i in interceptors) {
i.flush()
}
} finally {
for (PersistenceContextInterceptor i in interceptors) {
i.destroy()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.codehaus.groovy.grails.plugins.web.async

import groovy.transform.CompileStatic
import groovy.transform.TypeCheckingMode
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest
import org.codehaus.groovy.grails.web.util.WebUtils
import org.grails.async.decorator.PromiseDecorator
import org.grails.async.decorator.PromiseDecoratorLookupStrategy

/**
* A promise decorated lookup strategy that binds a WebRequest to the promise thread
*
* @author Graeme Rocher
* @since 2.3
*/
@CompileStatic
class WebRequestPromiseDecoratorLookupStrategy implements PromiseDecoratorLookupStrategy{
@Override
List<PromiseDecorator> findDecorators() {
final webRequest = GrailsWebRequest.lookup()
if (webRequest) {
return [new WebRequestPromsiseDecorator(webRequest)]
}
return Collections.emptyList()
}
}
@CompileStatic
class WebRequestPromsiseDecorator implements PromiseDecorator{
GrailsWebRequest webRequest

WebRequestPromsiseDecorator(GrailsWebRequest webRequest) {
this.webRequest = webRequest
}

@Override
def <D> Closure<D> decorate(Closure<D> c) {
return (Closure<D>) { args ->
def newWebRequest = new GrailsWebRequest(webRequest.currentRequest, webRequest.currentResponse, webRequest.servletContext,webRequest.applicationContext)
WebUtils.storeGrailsWebRequest(newWebRequest)
try {
return invokeClosure(c, args)
}
finally {
newWebRequest.requestCompleted()
WebUtils.clearGrailsWebRequest()

}
}
}

@CompileStatic(TypeCheckingMode.SKIP)
def invokeClosure(Closure c, args) {
c.call(* args)
}
}

0 comments on commit 88b2152

Please sign in to comment.