Announcement Announcement Module
Collapse
No announcement yet.
No session, transaction issue? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • No session, transaction issue?

    Hi,

    I'm having troubles with my session/transaction management. It's all good up to the point where I want my CRUD portlet to save data (from a form).

    OpenSessionInViewInterceptor should open a session for me (at least I think so), but it doesn't (is linked with the DefaultAnnotationHandlerMapping bean, which is the only handler mapping).

    For the people who read my other postins: I did some refactoring on my code, added a plain service layer which is class level annotated @Transactional with readonly=true, readonly=false for the writing methods on method level.

    applicationContext.xml:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    
    	<bean id="dataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName">
    			<value>com.mysql.jdbc.Driver</value>
    		</property>
    		[removed datasource config]
    	</bean>
    	<bean id="sessionFactory"
    		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    
    		<property name="mappingResources">
    			<list>
    				[hbms here]
    			</list>
    		</property>
    
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.session_factory_name">
    					SessionFactory
    				</prop>
    				<prop key="hibernate.dialect">
    					org.hibernate.dialect.MySQLDialect
          				</prop>
    				<prop key="hibernate.show_sql">false</prop>
    
    				<prop key="hibernate.connection.zeroDateTimeBehavior">convertToNull</prop>
    			</props>
    		</property>
    
    		<property name="dataSource">
    			<ref bean="dataSource" />
    		</property>
    	</bean>
    
    	<!--  Spring MVC -->
    	<!-- Abstract Default Exception Handler -->
    
    	<bean id="defaultExceptionHandlerTemplate"
    		class="org.springframework.web.portlet.handler.SimpleMappingExceptionResolver"
    		abstract="true">
    		<property name="defaultErrorView" value="defError" />
    		<property name="exceptionMappings">
    			<props>
    				<prop key="javax.portlet.PortletSecurityException">notAuthorized</prop>
    				<prop key="javax.portlet.UnavailableException">notAvailable</prop>
    			</props>
    		</property>
    	</bean>
    
    	<tx:annotation-driven transaction-manager="transactionManager" />
    
    	<bean id="transactionInterceptor"
    		class="org.springframework.transaction.interceptor.TransactionInterceptor">
    		<property name="transactionManager" ref="transactionManager" />
    		<property name="transactionAttributes">
    			<props>
    				<prop key="*">PROPAGATION_REQUIRED</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="transactionManager"
    		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    		<property name="dataSource" ref="dataSource" />
    		<property name="sessionFactory" ref="sessionFactory" />
    		<property name="nestedTransactionAllowed" value="true" />
    	</bean>
    
    
    	<import resource="dao.xml" />
    
    </beans>
    projekte-portlet.xml:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    
    	<context:annotation-config />
    
    	<!-- Service -->
    
    	<bean name="projekteService" class="com.company.myproject.service.ProjekteServiceImpl">
    		<property name="ProjektnamenHome" ref="ProjektnamenHome" />
    		<property name="ProjekteHome" ref="ProjekteHome" />
    	</bean>
    
    	<!-- Controllers -->
    
    	<bean name="projekteController" class="com.company.myproject.controller.ProjekteController">
    		<property name="projekteService" ref="projekteService" />
    	</bean>
    
    	<!-- Handler Mappings -->
    
    	<bean name="handlerMapping"
    		class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    		<property name="interceptors">
    			<list>
    				<ref bean="openSessionInViewInterceptor" />
    			</list>
    		</property>
    	</bean>
    
    	<!-- Interceptors -->
    
    	<bean name="openSessionInViewInterceptor"
    		class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
    		<property name="sessionFactory">
    			<ref bean="sessionFactory" />
    		</property>
    	</bean>
    
    	<!-- Exceptions Handlers -->
    
    	<bean id="defaultExceptionHandler" parent="defaultExceptionHandlerTemplate" />
    
    	<!-- Default View Resolver -->
    
    	<bean id="viewResolver"
    		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    		<property name="cache" value="true" />
    		<property name="viewClass"
    			value="org.springframework.web.servlet.view.JstlView" />
    		<property name="prefix" value="/WEB-INF/jsp/" />
    		<property name="suffix" value=".jsp" />
    	</bean>
    
    </beans>
    Stacktrace + DAO in next post
    Last edited by TRex2003; May 5th, 2010, 01:43 PM. Reason: solved

  • #2
    Stacktrace (after pressing submit):

    Code:
    16:50:06,025 DEBUG DispatcherPortlet:614 - DispatcherPortlet with name 'projekte' received action request
    16:50:06,027 DEBUG DispatcherPortlet:988 - Testing handler map [org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping@270d41e4] in DispatcherPortlet with name 'projekte'
    16:50:06,028 DEBUG DefaultAnnotationHandlerMapping:74 - Key [view] -> handler [{action=save=com.company.myproject.controller.ProjekteController@2debafce, action=edit=com.company.myproject.controller.ProjekteController@2debafce, =com.company.myproject.controller.ProjekteController@2debafce, action=viewSimple=com.company.myproject.controller.ProjekteController@2debafce}]
    16:50:06,028 DEBUG DispatcherPortlet:1029 - Testing handler adapter [org.springframework.web.portlet.mvc.SimpleControllerHandlerAdapter@4229708b]
    16:50:06,029 DEBUG DispatcherPortlet:1029 - Testing handler adapter [org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter@2e9bd79c]
    16:50:06,030 DEBUG HandlerMethodInvoker:327 - Invoking init-binder method: public void com.company.myproject.controller.ProjekteController.initBinder(org.springframework.web.bind.WebDataBinder)
    16:50:06,031 DEBUG HandlerMethodInvoker:146 - Invoking model attribute method: public com.company.myproject.bo.ProjekteProxy com.company.myproject.controller.ProjekteController.populateModel(java.lang.Integer)
    16:50:06,032 DEBUG HandlerMethodInvoker:327 - Invoking init-binder method: public void com.company.myproject.controller.ProjekteController.initBinder(org.springframework.web.bind.WebDataBinder)
    16:50:06,042 DEBUG HandlerMethodInvoker:165 - Invoking request handler method: public void com.company.myproject.controller.ProjekteController.save(com.company.myproject.bo.ProjekteProxy,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap,javax.portlet.ActionResponse,org.springframework.web.bind.support.SessionStatus)
    16:50:06,043  INFO ProjekteController:202 - Saving instance
    16:50:06,049 DEBUG ProjekteHome:98 - merging Projekte instance
    16:50:06,050 DEBUG SessionFactoryUtils:316 - Opening Hibernate Session
    16:50:06,051 DEBUG SessionFactoryUtils:789 - Closing Hibernate Session
    16:50:06,059 ERROR ProjekteHome:108 - merge failed
    org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
    	at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
    	at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:622)
    	at com.company.myproject.dbo.ProjekteHome.merge(ProjekteHome.java:101)
    	at com.company.myproject.service.ProjekteServiceImpl.mergeProjekt(ProjekteServiceImpl.java:72)
    	at com.company.myproject.controller.ProjekteController.save(ProjekteController.java:240)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:710)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:167)
    	at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:349)
    	at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.doHandle(AnnotationMethodHandlerAdapter.java:337)
    	at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.handleAction(AnnotationMethodHandlerAdapter.java:277)
    	at org.springframework.web.portlet.DispatcherPortlet.doActionService(DispatcherPortlet.java:646)
    	at org.springframework.web.portlet.FrameworkPortlet.processRequest(FrameworkPortlet.java:519)
    	at org.springframework.web.portlet.FrameworkPortlet.processAction(FrameworkPortlet.java:460)
    	at ....
    	at java.lang.Thread.run(Thread.java:619)
    16:50:06,069 DEBUG DispatcherPortlet:562 - Successfully completed request
    16:50:06,080 DEBUG DispatcherPortlet:694 - DispatcherPortlet with name 'projekte' received render request
    16:50:06,081 DEBUG DispatcherPortlet:709 - Render phase found exception caught during action phase - rethrowing it
    16:50:06,082 DEBUG SimpleMappingExceptionResolver:109 - Resolving exception from handler [null]: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
    16:50:06,085 DEBUG SimpleMappingExceptionResolver:140 - Resolving to default view 'defError' for exception of type [org.hibernate.HibernateException]
    16:50:06,086 DEBUG SimpleMappingExceptionResolver:225 - Exposing Exception as model attribute 'exception'
    16:50:06,088 DEBUG DispatcherPortlet:1162 - HandlerExceptionResolver returned ModelAndView [ModelAndView: reference to view with name 'defError'; model is {exception=org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here}] for exception
    16:50:06,089  WARN DispatcherPortlet:1164 - Handler execution resulted in exception - forwarding to resolved error view
    org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
    	at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
    	at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:622)
    	at com.company.myproject.dbo.ProjekteHome.merge(ProjekteHome.java:101)
    	at com.company.myproject.service.ProjekteServiceImpl.mergeProjekt(ProjekteServiceImpl.java:72)
    	at com.company.myproject.controller.ProjekteController.save(ProjekteController.java:240)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:710)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:167)
    	at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:349)
    	at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.doHandle(AnnotationMethodHandlerAdapter.java:337)
    	at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.handleAction(AnnotationMethodHandlerAdapter.java:277)
    	at org.springframework.web.portlet.DispatcherPortlet.doActionService(DispatcherPortlet.java:646)
    	at org.springframework.web.portlet.FrameworkPortlet.processRequest(FrameworkPortlet.java:519)
    	at org.springframework.web.portlet.FrameworkPortlet.processAction(FrameworkPortlet.java:460)
    	at ...
    	at java.lang.Thread.run(Thread.java:619)
    16:50:06,092 DEBUG DefaultListableBeanFactory:1444 - Invoking afterPropertiesSet() on bean with name 'defError'
    16:50:06,093 DEBUG DispatcherPortlet:1086 - Setting portlet response content type to view-determined type [text/html;charset=ISO-8859-1]
    16:50:06,094 DEBUG JstlView:328 - Added model object 'exception' of type [org.hibernate.HibernateException] to request in view with name 'defError'
    16:50:06,095 DEBUG JstlView:227 - Including resource [/WEB-INF/jsp/defError.jsp] in InternalResourceView 'defError'
    16:50:06,226 DEBUG DispatcherPortlet:562 - Successfully completed request
    Shortened DAO, fixed exceptions:

    Code:
    public class ProjekteHome
    	{
    
    	private static final Log log = LogFactory.getLog(ProjekteHome.class);
    
    	private SessionFactory sessionFactory = null;
    
    	public SessionFactory getSessionFactory()
    		{
    		return sessionFactory;
    		}
    
    	public void setSessionFactory(SessionFactory sessionFactory)
    		{
    		this.sessionFactory = sessionFactory;
    		}
    
    	public void persist(Projekte transientInstance)
    		{
    		log.debug("persisting Projekte instance");
    		sessionFactory.getCurrentSession().persist(transientInstance);
    		log.debug("persist successful");
    		}
    
    
    	
    	public void delete(Projekte persistentInstance)
    		{
    		log.debug("deleting Projekte instance");
    		sessionFactory.getCurrentSession().delete(persistentInstance);
    		log.debug("delete successful");
    		}
    
    	public Projekte merge(Projekte detachedInstance)
    		{
    		log.debug("merging Projekte instance");
    		Projekte result = (Projekte) sessionFactory.getCurrentSession().merge(
    				detachedInstance);
    		log.debug("merge successful");
    		return result;
    		}
    
    	public Projekte findById(java.lang.Integer id)
    		{
    		log.debug("getting Projekte instance with id: " + id);
    		Projekte instance = (Projekte) sessionFactory.getCurrentSession().get(
    				"com.credis.creplan.dbo.Projekte", id);
    		if (instance == null)
    			{
    			log.debug("get successful, no instance found");
    			}
    		else
    			{
    			log.debug("get successful, instance found");
    			}
    		return instance;
    		}
    
    	@SuppressWarnings("unchecked")
    	public List<Projekte> list()
    		{
    		log.debug("listing Projekte");
    		List results = sessionFactory.getCurrentSession().createCriteria(
    				"com.credis.creplan.dbo.Projekte").list();
    		log.debug("list successful, result size: " + results.size());
    		return results;
    		}
    
    	public Integer save(Projekte pProjekt)
    		{
    		Integer lRw;
    		log.debug("saving Projekte instance");
    		lRw = (Integer) sessionFactory.getCurrentSession().save(pProjekt);
    		log.debug("attach successful");
    		return lRw;
    		}
    	}
    Last edited by TRex2003; May 4th, 2010, 11:30 AM.

    Comment


    • #3
      Very similiar zombie-thread:

      http://forum.springsource.org/showthread.php?t=41762

      Almost the same problem, except that I'm not using the old controller hierarchy. I'm clear about the source of my formBackingObject; it's fetched again (old state) from db, filled with the new data from my form and merged again.

      The two calls (load edit form, submit edit form) differ at two locations:

      1. First line, it's not an render request, but an action request.
      2. Fourth line, render requests invokes the OSIV-Interceptor, action request doesn't.

      The Logs:

      render:
      Code:
      12:48:52,361 DEBUG DispatcherPortlet:694 - DispatcherPortlet with name 'projekte' received render request
      12:48:52,363 DEBUG DispatcherPortlet:988 - Testing handler map [org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping@379c032f] in DispatcherPortlet with name 'projekte'
      12:48:52,363 DEBUG DefaultAnnotationHandlerMapping:74 - Key [view] -> handler [{action=save=com.company.myproject.controller.ProjekteController@7fd00a54, action=edit=com.company.myproject.controller.ProjekteController@7fd00a54, =com.company.myproject.controller.ProjekteController@7fd00a54, action=viewSimple=com.company.myproject.controller.ProjekteController@7fd00a54}]
      12:48:52,364 DEBUG OpenSessionInViewInterceptor:154 - Opening single Hibernate Session in OpenSessionInViewInterceptor
      12:48:52,379 DEBUG SessionFactoryUtils:316 - Opening Hibernate Session
      12:48:52,383 DEBUG DispatcherPortlet:1029 - Testing handler adapter [org.springframework.web.portlet.mvc.SimpleControllerHandlerAdapter@2dd3adc0]
      12:48:52,383 DEBUG DispatcherPortlet:1029 - Testing handler adapter [org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter@24342fc1]
      12:48:52,387 DEBUG HandlerMethodInvoker:327 - Invoking init-binder method: public void com.company.myproject.controller.ProjekteController.initBinder(org.springframework.web.bind.WebDataBinder)
      12:48:52,399 DEBUG HandlerMethodInvoker:146 - Invoking model attribute method: public com.company.myproject.dbo.Projekte com.company.myproject.controller.ProjekteController.populateModel(java.lang.Integer,javax.portlet.PortletSession,org.springframework.web.bind.support.SessionStatus)
      12:48:52,412 DEBUG HandlerMethodInvoker:327 - Invoking init-binder method: public void com.company.myproject.controller.ProjekteController.initBinder(org.springframework.web.bind.WebDataBinder)
      12:48:52,414 DEBUG HandlerMethodInvoker:165 - Invoking request handler method: public java.lang.String com.company.myproject.controller.ProjekteController.edit(java.lang.Integer,org.springframework.ui.ModelMap,org.springframework.web.bind.support.SessionStatus)
      12:48:52,415  INFO ProjekteController:190 - edit project #2
      12:48:52,419 DEBUG ProjekteHome:114 - getting Projekte instance with id: 2
      12:48:52,423 DEBUG DriverManagerDataSource:162 - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost:3306/myproject]
      12:48:52,434 DEBUG ProjekteHome:125 - get successful, instance found
      [...]
      submit:
      Code:
      12:49:20,075 DEBUG DispatcherPortlet:614 - DispatcherPortlet with name 'projekte' received action request
      12:49:20,076 DEBUG DispatcherPortlet:988 - Testing handler map [org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping@379c032f] in DispatcherPortlet with name 'projekte'
      12:49:20,077 DEBUG DefaultAnnotationHandlerMapping:74 - Key [view] -> handler [{action=save=com.company.myproject.controller.ProjekteController@7fd00a54, action=edit=com.company.myproject.controller.ProjekteController@7fd00a54, =com.company.myproject.controller.ProjekteController@7fd00a54, action=viewSimple=com.company.myproject.controller.ProjekteController@7fd00a54}]
      12:49:20,077 DEBUG DispatcherPortlet:1029 - Testing handler adapter [org.springframework.web.portlet.mvc.SimpleControllerHandlerAdapter@2dd3adc0]
      12:49:20,078 DEBUG DispatcherPortlet:1029 - Testing handler adapter [org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter@24342fc1]
      12:49:20,079 DEBUG HandlerMethodInvoker:327 - Invoking init-binder method: public void com.company.myproject.controller.ProjekteController.initBinder(org.springframework.web.bind.WebDataBinder)
      12:49:20,080 DEBUG HandlerMethodInvoker:146 - Invoking model attribute method: public com.company.myproject.dbo.Projekte com.company.myproject.controller.ProjekteController.populateModel(java.lang.Integer,javax.portlet.PortletSession,org.springframework.web.bind.support.SessionStatus)
      12:49:20,081  INFO ProjekteController:207 - lookup project with id 2
      12:49:20,082 DEBUG ProjekteHome:114 - getting Projekte instance with id: 2
      12:49:20,082 DEBUG SessionFactoryUtils:316 - Opening Hibernate Session
      12:49:20,083 DEBUG SessionFactoryUtils:789 - Closing Hibernate Session
      12:49:20,087 ERROR ProjekteHome:131 - get failed
      org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
      	at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
      	at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:622)
      	at com.company.myproject.dbo.ProjekteHome.findById(ProjekteHome.java:117)
      	at com.company.myproject.controller.ProjekteController.populateModel(ProjekteController.java:210)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      I can't find my problem here..is OSIVI not able to handle action requests (don't think so)? The first request and session is closed after the jsp has loaded.

      Comment


      • #4
        First of all, I am not able to see your dao.xml - am i missing anything?

        Then you have defined the service in the config xml projekte-portlet.xml above. But the txmanager is in another xml applicationContext.xml isnt it?

        One important aspect is: When you define a TxManager this manager would look for @Transactional annotation in the beans defined within the same application context. Please check this link point # 6.

        Let us know what happens?

        Priya

        My blog: Spring/ Hibernate Tips

        Comment


        • #5
          You're brilliant!

          It was exactly the issue you've said. I moved the transaction bean to the portlet context and it just worked.

          The dao.xml just contains my dao-beans, wired with the session factory. Nothing special, and because of the char limit, I decided not to post it (in a 3rd post).

          Btw, the OSIVI really intercepts only for render requests. I saw it now in the logs.

          Big thanks!

          Comment


          • #6
            That was nice!

            Thanks
            Priya

            My blog: Spring/Hibernate Tips

            Comment

            Working...
            X