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 <[email protected]> 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: [email protected]
>
> ------------------------------------------------------------------------------
> 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
> [email protected]
> 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-users