I am writing integration test cases for the project that uses Struts2, Spring, Hibernate using JUnit.
My test class extends StrutsSpringTestCase. The application needs login/session to invoke any action. Following is the code:
#Test
public void testGetActionProxy() throws Exception {
ActionProxy proxy;
String result;
ActionContext.getContext().setSession(createUserSession()); // Not sure if this is needed here. But in order to get the session working, I need this.
proxy = initAction("cInfo");
assertNotNull(proxy);
CustInfo action = (CustInfo) proxy.getAction();
result = proxy.execute();
assertEquals(Action.SUCCESS, result);
}
The initAction() method:
private ActionProxy initAction(String actionUri) {
ActionProxy proxy = getActionProxy(actionUri);
ActionContext.setContext(proxy.getInvocation().getInvocationContext()); // I tried this line of code to get the ServletActionContext.getMapping().getName() to work. But no use.
ActionContext actionContext = proxy.getInvocation().getInvocationContext();
actionContext.setSession(createUserSession()); // This is for setting a session
return proxy;
}
Before it hits this method, it loads all the config files. struts.xml jpaContext.xml, beans.xml, etc.
My Action class CustInfo implements ServletRequestAware and it has a method getActionName which as the line:
return ServletActionContext.getActionMapping().getName();
This gets invoked when I call result = proxy.execute();. So the request is failing.
Question 1: Why does it return null? I thought ServletActionContext is automatically initiated, so it should return a value. But its not. If its not initialized, where is the proper place to initialize and how?
I tried the following after getActionProxy call. But it still did not work.
ServletActionContext.setContext(proxy.getInvocation().getInvocationContext());
Question 2: To set the session, before getActionProxy(), I am having to call,
ActionContext.getContext().setSession(createUserSession());
And again, after getActionProxy
ActionContext actionContext = proxy.getInvocation().getInvocationContext();
actionContext.setSession(createUserSession());
to set the session. I assume, there is something wrong here.
Question 3: Looks like, there are several contexts in play here:applicationContext, ActionContext ServletContext and ServletActionContext.
When my test class extends StrutsSpringTestCase class, I guess applicationContext is initialized. But I am not sure about other contexts. Where to initialize them?
Edit:
Further investigation in the source code reveals one issue..
When I call ServletActionContext.getActionMapping(), internally its calling ActionContext's get() method.
public Object get(String key) {
return context.get(key);
}
context is a map of object, in which its looking for value for a key struts.actionMapping, which does not exist. So, returns null. But not sure why it is there. It's not empty. It has other key/values.
The answer to your questions:
ServletActionContext.getActionMapping() returns the mapping from the action context, if it's not set then you get null.
You shouldn't set a session manually, a session is created when action is executed.
Don't mess up different classes ActionContext, ServletContext, and ServletActionContext. You shouldn't do anything with initializing these objects, because it's done by the superclass StrutsSpringTestCase.
public void testGetActionMapping() {
ActionMapping mapping = getActionMapping("/cInfo.action");
assertNotNull(mapping);
assertEquals("/", mapping.getNamespace());
assertEquals("cInfo", mapping.getName());
}
public void testGetActionProxy() throws Exception {
ActionProxy proxy = getActionProxy("/cInfo.action");
assertNotNull(proxy);
CustInfo action = (CustInfo) proxy.getAction();
assertNotNull(action);
String result = proxy.execute();
assertEquals(Action.SUCCESS, result);
}
Related
Question: How can I tell Spring that a set of beans with a custom scope should all be considered garbage, so that the next request on the same thread would not re-use their state?
What I've done: I've implemented a custom scope in Spring, to mimic the lifecycle of a request scope (HttpRequest) but for TcpRequests. It is very similar what is found here.
Many examples of custom scopes which I am finding are variants on prototype or singleton with no explicit termination of beans occurring, or, alternatively, they based around a thread local or ThreadScope but they do not describe telling Spring that the lifecycle has ended and that all beans should be destroyed.
Things I have tried (perhaps incorrectly):
Event + Listener to indicate the beginning and end of the scope (these occur when message is received and just before response is sent); in listener, the scope is explicitly cleared which clears the entire map used by the thread local implementation (scope.clear()). Clearing scope does result in the next call to context.getBean() returning a new instance when handled manually in tests, but my bean which is autowired in a singleton class does not get a new bean--it uses the same bean over and over.
Listener which implements: BeanFactoryPostProcessor, BeanPostProcessor, BeanFactoryAware, DisposableBean and attempt to call destroy() on all Disposable bean instances; something like this but for my custom scope only. This seems to fail in that nothing is explicitly ending the lifecycle of the beans, despite the fact that I'm calling customScope.clear() when I receive the scope ending event; ending the scope doesn't seem to translate to "end all beans associated with this scope".
I've read Spring documentation extensively and it seems to be clear that Spring doesn't manage the lifecycle of these custom beans in that it doesn't know when or how they should be destroyed, which means that it must be told when and how to destroy them; I've tried to read and understand the Session and Request scopes as provided by Spring so that I can mimic this but am missing something (again, these are not available to me since this is not a web-aware application and I'm not using HttpRequests and it is a non-trivial change in our application's structure)
Is anyone out there able to point me in the right direction?
I have the following code examples:
Xml Context Configuration:
<int-ip:tcp-connection-factory id="serverConnectionFactory" type="server" port="19000"
serializer="javaSerializer" deserializer="javaDeserializer"/>
<int-ip:tcp-inbound-gateway id="inGateway" connection-factory="serverConnectionFactory"
request-channel="incomingServerChannel" error-channel="errorChannel"/>
<int:channel id="incomingServerChannel" />
<int:chain input-channel="incomingServerChannel">
<int:service-activator ref="transactionController"/>
</int:chain>
TransactionController (handles request):
#Component("transactionController")
public class TransactionController {
#Autowired
private RequestWrapper requestWrapper;
#ServiceActivator
public String handle(final Message<?> requestMessage) {
// object is passed around through various phases of application
// object is changed, things are added, and finally, a response is generated based upon this data
tcpRequestCompletePublisher.publishEvent(requestWrapper, "Request lifecycle complete.");
return response;
}
}
TcpRequestScope (scope definition):
#Component
public class TcpRequestScope implements Scope {
private final ThreadLocal<ConcurrentHashMap<String, Object>> scopedObjects =
new InheritableThreadLocal<ConcurrentHashMap<String, Object>>({
#Override
protected ConcurrentHashMap<String, Object> initialValue(){
return new ConcurrentHashMap<>();
}
};
private final Map<String, Runnable> destructionCallbacks =
Collections.synchronizedMap(new HashMap<String, Runnable>());
#Override
public Object get(final String name, final ObjectFactory<?> objectFactory) {
final Map<String, Object> scope = this.scopedObjects.get();
Object object = scope.get(name);
if (object == null) {
object = objectFactory.getObject();
scope.put(name, object);
}
return object;
}
#Override
public Object remove(final String name) {
final Map<String, Object> scope = this.scopedObjects.get();
return scope.remove(name);
}
#Override
public void registerDestructionCallback(final String name, final Runnable callback) {
destructionCallbacks.put(name, callback);
}
#Override
public Object resolveContextualObject(final String key) {
return null;
}
#Override
public String getConversationId() {
return String.valueOf(Thread.currentThread().getId());
}
public void clear() {
final Map<String, Object> scope = this.scopedObjects.get();
scope.clear();
}
}
TcpRequestCompleteListener:
#Component
public class TcpRequestCompleteListener implements ApplicationListener<TcpRequestCompleteEvent> {
#Autowired
private TcpRequestScope tcpRequestScope;
#Override
public void onApplicationEvent(final TcpRequestCompleteEvent event) {
// do some processing
// clear all scope related data (so next thread gets clean slate)
tcpRequestScope.clear();
}
}
RequestWrapper (object we use throughout request lifecycle):
#Component
#Scope(scopeName = "tcpRequestScope", proxyMode =
ScopedProxyMode.TARGET_CLASS)
public class RequestWrapper implements Serializable, DisposableBean {
// we have many fields here which we add to and build up during processing of request
// actual request message contents will be placed into this class and used throughout processing
#Override
public void destroy() throws Exception {
System.out.print("Destroying RequestWrapper bean");
}
}
After many months and a few more attempts, I finally stumbled across some articles which pointed me in the right direction. Specifically, references in David Winterfeldt's blog post helped me understand the SimpleThreadScope which I had previously read, and was well aware of the fact that Spring makes no attempt to clear the scope after its lifecycle is complete, however, his article demonstrated the missing link for all previous implementations I had seen.
Specifically, the missing links were static references to ThreadScopeContextHolder in ThreadScope class in his implementation (in my proposed implementation above I called mine TcpRequestScope; the rest of this answer uses David Winterfeldt's terms since his reference documentation will prove most useful, and he wrote it).
Upon closer inspection of the Custom Thread Scope Module I noticed I was missing the ThreadScopeContextHolder, which contained a static reference to a ThreadLocal, which contains a ThreadScopeAttributes object which is what holds in-scope objects.
Some minor differences between David's implementation and my final one were, after Spring Integration sends its response, I use a ChannelInterceptor to clear the thread scope, since I'm using Spring Integration. In his examples, he extended threads which included a call to the context holder as part of a finally block.
How I'm clearing the scope attributes / beans:
public class ThreadScopeInterceptor extends ChannelInterceptorAdapter {
#Override
public void afterSendCompletion(final Message<?> message, final MessageChannel channel, final boolean sent,
#Nullable final Exception exception) {
// explicitly clear scope variables
ThreadScopeContextHolder.clearThreadScopeState();
}
Additionally, I added a method in the ThreadScopeContextHolder which clears the ThreadLocal:
public class ThreadScopeContextHolder {
// see: reference document for complete ThreadScopeContextHolder class
/**
* Clears all tcpRequest scoped beans which are stored on the current thread's ThreadLocal instance by calling
* {#link ThreadLocal#remove()}.
*/
public static void clearThreadScopeState() {
threadScopeAttributesHolder.remove();
}
}
While I'm not absolutely certain that there will not be memory leaks due to the ThreadLocal usage, I believe this will work as expected since I am calling ThreadLocal.remove(), which will remove the only reference to the ThreadScopeAttributes object, and therefore open it up to garbage collection.
Any improvements are welcomed, especially in terms of usage of ThreadLocal and how this might cause problems down the road.
Sources:
David Winterfeldt's Custom Thread Scope Module
Spring By Example Custom Thread Scope Module github (See David Winterfeldt's example above)
jyore's spring scopes (specifically, thread scope)
David Noel's (Devbury) Spring Boot Starter Thread Scope
I'm trying to implement a database authentication with Eclipse Scout.
For that I created a class DataSourceCredentialVerifier in the client module, which implements the ICredentialVerifierinterface. Then I adapted the init method of the UiServletFilter class to use my verifier.
public class DataSourceCredentialVerifier implements ICredentialVerifier {
private static final Logger LOG = LoggerFactory.getLogger(DataSourceCredentialVerifier.class);
#Override
public int verify(String username, char[] password) throws IOException {
Object queryResult[][] = BEANS.get(IMySqlAuthService.class).load();
return AUTH_OK;
}
I haven't implemented any authentication logic yet. My task now is to establish a clean database connection.
For that I created the following interface in the shared module:
public interface IMySqlAuthService extends IService {
Object[][] load();
}
The implementation is in the server module:
public class MySqlAuthService implements IMySqlAuthService {
#Override
public Object[][] load() {
String sql = "select username, password from users ";
Object[][] queryResult = SQL.select(sql, null, null);
return queryResult;
}
}
First I want to see, if there is at least something in the query, but I get an AssertionException here:
Object queryResult[][] = BEANS.get(IMySqlAuthService.class).load();
org.eclipse.scout.rt.platform.util.Assertions$AssertionException: Assertion error: no instance found for query: interface org.eclipse.scout.app.shared.services.IMySqlAuthService
at org.eclipse.scout.rt.platform.util.Assertions.fail(Assertions.java:580)
at org.eclipse.scout.rt.platform.util.Assertions.assertNotNull(Assertions.java:87)
at org.eclipse.scout.rt.platform.BEANS.get(BEANS.java:41)
I don't get an instance of my MySqlAuthService implementation. I assume that the BeanManager should have created an instance for me. MySqlAuthService should be registered as a Bean, since my IMySqlAuthService interface extends from IService which has the #ApplicationScoped annotation.
Adding the #Bean annotation to MySqlAuthService results in the same exception.
Here some information about the BeanManager and annotations:
https://eclipsescout.github.io/6.0/technical-guide.html#sec-bean.manager
Here is another different approach s.o. tried, but it doesn't feel correct:
https://www.eclipse.org/forums/index.php/t/1079741/
How can I get my example to work with my service?
Here is the working solution with important explanations of Eclipse Scout principles.
The source is summarized information of the Eclipse-Scout-Technical-Guide.
In Scout there is a built in annotation: #TunnelToServer. Interfaces marked with this annotation are called on the server. The server itself ignores this annotation.
To achieve that a bean is registered on client side, this annotation is required. The platform cannot (!) directly create an instance for these beans, a specific producer is registered which creates a proxy that delegates the call to the server.
My first clear mistake was that I hadn't annotated the IMySqlAuthServicewith #TunnelToServer.
After this addition I got rid of the no instance AssertionError.
After that my code ran into the HTTP status-code: 403 access forbidden.
This occured because my code didn't run in the correct Thread. That is the current RunContext. I had to use this lines of code in my verify method of the DataSourceCredentialVerifier:
Subject subject = new Subject();
subject.getPrincipals().add(new SimplePrincipal("system"));
subject.setReadOnly();
RunContext runContext = RunContexts.copyCurrent().withSubject(subject);
Now one can use the runContext's call() or run() method, depending whether the code returns a result. The action is run in the current thread, meaning that the caller is blocked until completion.
Concrete example solution:
Object[][] result = runContext.call(new Callable<Object[][]>() {
#Override
public Object[][] call() throws Exception {
return BEANS.get(IMySqlAuthService.class).load();
}
});
//TODO implement authentication logic.
For more information about the RunContext see here:
https://eclipsescout.github.io/6.0/technical-guide.html#runcontext
In my JEE application, running on glassfish 3, I have the following situation:
MyFacade class
#Interceptors(SomeInterceptor.class)
public void delete(Flag somethingForTheInterceptor, String idToDelete) {
.......
}
#Interceptors(SomeInterceptor.class)
public void update(Flag somethingForTheInterceptor, MyStuff newStuff) {
.......
}
The variable somethingForTheInterceptor is not used in these methods, it is only used in the interceptor:
SomeInterceptor class
#AroundInvoke
public Object userMayAccessOutlet(InvocationContext ctx) throws Exception {
Flag flag = extractParameterOfType(Arrays.asList(ctx.getParameters()), Flag.class);
// some checks on the flag
}
Somehow it doesn't feel good to have a parameter that is not used in the method. Is there another way to "send" somethingForTheInterceptor to the interceptor?
UPDATE: The callers of delete() and update() have different ways of calculating the somethingForTheInterceptor variable. And this is not a constant. The information needed to calculate it is in the REST call. But the 2 REST methods have different input objects so it is not enough to inject the http request.
These are the callers:
MyResource class
#DELETE
#Path("/delete/{" + ID + "}")
public Response delete(#PathParam(ID) final String id) {
Flag flag = calculateFlagForInterceptor(id);
facade.delete(flag, id);
}
#POST
#Path("/update")
#Consumes(MediaType.APPLICATION_JSON + RestResourceConstants.CHARSET_UTF_8)
public Response update(final WebInputDTO updateDetails) throws ILeanException {
Flag flag = calculateFlagForInterceptor(updateDetails);
facade.update(flag, convertToMyStuff(updateDetails));
}
I was thinking - is it possible for the methods in the Resource to set the flag in some kind of Context, that can be later injected in the Interceptor?
In Java EE, Interceptors allow to add pre and post processings to a method.
So, the context of the Interceptor execution is the context of the method.
I was thinking - is it possible for the methods in the Resource to set
the flag in some kind of Context, that can be later injected in the
Interceptor?
Staless Service should be privileged when you may. So, you should avoid storing data on the server (ThreadLocal, Session, etc..).
The information needed to calculate it is
in the REST call.
Why ?
A Rest controller has no vocation to do computations and logic.
To solve your problem, are you sure you could not move the flag computation in your interceptor ?
By enhancing the interceptor responsibilities, you would have not need anly longer to transit the flag :
#AroundInvoke
public Object userMayAccessOutlet(InvocationContext ctx) throws Exception {
Flag flag = calculFlag(Arrays.asList(ctx.getParameters()));
// some checks on the flag
}
I am using Guice's RequestScoped and Provider in order to get instances of some classes during a user request. This works fine currently. Now I want to do some job in a background thread, using the same instances created during request.
However, when I call Provider.get(), guice returns an error:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot
access scoped object. Either we are not currently inside an HTTP Servlet
request, or you may have forgotten to apply
com.google.inject.servlet.GuiceFilter as a servlet
filter for this request.
afaik, this is due to the fact that Guice uses thread local variables in order to keep track of the current request instances, so it is not possible to call Provider.get() from a thread different from the thread that is handling the request.
How can I get the same instances inside new threads using Provider? It is possible to achieve this writing a custom scope?
I recently solved this exact problem. There are a few things you can do. First, read up on ServletScopes.continueRequest(), which wraps a callable so it will execute as if it is within the current request. However, that's not a complete solution because it won't forward #RequestScoped objects, only basic things like the HttpServletResponse. That's because #RequestScoped objects are not expected to be thread safe. You have some options:
If your entire #RequestScoped hierarchy is computable from just the HTTP response, you're done! You will get new instances of these objects in the other thread though.
You can use the code snippet below to explicitly forward all RequestScoped objects, with the caveat that they will all be eagerly instantiated.
Some of my #RequestScoped objects couldn't handle being eagerly instantiated because they only work for certain requests. I extended the below solution with my own scope, #ThreadSafeRequestScoped, and only forwarded those ones.
Code sample:
public class RequestScopePropagator {
private final Map<Key<?>, Provider<?>> requestScopedValues = new HashMap<>();
#Inject
RequestScopePropagator(Injector injector) {
for (Map.Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
Key<?> key = entry.getKey();
Binding<?> binding = entry.getValue();
// This is like Scopes.isSingleton() but we don't have to follow linked bindings
if (binding.acceptScopingVisitor(IS_REQUEST_SCOPED)) {
requestScopedValues.put(key, binding.getProvider());
}
}
}
private final BindingScopingVisitor<Boolean> IS_REQUEST_SCOPED = new BindingScopingVisitor<Boolean>() {
#Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == RequestScoped.class;
}
#Override
public Boolean visitScope(Scope scope) {
return scope == ServletScopes.REQUEST;
}
#Override
public Boolean visitNoScoping() {
return false;
}
#Override
public Boolean visitEagerSingleton() {
return false;
}
};
public <T> Callable<T> continueRequest(Callable<T> callable) {
Map<Key<?>, Object> seedMap = new HashMap<>();
for (Map.Entry<Key<?>, Provider<?>> entry : requestScopedValues.entrySet()) {
// This instantiates objects eagerly
seedMap.put(entry.getKey(), entry.getValue().get());
}
return ServletScopes.continueRequest(callable, seedMap);
}
}
I have faced the exact same problem but solved it in a different way. I use jOOQ in my projects and I have implemented transactions using a request scope object and an HTTP filter.
But then I created a background task which is spawned by the server in the middle of the night. And the injection is not working because there is no request scope.
Well. The solutions is simple: create a request scope manually. Of course there is no HTTP request going on but that's not the point (mostly). It is the concept of the request scope. So I just need a request scope that exists alongside my background task.
Guice has an easy way to create a request scope: ServletScope.scopeRequest.
public class MyBackgroundTask extends Thread {
#Override
public void run() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
doTask();
}
}
private void doTask() {
}
}
Oh, and you probably will need some injections. Be sure to use providers there, you want to delay it's creation until inside the created scope.
Better use ServletScopes.transferRequest(Callable) in Guice 4
We are using Guice in our project for DI. Currently we have some configurations(properties) that we load a t server startup from a file. These are then bound to all the components & used for all the requests.
But now, we have multiple property files & load them at startup. These configurations can be different per REST(Jersey) request as they depend on the input.
So, we need to bind these configurations dynamically for each request. I looked into Guice API for #RequestScoped, but did not find anything specificallyu helpful.
There are few questions similar to this, but no luck yet. Can you please help me with this.
I'm providing 2 ways of doing this and both are request scoped.
Using HttpServletRequest, for classes where you can Inject request object.
Using ThreadLocal, Generic way. It can be used in any class.
(NOTE: This method wouldn't work if your creating new threads in your code and want to access the value. In which case you'll have to pass the values through Objects to those threads)
I meant something like this:
public class RequestFilter implements ContainerRequestFilter {
#Context
private HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
List listOfConfig = //load Config;
request.setAttribute("LOADED_CONFIG",listOfConfig);
// If you want to access this value at some place where Request object cannot be injected (like in service layers, etc.) Then use below ThreadLocals.
ThreadLocalWrapper.getInstance().get().add("adbc"); // In general add your config here, instead of abdc.
}
}
My ThreadLocalWrapper looks like this:
public class ThreadLocalWrapper {
private static ThreadLocal<List<String>> listOfStringLocals; // You can modify this to a list of Object or an Object by itself.
public static synchronized ThreadLocal<List<String>> getInstance() {
if (listOfStringLocals == null) {
listOfStringLocals = new ThreadLocal<List<String>>() {
#Override
protected List<String> initialValue() {
return new ArrayList<String>();
}
};
}
return listOfStringLocals;
}
}
To Access the value:
In Controller - Inject HttpServletRequest Object and do getAttribute() to get the value. Since HttpServletRequest Object is requestScoped, you can set the loaded config. into this and access it in your controller's using request Object again.
In Any other part of the code - If HttpServletRequest is not available then you can always use the ThreadLocal example shown. To access this value.
public class GuiceTransactionImpl implements GuiceTransaction {
private String value = "";
public GuiceTransactionImpl(String text) {
value = text;
}
#Override
public String returnSuccess() {
return value + " Thread Local Value " + ThreadLocalWrapper.getInstance().get();
}
}