0

I've read some of other questions on the same topic, but in my case I'm not actually specifying anything. What makes me really confused is I have another call that works. I don't specify any transactions so I'm not sure why this is becoming a problem.

This is what happens when I try to use xssSave() (in the service class at the bottom), but sqlInject (also in the same class) works fine. As far as I can tell these operate identically except that one works and one doesn't.

If you want to view the full code and/or check it out yourself, it's available on GitHub (https://github.com/tenmilez/WebBilly).

Spring configuration (split into 3 files):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
    <import resource="recipeasy-aspects.xml" />
    -->
    <import resource="webbilly-data.xml"/>
    <import resource="webbilly-spring.xml"/>
    <import resource="webbilly-service.xml"/>


    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="order">
            <value>0</value>
        </property>
        <property name="mappings">
            <props>
                <prop key="welcome.htm">welcomeController</prop>
                <prop key="sqli.htm">SQLiController</prop>
                <prop key="xss.htm">XssController</prop>
            </props>
        </property>
    </bean>

    <bean id="paramResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
        <property name="paramName" value="method"/>
        <property name="defaultMethodName" value="onInitPage"/>
    </bean>

    <bean id="welcomeController" class="com.webbilly.web.WelcomeController"/>

    <bean id="SQLiController" class="com.webbilly.web.SQLiController">
        <property name="methodNameResolver" ref="paramResolver"/>
        <property name="sqliServices" ref="sqliServices"/>
    </bean>

    <bean id="XssController" class="com.webbilly.web.XssController">
        <property name="methodNameResolver" ref="paramResolver"/>
        <property name="sqliServices" ref="sqliServices"/>
    </bean>
</beans>

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="sqliServices" class="com.webbilly.service.SQLiServices">
        <property name="sqliDataDAO" ref="sqliDataDAOhibernate"/>
        <!--
        <property name="sqliDataDAO" ref="sqliDataDAOjdbc" />
        <property name="sqliDataDAO" ref="sqliDataDAOhibernate" />
        -->


        <property name="xssDataDAO" ref="xssDataDAO"/>

    </bean>


</beans>

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="jdbcDataSource"/>
        <property name="mappingDirectoryLocations">
            <value>classpath:/com/webbilly/dao/hibernate/hbm</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.dialect">${database.dialect}</prop>
            </props>
        </property>
    </bean>

    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate4.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="genericDAO" class="com.webbilly.dao.hibernate.GenericDAO"
          abstract="true">
        <property name="hibernateTemplate" ref="hibernateTemplate"/>
    </bean>

    <bean id="sqliDataDAOhibernate" parent="genericDAO">
        <constructor-arg>
            <value>com.webbilly.domain.SQLiData</value>
        </constructor-arg>
    </bean>
    <bean id="xssDataDAO" parent="genericDAO">
        <constructor-arg>
            <value>com.webbilly.domain.XssData</value>
        </constructor-arg>
    </bean>

    <bean id="sqliDataDAOjdbc" class="com.webbilly.dao.jdbc.SQLiDAO">
        <property name="dataSource" ref="jdbcDataSource"/>
    </bean>

    <bean id="jdbcDataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${database.driver}"/>
        <property name="url" value="${database.url}"/>
        <property name="username" value="${database.username}"/>
        <property name="password" value="${database.password}"/>
        <property name="connectionProperties">
            <props>
                <prop key="allowMultiQueries">true</prop>
            </props>
        </property>
    </bean>

</beans>

My data objects (is there a name for these? Always referred to them as domain objects, but I'm not sure if that's widely accepted terminology).

package com.webbilly.domain;

/**
 * Created by christopher on 12/12/14.
 */
public class XssData {

    private int id;
    private String userName;
    private String message;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}


package com.webbilly.domain;

/**
 * Created by christopher on 12/3/14.
 */
public class SQLiData {

    private String id;
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

The persistence layer

package com.webbilly.dao;

import java.util.Collection;

public interface IGenericDAO<T> {
    void save(T t);

    Collection<T> getAll();

    T getById(int id);

    void delete(int id);
}

package com.webbilly.dao.hibernate;

import com.webbilly.dao.IGenericDAO;
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;

import java.util.Collection;

public class GenericDAO<T> extends HibernateDaoSupport implements IGenericDAO<T> {

    /**
     * ******************************************************
     * ********* Accessors and private members ****************
     * *******************************************************
     */

    private Class<T> type;

    public GenericDAO(Class<T> type) {
        this.type = type;
    }

    public T getById(int id) {
        return (T) getHibernateTemplate().get(type, id);
    }

    public Collection<T> getAll() {
        return getHibernateTemplate().loadAll(type);
    }

    public void save(T t) {
        getHibernateTemplate().saveOrUpdate(t);
    }

    public void delete(int id) {
        getHibernateTemplate().delete(getById(id));
    }

}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.webbilly.domain">
    <class name="SQLiData" table="sqli">
        <id column="id" name="id" type="int">
            <generator class="increment"/>
        </id>
        <property name="value" type="string">
            <column name="value"/>
        </property>
    </class>
</hibernate-mapping>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.webbilly.domain">
    <class name="XssData" table="xss">
        <id column="id" name="id" type="int">
            <generator class="increment"/>
        </id>
        <property name="userName" type="string">
            <column name="user_name"/>
        </property>
        <property name="message" type="string">
            <column name="message"/>
        </property>
    </class>
</hibernate-mapping>

The service layer (it really is just one class; my application is not that big yet).

package com.webbilly.service;

import com.webbilly.dao.IGenericDAO;
import com.webbilly.domain.SQLiData;
import com.webbilly.domain.XssData;

import java.util.Collection;

/**
 * Created by christopher on 12/3/14.
 */
public class SQLiServices {


    private IGenericDAO<SQLiData> sqliDataDAO;
    private IGenericDAO<XssData> xssDataDAO;

    public void sqlInject(String str) {
        SQLiData sqliData = new SQLiData();
        sqliData.setValue(str);
        getSqliDataDAO().save(sqliData);
    }

    public void xssSave(XssData data) {
        xssDataDAO.save(data);
    }

    public Collection<XssData> getAllPosts() {
        return xssDataDAO.getAll();
    }

    public IGenericDAO<SQLiData> getSqliDataDAO() {
        return sqliDataDAO;
    }

    public void setSqliDataDAO(IGenericDAO<SQLiData> sqliDataDAO) {
        this.sqliDataDAO = sqliDataDAO;
    }

    public IGenericDAO<XssData> getXssDataDAO() {
        return xssDataDAO;
    }

    public void setXssDataDAO(IGenericDAO<XssData> xssDataDAO) {
        this.xssDataDAO = xssDataDAO;
    }
}
tenmiles
  • 2,521
  • 3
  • 18
  • 20
  • Why are you writing your own DAO instead of using Spring Data? – chrylis -cautiouslyoptimistic- Jan 16 '15 at 00:06
  • @chrylis I'm not familiar with Spring Data. – tenmiles Jan 16 '15 at 00:09
  • It basically lets you write that interface and then generates all of the actual code for you (and standard methods like the ones you specified are built in). – chrylis -cautiouslyoptimistic- Jan 16 '15 at 00:17
  • The error suggests you are not using transactions. Do you not need to define a transaction manager: http://stackoverflow.com/questions/25222341/write-operations-are-not-allowed-in-read-only-mode-issue-while-persisting – JamesB Jan 16 '15 at 00:28
  • @JamesB This doesn't explain why it works for the sqlInject() method and not for the xssSave() method. As far as I know the transaction manager is optional until necessary for managing transactions (and I don't have transactions). – tenmiles Jan 16 '15 at 00:30

1 Answers1

0

HibernateTemplate doesn't manage transactions, you need a HibernateTransactionManager instead.

The write operations need to execute within the context of a transaction, so you need to also annotate you DAO or your services with @Transactional.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911