I'm not sure if we are still at the stripes mailing list ... something went wrong :-( http://www.nabble.com/Maximum-connections-reached---hibernate-session.close()---td23834269.html So please have a look at the quoted part below:
On Mon, Jun 8, 2009 at 10:29 AM, Morten Matras<morten.mat...@gmail.com> wrote: > Thanks a lot for the arguments. These seems to be completely valid and based > on best practice. > > It would be nice to have other people to discuss this issue, since the > service based way of doing this differs quite a lot from what many stripers > are doing now. > > Please speak up fellow stripers. Should we switch from filter based session > management to service based? > > Morten Matras > > 2009/6/8 Richard Hauswald <richard.hausw...@googlemail.com> >> >> DOS: If a filter opens a DB connection every time a request comes in, >> its no problem to DOS the apps connection pool with many requests even >> to non existing pages/ActionBeans . IMHO this is an argument. >> >> Testability is also a big argument. How would you test the database >> mappings and operations if they are scattered throw all your >> ActionBeans? IMHO this means testing the whole ActionBean with all the >> web related dependencies. It's much faster to test a service / dao (I >> don't use dao's). The same thing applies to ActionBeans. How to test a >> ActionBean doing complex hibernate stuff? Have fun mocking the whole >> hibernate framework... With a service you only have to mock one >> service call for the success and exception cases. That's pretty easy >> to do. >> >> If you use guice and bind the information which needs to be stored in >> the session using SessionScope you get rid of mocking the session. >> Just pass all dependencies to the constructor. It also frees you from >> managing the session keys. If you like doing that you can still do it >> using Names.named(String) - if you don't like them annotations are a >> superb alternative. Ever tried to find all references to an Object >> stored in the session? Using annotation based bindings you just right >> click the annotation and chose References - Project. >> >> Control: I don't like to be out of control of whats happening in my >> app. With the interceptor I posted earlier I'm the Captain of my >> vessel. If I don't want the interceptor to open a session, I just >> don't place the annotation. If I open the session myself, I do have >> full control over transaction and session handling. I can even use >> multiple connections - without the need to deal with intrusive >> frameworks(Like Spring...) at run time or unit testing. >> >> Last but not least there are some OOP rules out there... One of them >> is called Single Responsibility Principle. Merging Web and Service >> layer in one Class is bad. Merging Web and Service Layer in one method >> is evil :-) >> >> RAD is not evil. At least if you just need a one shot application >> which will never get extended / changed and your customers are >> satisfied with the default functionality of the RAD Framework. >> >> But be aware that this is my personal opinion. Others may differ :-) >> >> On Mon, Jun 8, 2009 at 9:54 AM, Morten Matras<morten.mat...@gmail.com> >> wrote: >> > I think that to find things about stripersist you should try googling >> > stripernate. http://www.google.dk/search?q=stripernate >> > >> > Stripernate has a similar (filterbased) approach as my framework. It >> > would >> > be nice to hear some more arguments for introducing a servicelayer based >> > architechture instead of a filterbased. You mention a DOS attack as a >> > reason, and something about a possible separation (EJB-like) between web >> > and >> > dao. This all sounds interesting, but would require some work and >> > therefore >> > I need some arguments.. >> > >> > Thanks >> > >> > Morten >> > >> > >> > >> > 2009/6/7 Richard Hauswald <richard.hausw...@googlemail.com> >> >> >> >> I dint know stripersist but I think it is a hibernate solution similar >> >> to grails and other RAD solutions. The proposed solution is not a >> >> solution like stripersist. It introduces a new layer in your >> >> application. So in order to store a user, stripes is only used as web >> >> component, doing request parameter mapping, validation and event >> >> management. It calls then the service layer and the service layer >> >> stores the user in a database. So you'll have to do more than save() >> >> and commit / rollback. I wrote a simple helper class doing the basic >> >> crud stuff: >> >> public class HibernateCRUDService<T extends PersistentObject> { >> >> private final Class<T> clazz; >> >> >> >> public HibernateCRUDService(Class<T> clazz) { >> >> this.clazz = clazz; >> >> } >> >> >> >> �...@suppresswarnings("unchecked") >> >> public T retrieve(Session session, Long id) throws >> >> EntityNotFoundException { >> >> T ret = (T) session.get(clazz, id); >> >> if (ret == null) >> >> throw new EntityNotFoundException(); >> >> return ret; >> >> } >> >> >> >> public void create(Session session, T persistentObject) { >> >> session.save(persistentObject); >> >> session.flush(); >> >> } >> >> >> >> public void update(Session session, T persistentObject) { >> >> session.update(persistentObject); >> >> session.flush(); >> >> } >> >> >> >> public void delete(Session session, Long id, Long version) >> >> throws >> >> EntityNotFoundException { >> >> // NOTE this is to work around >> >> // >> >> http://opensource.atlassian.com/projects/hibernate/browse/HHH-2792 >> >> // where not-null-constraints are checked when calling >> >> delete >> >> T sessionPersistentObject = retrieve(session, id); >> >> session.evict(sessionPersistentObject); >> >> sessionPersistentObject.setVersion(version); >> >> session.delete(sessionPersistentObject); >> >> session.flush(); >> >> } >> >> >> >> Every service is using this component, so the user uservice is doing >> >> the following: >> >> @ReadWriteSession >> >> �...@serviceexceptionintercepted >> >> public void create(User user) throws ServiceException { >> >> try { >> >> hibernateCRUDService.create(session, user); >> >> } catch (ConstraintViolationException e) { >> >> log.error(MessageFormat.format("Could not create >> >> User {0}", user), e); >> >> throw new DuplicateUserNameException(); >> >> } >> >> >> >> } >> >> >> >> Notice that the service only takes care of specific exceptions that >> >> will lead to a specific error message the user gets displayed. All >> >> other exceptions are handled using a exception interceptor: >> >> public class ServiceExceptionInterceptor implements MethodInterceptor { >> >> private static final Log log = >> >> LogFactory.getLog(ServiceExceptionInterceptor.class); >> >> >> >> �...@override >> >> public Object invoke(MethodInvocation invocation) throws >> >> Throwable >> >> { >> >> try { >> >> return invocation.proceed(); >> >> } catch (ServiceException e) { >> >> throw e; >> >> } catch (Exception e) { >> >> Class<? extends Object> invokedClass = >> >> invocation.getThis().getClass(); >> >> String invokedMethodName = >> >> invocation.getMethod().getName(); >> >> String paramString = >> >> buildParamString(invocation.getArguments()); >> >> log.error(MessageFormat.format("Unexpected >> >> exception invoking >> >> {0}.{1}{2}", invokedClass, invokedMethodName, >> >> paramString), e); >> >> throw new ServiceException(); >> >> } >> >> } >> >> >> >> private String buildParamString(Object[] arguments) { >> >> StringBuilder sb = new StringBuilder("("); >> >> for (Object object : arguments) { >> >> sb.append(String.valueOf(object)).append(", "); >> >> } >> >> sb.append(")"); >> >> return sb.toString(); >> >> } >> >> } >> >> Notice that this one only handles exceptions which are not an instance >> >> of serviceException since these exceptions are meant to reach the web >> >> layer. >> >> >> >> If you need to do more complex things like searches or complex update >> >> and delete operations which can not be done using constraints you'll >> >> do this in a separate service method. >> >> >> >> IMHO this enables easy testing of actionBeans and services(eg. >> >> database operations) and helps to keep the actionBeans clean. If the >> >> app grows its easy to separate the web part to another machine and use >> >> the service layer over a web service framework like hessian. It also >> >> makes it possible to divide the development into web and service >> >> development so the work can be striped over more than one developer. >> >> >> >> Since I dont know stripersist in detail I'm interested in the >> >> documentation of stripersist. Googled it but without any luck. Can >> >> someone provide a link? >> >> >> >> Let me know if the 3-tier way is something you want to use and you >> >> have further questions, >> >> Richard >> >> On Wed, Jun 3, 2009 at 1:22 PM, Morten Matras <kodekon...@gmail.com> >> >> wrote: >> >> > Hi Richard >> >> > >> >> > This sounds like a good and solid solution. Could you provide more >> >> > info >> >> > regarding this. >> >> > >> >> > I have no experience with guice, so I'll need some extra information >> >> > >> >> > 1) How do I set it up with an existing stripes / Hibernate >> >> > application? >> >> > Your >> >> > example seems to be an example making it possible to retrieve and >> >> > save >> >> > User >> >> > entities. What I'm looking for is something that works as smoothly as >> >> > stripernate where all entities are automatically binded and where all >> >> > I >> >> > have >> >> > to do is to save() and commit / rollback. >> >> > >> >> > Please provide a little extra information. >> >> > >> >> > Thanks >> >> > >> >> > Morten Matras >> >> > >> >> > >> >> > 2009/6/2 Richard Hauswald <richard.hausw...@googlemail.com> >> >> >> >> >> >> I would not recommend you to open database sessions in a filter, >> >> >> since >> >> >> there is a high risk that a non authenticated user can run a DOS >> >> >> attack if you do not define your filters in the correct order. >> >> >> Instead >> >> >> I'd recommend to use Google-Guice, stripes-guice and a annotation >> >> >> based interceptor solution using guice-aop stuff. A simple solution >> >> >> would look like this: >> >> >> The interceptor: >> >> >> public class SessionInterceptor implements MethodInterceptor { >> >> >> >> >> >> private static final Log log = >> >> >> LogFactory.getLog(SessionInterceptor.class); >> >> >> >> >> >> private final FlushMode flushMode; >> >> >> >> >> >> private final Provider<SessionFactory> >> >> >> sessionFactoryProvider; >> >> >> >> >> >> public SessionInterceptor(FlushMode flushMode, >> >> >> Provider<SessionFactory> sessionFactoryProvider) { >> >> >> this.flushMode = flushMode; >> >> >> this.sessionFactoryProvider = sessionFactoryProvider; >> >> >> } >> >> >> >> >> >> �...@override >> >> >> public Object invoke(MethodInvocation invocation) throws >> >> >> Throwable >> >> >> { >> >> >> if (log.isDebugEnabled()) >> >> >> log.debug(MessageFormat.format("Intecepting >> >> >> call >> >> >> to >> >> >> {0}.{1}", >> >> >> invocation.getThis().getClass(), invocation >> >> >> .getMethod())); >> >> >> SessionManagedService service = >> >> >> getService(invocation); >> >> >> SessionFactory sessionFactory = >> >> >> sessionFactoryProvider.get(); >> >> >> Session session = sessionFactory.openSession(); >> >> >> session.setFlushMode(flushMode); >> >> >> Transaction transaction = session.beginTransaction(); >> >> >> if(log.isDebugEnabled()) >> >> >> log.debug(MessageFormat.format("Injecting >> >> >> session({2}) before call >> >> >> to {0}.{1}", invocation.getThis().getClass(), invocation >> >> >> .getMethod().getName(), >> >> >> Integer.toString(session.hashCode(), 16))); >> >> >> service.setSession(session); >> >> >> try { >> >> >> final Object ret = invocation.proceed(); >> >> >> if (log.isDebugEnabled()) >> >> >> >> >> >> log.debug(MessageFormat.format("Commiting >> >> >> transaction after call >> >> >> to {0}.{1}", invocation.getThis() >> >> >> .getClass(), >> >> >> invocation.getMethod())); >> >> >> transaction.commit(); >> >> >> return ret; >> >> >> } catch (Exception e) { >> >> >> try { >> >> >> if (log.isDebugEnabled()) >> >> >> >> >> >> log.debug(MessageFormat.format("Rolling back transaction after >> >> >> call to {0}.{1}", invocation >> >> >> >> >> >> .getThis().getClass(), invocation.getMethod())); >> >> >> transaction.rollback(); >> >> >> } catch (Exception e1) { >> >> >> log.fatal("Cannot rollback >> >> >> transaction", >> >> >> e1); >> >> >> } >> >> >> throw e; >> >> >> } finally { >> >> >> try { >> >> >> if (log.isDebugEnabled()) >> >> >> >> >> >> log.debug(MessageFormat.format("Closing session after call to >> >> >> {0}.{1}", invocation >> >> >> >> >> >> .getThis().getClass(), invocation.getMethod())); >> >> >> session.close(); >> >> >> } catch (Exception e) { >> >> >> log.fatal("Cannot close session", e); >> >> >> } >> >> >> service.setSession(null); >> >> >> } >> >> >> } >> >> >> >> >> >> private SessionManagedService getService(MethodInvocation >> >> >> invocation) { >> >> >> final Object ret = invocation.getThis(); >> >> >> if (!(ret instanceof SessionManagedService)) >> >> >> throw new IllegalArgumentException("this >> >> >> inteceptor >> >> >> supports only >> >> >> instances of " >> >> >> + SessionManagedService.class >> >> >> + >> >> >> " >> >> >> but was passed an " + ret.getClass()); >> >> >> return (SessionManagedService) ret; >> >> >> } >> >> >> >> >> >> } >> >> >> >> >> >> The guice module binding: >> >> >> bindInterceptor(Matchers.subclassesOf(UserService.class), >> >> >> Matchers.annotatedWith(ReadOnlySession.class), >> >> >> new >> >> >> SessionInterceptor(FlushMode.MANUAL, >> >> >> binder().getProvider(SessionFactory.class))); >> >> >> bindInterceptor(Matchers.subclassesOf(UserService.class), >> >> >> Matchers.annotatedWith(ReadWriteSession.class), >> >> >> new >> >> >> SessionInterceptor(FlushMode.COMMIT, >> >> >> binder().getProvider(SessionFactory.class))); >> >> >> >> >> >> The service: >> >> >> public class UserService extends SessionManagedService { >> >> >> >> >> >> private static final Log log = >> >> >> LogFactory.getLog(LectureService.class); >> >> >> private final HibernateCRUDService<User> >> >> >> hibernateCRUDService; >> >> >> >> >> >> �...@inject >> >> >> public UserService(HibernateCRUDService<User> >> >> >> hibernateCRUDService) >> >> >> { >> >> >> this.hibernateCRUDService = hibernateCRUDService; >> >> >> } >> >> >> >> >> >> �...@readwritesession >> >> >> �...@serviceexceptionintercepted >> >> >> public void create(User user) throws ServiceException { >> >> >> try { >> >> >> hibernateCRUDService.create(session, user); >> >> >> } catch (ConstraintViolationException e) { >> >> >> log.error(MessageFormat.format("Could not >> >> >> create >> >> >> User {0}", user), e); >> >> >> throw new DuplicateUserNameException(); >> >> >> } >> >> >> >> >> >> } >> >> >> >> >> >> �...@readonlysession >> >> >> �...@serviceexceptionintercepted >> >> >> public User retrieve(Long id) throws ServiceException { >> >> >> return hibernateCRUDService.retrieve(session, id); >> >> >> } >> >> >> ... >> >> >> } >> >> >> >> >> >> You should also have a look at cp30 connection pooling and make sure >> >> >> that every database contact happens after a transaction was opened >> >> >> by >> >> >> a session.beginTransaction() which is committed or rolled back in >> >> >> any >> >> >> case. Make sure to not use Hibernate built in connection pool! ([ >> >> >> INFO] 21:17:01 >> >> >> org.hibernate.connection.DriverManagerConnectionProvider:64 >> >> >> - Using Hibernate built-in connection pool (not for production >> >> >> use!)) >> >> >> >> >> >> Regards, >> >> >> Richard >> >> >> >> >> >> On Tue, Jun 2, 2009 at 4:50 PM, Morten Matras >> >> >> <morten.mat...@gmail.com> >> >> >> wrote: >> >> >> > Let's start with the questions for you: >> >> >> > >> >> >> > - How do I modify the filter below / use another (downloadable) >> >> >> > filter >> >> >> > to >> >> >> > get a Hibernate Filter in my application that takes care of >> >> >> > transaction >> >> >> > management and commit / rollback for me that works on a windows >> >> >> > server >> >> >> > and >> >> >> > with an application that uses RedirectResolution? >> >> >> > - I consider switching to Stripernate (or whatever it's called >> >> >> > now a >> >> >> > days). >> >> >> > Would that be a good idea? >> >> >> > >> >> >> > >> >> >> > In our application http://www.redantenna.com I've added a >> >> >> > HibernateRequestFilter inspired by: >> >> >> > https://www.hibernate.org/43.html >> >> >> > >> >> >> > The architecture is something like: (MySQL - Hibernate - Tomcat - >> >> >> > JSP) >> >> >> > >> >> >> > In this filter I open a new session on every request and either >> >> >> > commit >> >> >> > it or >> >> >> > roll it back when the request is finished and the .jsp created and >> >> >> > returned. >> >> >> > >> >> >> > This has been working fine for years when deployed on linux >> >> >> > machines, >> >> >> > but >> >> >> > this application is deployed on a windows machine causing this >> >> >> > error: >> >> >> > >> >> >> > java.net.SocketException: No buffer space available (maximum >> >> >> > connections >> >> >> > reached?): JVM_Bind >> >> >> > at java.net.PlainSocketImpl.socketBind(Native Method) >> >> >> > at java.net.PlainSocketImpl.bind(Unknown Source) >> >> >> > at java.net.Socket.bind(Unknown Source) >> >> >> > at java.net.Socket.<init>(Unknown Source) >> >> >> > at java.net.Socket.<init>(Unknown Source) >> >> >> > >> >> >> > The application tries to connect to a mysql database (on another >> >> >> > server) >> >> >> > and >> >> >> > is using a port to do that. When this error occurs nothing but a >> >> >> > complete >> >> >> > reboot of the server helps. >> >> >> > >> >> >> > I took a look at the source code of the hibernate filter and found >> >> >> > that >> >> >> > the >> >> >> > session is never closed (unless that happens behind the scenes in >> >> >> > commit >> >> >> > and >> >> >> > rollback of the transaction). I tried adding a session.close() to >> >> >> > the >> >> >> > filter >> >> >> > but that caused errors when using RedirectResolution(...) in the >> >> >> > application. >> >> >> > >> >> >> > ---- >> >> >> > >> >> >> > Source code of the doFilter method in the HibernateRequestFilter: >> >> >> > >> >> >> > public void doFilter(ServletRequest request, >> >> >> > ServletResponse response, >> >> >> > FilterChain chain) >> >> >> > throws IOException, ServletException { >> >> >> > >> >> >> > try { >> >> >> > sf.getCurrentSession().beginTransaction(); >> >> >> > if (! sf.getCurrentSession().isConnected() ){ >> >> >> > >> >> >> > >> >> >> > >> >> >> > sf.getCurrentSession().reconnect(sf.getCurrentSession().connection()); >> >> >> > } >> >> >> > chain.doFilter(request, response); >> >> >> > } catch (StaleObjectStateException staleEx) { >> >> >> > throw staleEx; >> >> >> > } catch (Throwable ex) { >> >> >> > try { >> >> >> > if >> >> >> > (sf.getCurrentSession().getTransaction().isActive()) >> >> >> > { >> >> >> > log.debug("Trying to rollback database >> >> >> > transaction >> >> >> > after >> >> >> > exception"); >> >> >> > >> >> >> > sf.getCurrentSession().getTransaction().rollback(); >> >> >> > } >> >> >> > } catch (Throwable rbEx) { >> >> >> > log.error("Could not rollback transaction after >> >> >> > exception!", >> >> >> > rbEx); >> >> >> > } >> >> >> > >> >> >> > // Let others handle it... maybe another interceptor >> >> >> > for >> >> >> > exceptions? >> >> >> > throw new ServletException(ex); >> >> >> > } >> >> >> > finally{ >> >> >> > Session session = sf.getCurrentSession(); >> >> >> > Transaction transaction = session.getTransaction(); >> >> >> > //doCommit is an internal parameter telling the filter whether it >> >> >> > should >> >> >> > commit or rollback. >> >> >> > Boolean doCommit = (Boolean) >> >> >> > request.getAttribute("commit"); >> >> >> > if (doCommit != null && doCommit.booleanValue()){ >> >> >> > transaction.commit(); >> >> >> > } >> >> >> > if (transaction.isActive()){ >> >> >> > transaction.rollback(); >> >> >> > } >> >> >> > session.close(); >> >> >> > } >> >> >> > } >> >> >> > >> >> >> > --- >> >> >> > >> >> >> > With the last line: session.close(); the application is not able >> >> >> > to >> >> >> > handle >> >> >> > RedirectResolution correctly. It causes an error saying that the >> >> >> > session >> >> >> > is >> >> >> > closed. Without that the application get's the "maximum >> >> >> > connections >> >> >> > reached?" error causing the server to stop working. >> >> >> > >> >> >> > >> >> >> > >> >> >> > >> >> >> > -- >> >> >> > Morten Matras >> >> >> > Consultant >> >> >> > Blob Communication ApS >> >> >> > Svendsagervej 42 >> >> >> > DK-5240 Odense NØ >> >> >> > P: (+45) 76 6-5-4-3-2-1 >> >> >> > W: www.blobcom.com >> >> >> > E: morten.mat...@gmail.com >> >> >> > >> >> >> > >> >> >> > >> >> >> > >> >> >> > ------------------------------------------------------------------------------ >> >> >> > OpenSolaris 2009.06 is a cutting edge operating system for >> >> >> > enterprises >> >> >> > looking to deploy the next generation of Solaris that includes the >> >> >> > latest >> >> >> > innovations from Sun and the OpenSource community. Download a copy >> >> >> > and >> >> >> > enjoy capabilities such as Networking, Storage and Virtualization. >> >> >> > Go to: http://p.sf.net/sfu/opensolaris-get >> >> >> > _______________________________________________ >> >> >> > Stripes-users mailing list >> >> >> > Stripes-users@lists.sourceforge.net >> >> >> > https://lists.sourceforge.net/lists/listinfo/stripes-users >> >> >> > >> >> >> > >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ------------------------------------------------------------------------------ >> >> >> OpenSolaris 2009.06 is a cutting edge operating system for >> >> >> enterprises >> >> >> looking to deploy the next generation of Solaris that includes the >> >> >> latest >> >> >> innovations from Sun and the OpenSource community. Download a copy >> >> >> and >> >> >> enjoy capabilities such as Networking, Storage and Virtualization. >> >> >> Go to: http://p.sf.net/sfu/opensolaris-get >> >> >> _______________________________________________ >> >> >> Stripes-users mailing list >> >> >> Stripes-users@lists.sourceforge.net >> >> >> https://lists.sourceforge.net/lists/listinfo/stripes-users >> >> > >> >> > >> >> > >> >> > -- >> >> > Morten Matras >> >> > Consultant >> >> > Blob Communication ApS >> >> > Svendsagervej 42 >> >> > DK-5240 Odense NØ >> >> > P: (+45) 76 6-5-4-3-2-1 >> >> > W: www.blobcom.com >> >> > E: morten.mat...@gmail.com >> >> > >> >> > >> >> > >> >> > ------------------------------------------------------------------------------ >> >> > OpenSolaris 2009.06 is a cutting edge operating system for >> >> > enterprises >> >> > looking to deploy the next generation of Solaris that includes the >> >> > latest >> >> > innovations from Sun and the OpenSource community. Download a copy >> >> > and >> >> > enjoy capabilities such as Networking, Storage and Virtualization. >> >> > Go to: http://p.sf.net/sfu/opensolaris-get >> >> > _______________________________________________ >> >> > Stripes-users mailing list >> >> > Stripes-users@lists.sourceforge.net >> >> > https://lists.sourceforge.net/lists/listinfo/stripes-users >> >> > >> >> > >> > >> > >> > >> > -- >> > Morten Matras >> > Consultant >> > Blob Communication ApS >> > Svendsagervej 42 >> > DK-5240 Odense NØ >> > P: (+45) 76 6-5-4-3-2-1 >> > W: www.blobcom.com >> > E: morten.mat...@gmail.com >> > > > > > -- > Morten Matras > Consultant > Blob Communication ApS > Svendsagervej 42 > DK-5240 Odense NØ > P: (+45) 76 6-5-4-3-2-1 > W: www.blobcom.com > E: morten.mat...@gmail.com > ------------------------------------------------------------------------------ OpenSolaris 2009.06 is a cutting edge operating system for enterprises looking to deploy the next generation of Solaris that includes the latest innovations from Sun and the OpenSource community. Download a copy and enjoy capabilities such as Networking, Storage and Virtualization. Go to: http://p.sf.net/sfu/opensolaris-get _______________________________________________ Stripes-users mailing list Stripes-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/stripes-users