When to explicitly close ResourceResolver in Sling - sling

I've read on this blog about how to use resourceResolver properly. The author quotes
If you open a JCR session of a Sling ResourceResolver, you are also
responsible for closing it. On the other hand: If you get passed a
ResourceResolver or a Session object, do not call logout() or close()
on it.
I'm not able to grasp this concept, may be because of no code example in this case.
From what i know, i can get a ResourceResolver object via either request.getResourceResolver() in servlets, using #Reference SCR annotation in OSGi components, jsp's implicit resourceResolver object, using sling.getService() in jsp, and also via adapting to ResourceResolver object.
In all the ways of getting resourceResolver object, which ones should i close myself and what is the session associated with each of these objects ?

Think of it like a File resource.
if you open it, you are responsible for closing it
if you use a reference to the File, then it is not your responsibility to close it
Therefore, your code should open & close in the same scope.
If you obtain a resourceResolver FROM a resource, you did not open the resolver and you do not need to close it.
In the example from the blog, they generate a session from session = repo.loginAdministrative() (Repository no longer has this method); thus is responsible for calling session.logout() in the same scope (using the finally {...} block).

Related

When does JSF creates a session & what does it puts in a session map?

I am running Mojarra 2.2.0.
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
The managed bean action method is-
public void action() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
System.out.println(session.getId()); // not null for stateful views
}
For stateless views session.getId() throws NPE
For views which are not stateless-
Firing a GET request, there is JSESSIONID=340041C96D5AA446D761C3602F54A76D
I read it here that-
For client side state saving mechanism, JSF won't create the session
and will store the view state in a hidden input field with the name
javax.faces.ViewState in the form whenever necessary.
Further, it's mentioned here that
JSF will indeed autocreate the session because the JSF view state has
to be stored over there. If you set the JSF state saving method to
client instead of server, then it won't be stored in session and hence
no session needs to be created
I think the above line is a source for trouble for me.
If you set the JSF state saving method to client instead of server,
then it won't be stored in session // FULLY AGREED
and
hence no session needs to be created. // This confuses because for
client side saving mechanism, a session id gets generated by the
servlet container & hence there is a session associated with the
request.
In reference to the discussion which I had with BalusC in this question,
I created a HttpSessionListener-
#WebListener
public class MyHttpSessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
Thread.dumpStack();
}
public void sessionDestroyed(HttpSessionEvent event) {
}
}
See below attached screenshots(these 2 screenshots are for version 2.0.3, there must have been an old bug due to which the session was getting created)-
Libraby (Mojarra 2.2.0)-
When does JSF creates a session
Eaiest way to naildown this is creating a HttpSessionListener, putting a debug breakpoint on sessionCreated() method and inspecting the call stack who needed to get the session for the first time (and thus implicitly needs to create it).
In below example you will see a chain of getSession() calls in the call stack. You will see that FaceletViewHandlingStrategy.renderView() method is the one calling it for the first time.
After you click on FaceletViewHandlingStrategy.renderView() line in debugger's call stack, you will get into its source code (Maven will load source code automatically, otherwise you need to manually attach it).
You see, when server side state saving is enabled and the view to render is not transient (stateless), then JSF will implicitly create the session, just to ensure it's created on time in order to save the view (if the session was created later, e.g. during render response phase, you would otherwise risk exceptions like this Adding <h:form> causes java.lang.IllegalStateException: Cannot create a session after the response has been committed).
You'll in the source code also immediately see that when the state saving method is set to client, or when the view is stateless as in <f:view transient="true">, then JSF won't anymore implicitly create the session. Older JSF versions may do that as you figured, but this is to be accounted as a bug and ought to be fixed in a newer version.
If you would like to ensure statelessness and avoid accidental/unforeseen session creation, then you could just throw new IllegalStateException() inside sessionCreated() method. When that happens, you just have to look in call stack who's responsible for creating the session and then fix/change the code to not do that anymore.
what does it puts in a session map?
Under the covers, ExternalContext#getSessionMap() delegates to HttpSession#setAttribute()/getAttribute()/removeAttribute(). You can listen on those methods using a HttpSessionAttributeListener.
In below example you will see that ViewScopeContextManager.getContextMap() line calls SessionMap#put() method in order to put something in the session map. When you unfold the event argument, you will see the session attribute name and value, which is com.sun.faces.application.view.activeViewContexts and an empty ConcurrentHashMap respectively.
Indeed, I was using a #Named #ViewScoped which was referenced by an value expression on the particular page (you see EL resolver and Weld resolver further down in call stack). When you click ViewScopeContextManager.getContextMap() line in call stack, you'll see that it was just preparing a map in session scope in order to store view scoped beans.
That's just one example. There are more things which could be stored in the session. Using a debugger this way and inspecting the associated source code will tell a lot about the Why.

Typhoon: Injecting run-time arguments into a singleton

I'm trying to figure out how to inject run-time arguments into a singleton when it is created, and then have those arguments just be remembered from then on. I'm not sure if the interface for run-time arguments can support this, though. Say, for example, I have a Client object that requires a token, and has the following initializer:
+ (instancetype)initWithToken:(NSString *)token;
The token is obtained at runtime from the server and is different for every user, so I can't simply put the NSString in the definition. So I create the following method on my Typhoon assembly:
- (Client *)clientWithToken:(NSString *)token;
However, in the future (when I'm injecting this client into other classes), I won't have the token on hand to call this method with. So I would like to just be able to inject [self client], for example. Since the client is a singleton and has already been created, the token isn't necessary, anyway.
However, I can't seem to find a way to do this. Obviously, defining a separate method called client would just return a different client. Can I just call clientWithToken:nil and the argument will be ignored if the client already exists? Perhaps traversing the assembly's singletons array would work, but that is obviously very inelegant.
I have considered injecting by type (so I don't need a method to call), but I have multiple different clients of the same type, so I need to be explicit about which client to inject. Of course, there is also the option of removing this parameter from the initializer, and instead setting it as a property from outside the assembly; however this pattern is used throughout our application, so I would like to avoid rewriting that much code.
Thank you.
Reviewing the Typhoon User Guide's 'When to Use Runtime Arguments' shows that this scenario isn't really a good match. Runtime arguments are great when we have a top-level component that mixes some static dependencies with information that is known later - thus avoiding the creation of a custom 'factory' class. Its not possible to use them in the way described.
Instead consider the following suggestions:
Inject a shared context class
Create a mutable Session model object and register it with Typhoon. Update the state on this model when you have a token. Inject this into the clients, which will use this session information when making connections.
Aspect Hook
Hook your clients so that before a method is invoked the token information is available. This could be done by:
Using an Aspects library like this one.
Define a Protocol for the clients and wrap the base implementation in one that is security aware.

In which session/memory does ABAP store static attribute values?

My guess would be in the ABAP memory from the main session, but I'm not sure and cannot find anything in the documentation. Does anyone know for sure?
Check this article for the basic memory layout and terminology, unless you already have done so. The static attributes of a class are handled the same way the global variables of a function pool are (you might think of them as global variables of the class pool, but don't hit me too hard for that analogy). Whenever you open a new internal session (e. g. with SUBMIT), they are reinitialized. You could try to check this with a small program that recursively calls itself using SUBMIT ... AND RETURN for yourself.

Accessing user session from a custom routing class

Is there some way to acces the user object from a custom routing class?
I'd like to add a parameter when generating a url, and that parameter is inside the user session, so I need to access it.
The only way I found to access is using the sfContext::getInstance()->getUser(), but it's known to be inefficient.
Thanks!
I'd write it the way you mention - I've used that method in similar situations and never had an issue performance wise, and suspect you will be the same.
Also, never heard this mentioned as inefficient, but it is a little bit frowned upon because it couples the route to the context. An alternative that would overcome this would be to pass the variable to the route as you would any other parameter (or the user object if you need the whole thing). If you need to do this a lot, you can always make a custom url helper that wraps the existing url_for method, adding this param to any other details passed.
A workaround I have implemented (for now), is getting some data from somewhere (not ideal, I'm willing to access the user session yet), and set a new parameter inside $params, in the generate method of the custom routing class.
Hope it helps...

OpenRasta - Pass parameters to custom Codec

I've created a new custom JSON codec for OpenRasta which works fine.
I need to pass arguments to the codec's write method when the handler is executed but cannot find any documentation on how to do it.
I notice in the implemented WriteTo method, there is a string[] codecParameters parameter, however no idea how to pass them in.
Anyone come accross this problem before? Thanks
the codec parameters are per-request. They're intended to be used together with (for example) the PathSegmentAsParameterUriDecorator.
For example, if you enable that decorator, the path /resource;segment will be treated as /resource by openrasta, and a parameter will be created with the "segment" value, and passed to the codec.
If you wish to pass information to the codec from the handler, there's nothing there, as architecturally it goes against the design of OpenRasta, which specifically prevents handlers and codecs from talking to each others.
If you wish to pass configuration data to your codec, you use the Configuration property from the ICodec interface, which will be filled with whatever object you have provided at configuration time.
You provide the configuration object either through the paramter in the .TranscodedBy(object configuration) method, or if you do custom registration using the configuration metamodel, bu adding the configuration to your Configuration property on CodecModel (which incidently is used in the ResourceModel object created by the fluent API).
Do you have a specific scenario I can help with?

Resources