What is the difference between Session.getDefaultInstance(props, authenticator) and getInstance(props, authenticator)? In general, when will you choose one over the other?
I also read Java doc on getDefaultInstance(props, authenticator), but still couldn't able to make out the difference distinctly/clearly.
Hope experts can help me in understanding this better.
UPDATE: Actual reason that triggered to ask this question is: We've used Session.getDefaultInstance() method in some places within our web-based application. Sometimes, it throws java.lang.SecurityException: Access to default session denied, on quick googling, it suggested to use Session.getInstance() method instead. Hence, when one would choose one over the other?
If you read the documentation, you will see that
getDefaultInstance
Get the default Session object. If a default has not yet been setup, a new Session object is created and installed as the default.
Therefore, if one does not already exist, it call getInstance()
getInstance
Get a new Session object.
So, a new session object is created, regardless of whether one already exists.
FAQ says: https://javaee.github.io/javamail/FAQ#getdefaultinstance
Q: When should I use Session.getDefaultInstance and when should I
use Session.getInstance?
A: Almost all code should use Session.getInstance. The
Session.getDefaultInstance method creates a new Session the first
time it's called, using the Properties that are passed. Subsequent
calls will return that original Session and ignore any Properties you
pass in. If you want to create different Sessions with different
properties, Session.getDefaultInstance won't do that. If some other
code in the same JVM (e.g., in the same app server) has already
created the default Session with their properties, you may end up
using their Session and your properties will be ignored. This often
explains why your property settings seem to be ignored. Always use
Session.getInstance to avoid this problem.
Cause
This error is raised in the getDefaultInstance method in javax.mail.Session.java. According to this source code, this error occures when the default session object is already initialized, but authenticator instance is renewed or changed, or the class loader of the default session object is different from the argument authentificator's. Maybe the java source code using the default session instance of the java mail is recompiled and reloaded, or duplicate javamail class libraries are included into the Classpath of the environment.
it gives proper solution
javax.mail.Session.java file
public static synchronized Session getDefaultInstance(Properties props,
Authenticator authenticator) {
if (defaultSession == null)
defaultSession = new Session(props, authenticator);
else {
// have to check whether caller is allowed to see default session
if (defaultSession.authenticator == authenticator)
; // either same object or both null, either way OK
else if (defaultSession.authenticator != null &&
authenticator != null &&
defaultSession.authenticator.getClass().getClassLoader() ==
authenticator.getClass().getClassLoader())
; // both objects came from the same class loader, OK
else
// anything else is not allowed
throw new SecurityException("Access to default session denied");
}
return defaultSession;
}
For me, it was very important to use getInstance() instead of getDefaultInstance().
Because after mail session properties was changed, mail session still was storing old properties.
So getDefaultInstance() - it is looks like Singleton.
As docs said:
Note also that the Properties object is used only the first time this method is called, when a new Session object is created. Subsequent calls return the Session object that was created by the first call, and ignore the passed Properties object. Use the getInstance method to get a new Session object every time the method is called.
Related
If two threads are accessing this method on server, will it be thread safe? The threads are coming from GWT timer.
public UserDTO getUserFromSession()
{
UserDTO user = null;
HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
HttpSession session = httpServletRequest.getSession();
Object userObj = session.getAttribute("user");
if (userObj != null && userObj instanceof UserDTO)
{
user = (UserDTO) userObj;
}
return user;
}
A method is thread safe if it doesn't access to external (to the method) shared variables.
The problem in your code could be on that line of code:
HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
because this.getThreadLocalRequest() seems to access a shared variable.
To be sure post the whole class, but for what I can see it is not thread safe.
Also after the comment that explain what getThreadLocalRequest method returns a HttpServletRequest safely the code remains not thread safe.
Infact HttpSession is not thread safe according to this article: basically the session can change during the code execution.
For example you can return the user also after an invalidation of the session.
Imagine this steps:
thread 1 thread 2
---------------------------------------------- --------------
Object userObj = session.getAttribute("user");
session.invalidate();
if (userObj != null && userObj instanceof UserDTO) {
user = (UserDTO) userObj;
}
return user;
At the end you return a user also if the session was invalidated by another thread.
This method in of itself is harmless. It would be harmless even if you did not have a thread local request. The only problem with it I see is the off case in which you retrieve attribute "user" while it is instantiated, and another thread wipes attribute "user" clean before the first thread can exit the method. You'd be dealing with a user instance in one thread and in the other, you might be performing logic differently due to the fact that "user" attribute is no longer defined.
That said, I sincerely doubt that any problems would arise since these are all methods that read and don't write with no side effects. Just be mindful of the fact that several threads could be (and probably will be) handling the same instance of user so you'll want to keep thread-sensitive operations on user under a synchronized block in that case.
Yes, it is threadsafe as far as only your given method is concerned.
getThreadLocalRequest() is local to your current thread and getSession() is threadsafe as well.
Even getting the userObj from the session should not cause issues.
But after all multiple calls could access the same UserDTO object.
Therefore you need to make sure that either possible changes in this object are done in a threadsafe way or that the object is immutable.
the method looks threadsafe but it isn't, but in a more subtile way:
While getSession() and Session is safe, the session and its contents are not.
The Session you were looking for can go away anytime. It is not enough to examine only this method, but all other session dependent objects as well.
In a high load situation, you need to take care, that your getuser function will not recreate the session on the fly.
getSession(false) will take care of this. You will have a null check on the Session returned and abort your call in that case.
The user object as stated by others before is another responsibility.
into a method I put an object into the HttpSession by this line:
req.getSession().setAttribute("docPDF", docPDF);
So the previous line put in the session the docPDF object (it is a ByteArrayOutputStream instance) with the name docPDF.
If in the debugger I do:
req.getSession().getAttribute("docPDF")
I can see this object, so it seems correctly putted into the HttpSession.
Then, into another method of my class I have to retrieve it, so I have try in this way:
docPDF = (ByteArrayOutputStream) req.getAttribute("docPDF");
but the problem is that I obtain that docPDF object is null.
Why? What I am missing? Maybe it could depend by the fact that this is into another HttpRequest?
How can I correctly retrieve this object that I putted into session?
Thanks
If you set a object in Session you have to get from Session only.
use this code.
docPDF = (ByteArrayOutputStream) req.getSession().getAttribute("docPDF")
in my java project web.xml, session timeout parameter set 5 minutes. After 5 minutes, all session object kill or it remains memory?
I had the same question once so I checked out tomcat source code. I did not check everything but I will as much as i did. There is a StandardSession class which has many method tow of the methods are related to this.
one of them is expire() which updates isValid variable to false.
there is another method recycle() which clears all attributes and reset many properties like lastAccessedTime, maxInactiveInterval etc.
Now I assume that these methods are being called when the session is timed out. So it does not kill them it recycles them.
I went into session manager ManagerBase to see if that it what it does. Whenever new request comes the the below method is being called(there are few other method calls before this).
/**
* Get a session from the recycled ones or create a new empty one.
* The PersistentManager manager does not need to create session data
* because it reads it from the Store.
*/
#Override
public Session createEmptySession() {
return (getNewSession());
}
I'm using vanilla Spring MVC with a custom FlashScope implementation. We basically use it to follow the Post-Redirect-Get pattern.
I've run into an odd situation. In my Post I do some searching for the parameters the user entered, and I set those instances onto FlashScope. I see those pieces working just fine.
In the object I place onto FlashScope I have a lazy loaded collection, however when I attempt to access the collection like so:
entity.getLazyLoadedCollection();
I receive the following stacktrace:
ERROR org.hibernate.LazyInitializationException IP127.0.0.1 CV#4c44559c-c576-4732 P#75004 - could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at core.model.entities.WorkflowState_$$_javassist_36.getFunctions(WorkflowState_$$_javassist_36.java)
The odd thing is that right before the call above I merge it onto the session in my service layer:
getSession().merge(entity);
Hibernate Documentation states that I should call update if I know that I'm working with a new session, but the JavaDocs make it seem like I should call merge...
As a workaround I've done the following:
if (getSession().contains(entity)) {
getHibernateTemplate().merge(person);
} else {
getSession.update(entity);
}
What should I be doing here?
Read the javadoc that you linked carefully: "Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session."
No matter what you pass to merge(), that object doesn't get associated to the session. You need to be working with the object returned from merge().
Never worked with FlashScope, but your error apeears to be because you are trying to access a LAZY collection which has not been initialized, and you are no longer in a layer of your app which has access to the Hibernate Session. If that assumption is correct, you need to initialize the collection where you have access to the Session (e.g., your DAO). Here are 2 basic ways:
Hibernate.initialize(object.getMyLazyCollection());
or
if(object.getMyLazyCollection() != null) {
object.getMyLazyCollection().size(); // forces a collection load
}
HTTPUrlConnection.setContentHandlerFactory()method throws Exception saying factory is already defined. I understand that. Is it possible to unset the factory and change the contenthandler factory?
The factory field in URLConnection (the superclass of HttpURLConnection) is a static package access member variable. The only place it's modified via the API is the setContentHandlerFactory() method, and as you've noted you can only call it once for any URL connection (or subclass) in the application.
I believe there is a way around it, but it's hardly ideal: You can reset and/or change the value of the factory field using reflection (assuming your application has appropriate security manager privileges to make the field accessible).
Here's a snippet that will do so:
ContentHandlerFactory newFactory = ... // create factory instance
factoryField = URLConnection.class.getDeclaredField( "factory" );
factoryField.setAccessible( true );
factoryField.set( null, newFactory );
The problem with this is that the API doesn't expect this will ever happen, so there may be unwanted side effects (since it applies to all URL connection subclasses). Basically you would be doing it at your own risk.