diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java
new file mode 100644
index 00000000000..b083e95b27e
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.io.IOException;
+import java.io.InputStream;
+import javax.servlet.ServletInputStream;
+
+import org.springframework.util.Assert;
+
+/**
+ * Delegating implementation of {@link javax.servlet.ServletInputStream}.
+ *
+ *
Used by {@link MockHttpServletRequest}; typically not directly
+ * used for testing application controllers.
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.2
+ * @see MockHttpServletRequest
+ */
+public class DelegatingServletInputStream extends ServletInputStream {
+
+ private final InputStream sourceStream;
+
+
+ /**
+ * Create a DelegatingServletInputStream for the given source stream.
+ * @param sourceStream the source stream (never null)
+ */
+ public DelegatingServletInputStream(InputStream sourceStream) {
+ Assert.notNull(sourceStream, "Source InputStream must not be null");
+ this.sourceStream = sourceStream;
+ }
+
+ /**
+ * Return the underlying source stream (never null).
+ */
+ public final InputStream getSourceStream() {
+ return this.sourceStream;
+ }
+
+
+ public int read() throws IOException {
+ return this.sourceStream.read();
+ }
+
+ public void close() throws IOException {
+ super.close();
+ this.sourceStream.close();
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java
new file mode 100644
index 00000000000..66fca5df2f9
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.servlet.ServletOutputStream;
+
+import org.springframework.util.Assert;
+
+/**
+ * Delegating implementation of {@link javax.servlet.ServletOutputStream}.
+ *
+ *
Used by {@link MockHttpServletResponse}; typically not directly
+ * used for testing application controllers.
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.2
+ * @see MockHttpServletResponse
+ */
+public class DelegatingServletOutputStream extends ServletOutputStream {
+
+ private final OutputStream targetStream;
+
+
+ /**
+ * Create a DelegatingServletOutputStream for the given target stream.
+ * @param targetStream the target stream (never null)
+ */
+ public DelegatingServletOutputStream(OutputStream targetStream) {
+ Assert.notNull(targetStream, "Target OutputStream must not be null");
+ this.targetStream = targetStream;
+ }
+
+ /**
+ * Return the underlying target stream (never null).
+ */
+ public final OutputStream getTargetStream() {
+ return this.targetStream;
+ }
+
+
+ public void write(int b) throws IOException {
+ this.targetStream.write(b);
+ }
+
+ public void flush() throws IOException {
+ super.flush();
+ this.targetStream.flush();
+ }
+
+ public void close() throws IOException {
+ super.close();
+ this.targetStream.close();
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/HeaderValueHolder.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/HeaderValueHolder.java
new file mode 100644
index 00000000000..afe74ad8f0f
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/HeaderValueHolder.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Internal helper class that serves as value holder for request headers.
+ *
+ * @author Juergen Hoeller
+ * @author Rick Evans
+ * @since 2.0.1
+ */
+class HeaderValueHolder {
+
+ private final List values = new LinkedList();
+
+
+ public void setValue(Object value) {
+ this.values.clear();
+ this.values.add(value);
+ }
+
+ public void addValue(Object value) {
+ this.values.add(value);
+ }
+
+ public void addValues(Collection> values) {
+ this.values.addAll(values);
+ }
+
+ public void addValueArray(Object values) {
+ CollectionUtils.mergeArrayIntoCollection(values, this.values);
+ }
+
+ public List getValues() {
+ return Collections.unmodifiableList(this.values);
+ }
+
+ public List getStringValues() {
+ List stringList = new ArrayList(this.values.size());
+ for (Object value : this.values) {
+ stringList.add(value.toString());
+ }
+ return Collections.unmodifiableList(stringList);
+ }
+
+ public Object getValue() {
+ return (!this.values.isEmpty() ? this.values.get(0) : null);
+ }
+
+ public String getStringValue() {
+ return (!this.values.isEmpty() ? this.values.get(0).toString() : null);
+ }
+
+
+ /**
+ * Find a HeaderValueHolder by name, ignoring casing.
+ * @param headers the Map of header names to HeaderValueHolders
+ * @param name the name of the desired header
+ * @return the corresponding HeaderValueHolder,
+ * or null if none found
+ */
+ public static HeaderValueHolder getByName(Map headers, String name) {
+ Assert.notNull(name, "Header name must not be null");
+ for (String headerName : headers.keySet()) {
+ if (headerName.equalsIgnoreCase(name)) {
+ return headers.get(headerName);
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockFilterChain.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockFilterChain.java
new file mode 100644
index 00000000000..3f5d5106c36
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockFilterChain.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Mock implementation of the {@link javax.servlet.FilterChain} interface. Used
+ * for testing the web framework; also useful for testing custom
+ * {@link javax.servlet.Filter} implementations.
+ *
+ *
A {@link org.springframework.mock.web.MockFilterChain} can be configured with one or more filters and a
+ * Servlet to invoke. The first time the chain is called, it invokes all filters
+ * and the Servlet, and saves the request and response. Subsequent invocations
+ * raise an {@link IllegalStateException} unless {@link #reset()} is called.
+ *
+ * @author Juergen Hoeller
+ * @author Rob Winch
+ * @author Rossen Stoyanchev
+ *
+ * @since 2.0.3
+ * @see org.springframework.mock.web.MockFilterConfig
+ * @see org.springframework.mock.web.PassThroughFilterChain
+ */
+public class MockFilterChain implements FilterChain {
+
+ private ServletRequest request;
+
+ private ServletResponse response;
+
+ private final List filters;
+
+ private Iterator iterator;
+
+
+ /**
+ * Register a single do-nothing {@link javax.servlet.Filter} implementation. The first
+ * invocation saves the request and response. Subsequent invocations raise
+ * an {@link IllegalStateException} unless {@link #reset()} is called.
+ */
+ public MockFilterChain() {
+ this.filters = Collections.emptyList();
+ }
+
+ /**
+ * Create a FilterChain with a Servlet.
+ *
+ * @param servlet the Servlet to invoke
+ * @since 3.2
+ */
+ public MockFilterChain(Servlet servlet) {
+ this.filters = initFilterList(servlet);
+ }
+
+ /**
+ * Create a {@code FilterChain} with Filter's and a Servlet.
+ *
+ * @param servlet the {@link javax.servlet.Servlet} to invoke in this {@link javax.servlet.FilterChain}
+ * @param filters the {@link javax.servlet.Filter}'s to invoke in this {@link javax.servlet.FilterChain}
+ * @since 3.2
+ */
+ public MockFilterChain(Servlet servlet, Filter... filters) {
+ Assert.notNull(filters, "filters cannot be null");
+ Assert.noNullElements(filters, "filters cannot contain null values");
+ this.filters = initFilterList(servlet, filters);
+ }
+
+ private static List initFilterList(Servlet servlet, Filter... filters) {
+ Filter[] allFilters = ObjectUtils.addObjectToArray(filters, new ServletFilterProxy(servlet));
+ return Arrays.asList(allFilters);
+ }
+
+ /**
+ * Return the request that {@link #doFilter} has been called with.
+ */
+ public ServletRequest getRequest() {
+ return this.request;
+ }
+
+ /**
+ * Return the response that {@link #doFilter} has been called with.
+ */
+ public ServletResponse getResponse() {
+ return this.response;
+ }
+
+ /**
+ * Invoke registered {@link javax.servlet.Filter}s and/or {@link javax.servlet.Servlet} also saving the
+ * request and response.
+ */
+ public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
+ Assert.notNull(request, "Request must not be null");
+ Assert.notNull(response, "Response must not be null");
+
+ if (this.request != null) {
+ throw new IllegalStateException("This FilterChain has already been called!");
+ }
+
+ if (this.iterator == null) {
+ this.iterator = this.filters.iterator();
+ }
+
+ if (this.iterator.hasNext()) {
+ Filter nextFilter = this.iterator.next();
+ nextFilter.doFilter(request, response, this);
+ }
+
+ this.request = request;
+ this.response = response;
+ }
+
+ /**
+ * Reset the {@link org.springframework.mock.web.MockFilterChain} allowing it to be invoked again.
+ */
+ public void reset() {
+ this.request = null;
+ this.response = null;
+ this.iterator = null;
+ }
+
+
+ /**
+ * A filter that simply delegates to a Servlet.
+ */
+ private static class ServletFilterProxy implements Filter {
+
+ private final Servlet delegateServlet;
+
+ private ServletFilterProxy(Servlet servlet) {
+ Assert.notNull(servlet, "servlet cannot be null");
+ this.delegateServlet = servlet;
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+
+ this.delegateServlet.service(request, response);
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ public void destroy() {
+ }
+
+ @Override
+ public String toString() {
+ return this.delegateServlet.toString();
+ }
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockFilterConfig.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockFilterConfig.java
new file mode 100644
index 00000000000..34cafd55fc1
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockFilterConfig.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+
+import org.springframework.util.Assert;
+
+/**
+ * Mock implementation of the {@link javax.servlet.FilterConfig} interface.
+ *
+ * Used for testing the web framework; also useful for testing
+ * custom {@link javax.servlet.Filter} implementations.
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.2
+ * @see MockFilterChain
+ * @see PassThroughFilterChain
+ */
+public class MockFilterConfig implements FilterConfig {
+
+ private final ServletContext servletContext;
+
+ private final String filterName;
+
+ private final Map initParameters = new LinkedHashMap();
+
+
+ /**
+ * Create a new MockFilterConfig with a default {@link MockServletContext}.
+ */
+ public MockFilterConfig() {
+ this(null, "");
+ }
+
+ /**
+ * Create a new MockFilterConfig with a default {@link MockServletContext}.
+ * @param filterName the name of the filter
+ */
+ public MockFilterConfig(String filterName) {
+ this(null, filterName);
+ }
+
+ /**
+ * Create a new MockFilterConfig.
+ * @param servletContext the ServletContext that the servlet runs in
+ */
+ public MockFilterConfig(ServletContext servletContext) {
+ this(servletContext, "");
+ }
+
+ /**
+ * Create a new MockFilterConfig.
+ * @param servletContext the ServletContext that the servlet runs in
+ * @param filterName the name of the filter
+ */
+ public MockFilterConfig(ServletContext servletContext, String filterName) {
+ this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
+ this.filterName = filterName;
+ }
+
+
+ public String getFilterName() {
+ return filterName;
+ }
+
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+
+ public void addInitParameter(String name, String value) {
+ Assert.notNull(name, "Parameter name must not be null");
+ this.initParameters.put(name, value);
+ }
+
+ public String getInitParameter(String name) {
+ Assert.notNull(name, "Parameter name must not be null");
+ return this.initParameters.get(name);
+ }
+
+ public Enumeration getInitParameterNames() {
+ return Collections.enumeration(this.initParameters.keySet());
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java
new file mode 100644
index 00000000000..88afb595afe
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java
@@ -0,0 +1,910 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.springframework.util.Assert;
+import org.springframework.util.LinkedCaseInsensitiveMap;
+
+/**
+ * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} interface.
+ *
+ * Compatible with Servlet 2.5 and partially with Servlet 3.0 (notable exceptions:
+ * the getPart(s) and startAsync families of methods).
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @author Rick Evans
+ * @author Mark Fisher
+ * @author Sam Brannen
+ * @since 1.0.2
+ */
+public class MockHttpServletRequest implements HttpServletRequest {
+
+ /**
+ * The default protocol: 'http'.
+ */
+ public static final String DEFAULT_PROTOCOL = "http";
+
+ /**
+ * The default server address: '127.0.0.1'.
+ */
+ public static final String DEFAULT_SERVER_ADDR = "127.0.0.1";
+
+ /**
+ * The default server name: 'localhost'.
+ */
+ public static final String DEFAULT_SERVER_NAME = "localhost";
+
+ /**
+ * The default server port: '80'.
+ */
+ public static final int DEFAULT_SERVER_PORT = 80;
+
+ /**
+ * The default remote address: '127.0.0.1'.
+ */
+ public static final String DEFAULT_REMOTE_ADDR = "127.0.0.1";
+
+ /**
+ * The default remote host: 'localhost'.
+ */
+ public static final String DEFAULT_REMOTE_HOST = "localhost";
+
+ private static final String CONTENT_TYPE_HEADER = "Content-Type";
+
+ private static final String CHARSET_PREFIX = "charset=";
+
+ private boolean active = true;
+
+ // ---------------------------------------------------------------------
+ // ServletRequest properties
+ // ---------------------------------------------------------------------
+
+ private final Map attributes = new LinkedHashMap();
+
+ private String characterEncoding;
+
+ private byte[] content;
+
+ private String contentType;
+
+ private final Map parameters = new LinkedHashMap(16);
+
+ private String protocol = DEFAULT_PROTOCOL;
+
+ private String scheme = DEFAULT_PROTOCOL;
+
+ private String serverName = DEFAULT_SERVER_NAME;
+
+ private int serverPort = DEFAULT_SERVER_PORT;
+
+ private String remoteAddr = DEFAULT_REMOTE_ADDR;
+
+ private String remoteHost = DEFAULT_REMOTE_HOST;
+
+ /** List of locales in descending order */
+ private final List locales = new LinkedList();
+
+ private boolean secure = false;
+
+ private final ServletContext servletContext;
+
+ private int remotePort = DEFAULT_SERVER_PORT;
+
+ private String localName = DEFAULT_SERVER_NAME;
+
+ private String localAddr = DEFAULT_SERVER_ADDR;
+
+ private int localPort = DEFAULT_SERVER_PORT;
+
+ // ---------------------------------------------------------------------
+ // HttpServletRequest properties
+ // ---------------------------------------------------------------------
+
+ private String authType;
+
+ private Cookie[] cookies;
+
+ private final Map headers = new LinkedCaseInsensitiveMap();
+
+ private String method;
+
+ private String pathInfo;
+
+ private String contextPath = "";
+
+ private String queryString;
+
+ private String remoteUser;
+
+ private final Set userRoles = new HashSet();
+
+ private Principal userPrincipal;
+
+ private String requestedSessionId;
+
+ private String requestURI;
+
+ private String servletPath = "";
+
+ private HttpSession session;
+
+ private boolean requestedSessionIdValid = true;
+
+ private boolean requestedSessionIdFromCookie = true;
+
+ private boolean requestedSessionIdFromURL = false;
+
+
+ // ---------------------------------------------------------------------
+ // Constructors
+ // ---------------------------------------------------------------------
+
+ /**
+ * Create a new {@code MockHttpServletRequest} with a default
+ * {@link org.springframework.mock.web.MockServletContext}.
+ * @see #MockHttpServletRequest(javax.servlet.ServletContext, String, String)
+ */
+ public MockHttpServletRequest() {
+ this(null, "", "");
+ }
+
+ /**
+ * Create a new {@code MockHttpServletRequest} with a default
+ * {@link org.springframework.mock.web.MockServletContext}.
+ * @param method the request method (may be null)
+ * @param requestURI the request URI (may be null)
+ * @see #setMethod
+ * @see #setRequestURI
+ * @see #MockHttpServletRequest(javax.servlet.ServletContext, String, String)
+ */
+ public MockHttpServletRequest(String method, String requestURI) {
+ this(null, method, requestURI);
+ }
+
+ /**
+ * Create a new {@code MockHttpServletRequest} with the supplied {@link javax.servlet.ServletContext}.
+ * @param servletContext the ServletContext that the request runs in (may be
+ * null to use a default {@link org.springframework.mock.web.MockServletContext})
+ * @see #MockHttpServletRequest(javax.servlet.ServletContext, String, String)
+ */
+ public MockHttpServletRequest(ServletContext servletContext) {
+ this(servletContext, "", "");
+ }
+
+ /**
+ * Create a new {@code MockHttpServletRequest} with the supplied {@link javax.servlet.ServletContext},
+ * {@code method}, and {@code requestURI}.
+ * The preferred locale will be set to {@link java.util.Locale#ENGLISH}.
+ * @param servletContext the ServletContext that the request runs in (may be
+ * null to use a default {@link org.springframework.mock.web.MockServletContext})
+ * @param method the request method (may be null)
+ * @param requestURI the request URI (may be null)
+ * @see #setMethod
+ * @see #setRequestURI
+ * @see #setPreferredLocales
+ * @see org.springframework.mock.web.MockServletContext
+ */
+ public MockHttpServletRequest(ServletContext servletContext, String method, String requestURI) {
+ this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
+ this.method = method;
+ this.requestURI = requestURI;
+ this.locales.add(Locale.ENGLISH);
+ }
+
+ // ---------------------------------------------------------------------
+ // Lifecycle methods
+ // ---------------------------------------------------------------------
+
+ /**
+ * Return the ServletContext that this request is associated with. (Not
+ * available in the standard HttpServletRequest interface for some reason.)
+ */
+ public ServletContext getServletContext() {
+ return this.servletContext;
+ }
+
+ /**
+ * Return whether this request is still active (that is, not completed yet).
+ */
+ public boolean isActive() {
+ return this.active;
+ }
+
+ /**
+ * Mark this request as completed, keeping its state.
+ */
+ public void close() {
+ this.active = false;
+ }
+
+ /**
+ * Invalidate this request, clearing its state.
+ */
+ public void invalidate() {
+ close();
+ clearAttributes();
+ }
+
+ /**
+ * Check whether this request is still active (that is, not completed yet),
+ * throwing an IllegalStateException if not active anymore.
+ */
+ protected void checkActive() throws IllegalStateException {
+ if (!this.active) {
+ throw new IllegalStateException("Request is not active anymore");
+ }
+ }
+
+ // ---------------------------------------------------------------------
+ // ServletRequest interface
+ // ---------------------------------------------------------------------
+
+ public Object getAttribute(String name) {
+ checkActive();
+ return this.attributes.get(name);
+ }
+
+ public Enumeration getAttributeNames() {
+ checkActive();
+ return Collections.enumeration(this.attributes.keySet());
+ }
+
+ public String getCharacterEncoding() {
+ return this.characterEncoding;
+ }
+
+ public void setCharacterEncoding(String characterEncoding) {
+ this.characterEncoding = characterEncoding;
+ updateContentTypeHeader();
+ }
+
+ private void updateContentTypeHeader() {
+ if (this.contentType != null) {
+ StringBuilder sb = new StringBuilder(this.contentType);
+ if (!this.contentType.toLowerCase().contains(CHARSET_PREFIX) && this.characterEncoding != null) {
+ sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding);
+ }
+ doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true);
+ }
+ }
+
+ public void setContent(byte[] content) {
+ this.content = content;
+ }
+
+ public int getContentLength() {
+ return (this.content != null ? this.content.length : -1);
+ }
+
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ if (contentType != null) {
+ int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX);
+ if (charsetIndex != -1) {
+ String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length());
+ this.characterEncoding = encoding;
+ }
+ updateContentTypeHeader();
+ }
+ }
+
+ public String getContentType() {
+ return this.contentType;
+ }
+
+ public ServletInputStream getInputStream() {
+ if (this.content != null) {
+ return new DelegatingServletInputStream(new ByteArrayInputStream(this.content));
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
+ * Set a single value for the specified HTTP parameter.
+ * If there are already one or more values registered for the given
+ * parameter name, they will be replaced.
+ */
+ public void setParameter(String name, String value) {
+ setParameter(name, new String[] { value });
+ }
+
+ /**
+ * Set an array of values for the specified HTTP parameter.
+ *
If there are already one or more values registered for the given
+ * parameter name, they will be replaced.
+ */
+ public void setParameter(String name, String[] values) {
+ Assert.notNull(name, "Parameter name must not be null");
+ this.parameters.put(name, values);
+ }
+
+ /**
+ * Sets all provided parameters replacing any existing
+ * values for the provided parameter names. To add without replacing
+ * existing values, use {@link #addParameters(java.util.Map)}.
+ */
+ @SuppressWarnings("rawtypes")
+ public void setParameters(Map params) {
+ Assert.notNull(params, "Parameter map must not be null");
+ for (Object key : params.keySet()) {
+ Assert.isInstanceOf(String.class, key, "Parameter map key must be of type [" + String.class.getName() + "]");
+ Object value = params.get(key);
+ if (value instanceof String) {
+ this.setParameter((String) key, (String) value);
+ }
+ else if (value instanceof String[]) {
+ this.setParameter((String) key, (String[]) value);
+ }
+ else {
+ throw new IllegalArgumentException("Parameter map value must be single value " + " or array of type ["
+ + String.class.getName() + "]");
+ }
+ }
+ }
+
+ /**
+ * Add a single value for the specified HTTP parameter.
+ *
If there are already one or more values registered for the given
+ * parameter name, the given value will be added to the end of the list.
+ */
+ public void addParameter(String name, String value) {
+ addParameter(name, new String[] { value });
+ }
+
+ /**
+ * Add an array of values for the specified HTTP parameter.
+ *
If there are already one or more values registered for the given
+ * parameter name, the given values will be added to the end of the list.
+ */
+ public void addParameter(String name, String[] values) {
+ Assert.notNull(name, "Parameter name must not be null");
+ String[] oldArr = this.parameters.get(name);
+ if (oldArr != null) {
+ String[] newArr = new String[oldArr.length + values.length];
+ System.arraycopy(oldArr, 0, newArr, 0, oldArr.length);
+ System.arraycopy(values, 0, newArr, oldArr.length, values.length);
+ this.parameters.put(name, newArr);
+ }
+ else {
+ this.parameters.put(name, values);
+ }
+ }
+
+ /**
+ * Adds all provided parameters without replacing any
+ * existing values. To replace existing values, use
+ * {@link #setParameters(java.util.Map)}.
+ */
+ @SuppressWarnings("rawtypes")
+ public void addParameters(Map params) {
+ Assert.notNull(params, "Parameter map must not be null");
+ for (Object key : params.keySet()) {
+ Assert.isInstanceOf(String.class, key, "Parameter map key must be of type [" + String.class.getName() + "]");
+ Object value = params.get(key);
+ if (value instanceof String) {
+ this.addParameter((String) key, (String) value);
+ }
+ else if (value instanceof String[]) {
+ this.addParameter((String) key, (String[]) value);
+ }
+ else {
+ throw new IllegalArgumentException("Parameter map value must be single value " + " or array of type ["
+ + String.class.getName() + "]");
+ }
+ }
+ }
+
+ /**
+ * Remove already registered values for the specified HTTP parameter, if
+ * any.
+ */
+ public void removeParameter(String name) {
+ Assert.notNull(name, "Parameter name must not be null");
+ this.parameters.remove(name);
+ }
+
+ /**
+ * Removes all existing parameters.
+ */
+ public void removeAllParameters() {
+ this.parameters.clear();
+ }
+
+ public String getParameter(String name) {
+ Assert.notNull(name, "Parameter name must not be null");
+ String[] arr = this.parameters.get(name);
+ return (arr != null && arr.length > 0 ? arr[0] : null);
+ }
+
+ public Enumeration getParameterNames() {
+ return Collections.enumeration(this.parameters.keySet());
+ }
+
+ public String[] getParameterValues(String name) {
+ Assert.notNull(name, "Parameter name must not be null");
+ return this.parameters.get(name);
+ }
+
+ public Map getParameterMap() {
+ return Collections.unmodifiableMap(this.parameters);
+ }
+
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ public String getProtocol() {
+ return this.protocol;
+ }
+
+ public void setScheme(String scheme) {
+ this.scheme = scheme;
+ }
+
+ public String getScheme() {
+ return this.scheme;
+ }
+
+ public void setServerName(String serverName) {
+ this.serverName = serverName;
+ }
+
+ public String getServerName() {
+ return this.serverName;
+ }
+
+ public void setServerPort(int serverPort) {
+ this.serverPort = serverPort;
+ }
+
+ public int getServerPort() {
+ return this.serverPort;
+ }
+
+ public BufferedReader getReader() throws UnsupportedEncodingException {
+ if (this.content != null) {
+ InputStream sourceStream = new ByteArrayInputStream(this.content);
+ Reader sourceReader = (this.characterEncoding != null) ? new InputStreamReader(sourceStream,
+ this.characterEncoding) : new InputStreamReader(sourceStream);
+ return new BufferedReader(sourceReader);
+ }
+ else {
+ return null;
+ }
+ }
+
+ public void setRemoteAddr(String remoteAddr) {
+ this.remoteAddr = remoteAddr;
+ }
+
+ public String getRemoteAddr() {
+ return this.remoteAddr;
+ }
+
+ public void setRemoteHost(String remoteHost) {
+ this.remoteHost = remoteHost;
+ }
+
+ public String getRemoteHost() {
+ return this.remoteHost;
+ }
+
+ public void setAttribute(String name, Object value) {
+ checkActive();
+ Assert.notNull(name, "Attribute name must not be null");
+ if (value != null) {
+ this.attributes.put(name, value);
+ }
+ else {
+ this.attributes.remove(name);
+ }
+ }
+
+ public void removeAttribute(String name) {
+ checkActive();
+ Assert.notNull(name, "Attribute name must not be null");
+ this.attributes.remove(name);
+ }
+
+ /**
+ * Clear all of this request's attributes.
+ */
+ public void clearAttributes() {
+ this.attributes.clear();
+ }
+
+ /**
+ * Add a new preferred locale, before any existing locales.
+ * @see #setPreferredLocales
+ */
+ public void addPreferredLocale(Locale locale) {
+ Assert.notNull(locale, "Locale must not be null");
+ this.locales.add(0, locale);
+ }
+
+ /**
+ * Set the list of preferred locales, in descending order, effectively replacing
+ * any existing locales.
+ * @see #addPreferredLocale
+ * @since 3.2
+ */
+ public void setPreferredLocales(List locales) {
+ Assert.notEmpty(locales, "preferred locales list must not be empty");
+ this.locales.clear();
+ this.locales.addAll(locales);
+ }
+
+ public Locale getLocale() {
+ return this.locales.get(0);
+ }
+
+ public Enumeration getLocales() {
+ return Collections.enumeration(this.locales);
+ }
+
+ public void setSecure(boolean secure) {
+ this.secure = secure;
+ }
+
+ public boolean isSecure() {
+ return this.secure;
+ }
+
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return new MockRequestDispatcher(path);
+ }
+
+ public String getRealPath(String path) {
+ return this.servletContext.getRealPath(path);
+ }
+
+ public void setRemotePort(int remotePort) {
+ this.remotePort = remotePort;
+ }
+
+ public int getRemotePort() {
+ return this.remotePort;
+ }
+
+ public void setLocalName(String localName) {
+ this.localName = localName;
+ }
+
+ public String getLocalName() {
+ return this.localName;
+ }
+
+ public void setLocalAddr(String localAddr) {
+ this.localAddr = localAddr;
+ }
+
+ public String getLocalAddr() {
+ return this.localAddr;
+ }
+
+ public void setLocalPort(int localPort) {
+ this.localPort = localPort;
+ }
+
+ public int getLocalPort() {
+ return this.localPort;
+ }
+
+ // ---------------------------------------------------------------------
+ // HttpServletRequest interface
+ // ---------------------------------------------------------------------
+
+ public void setAuthType(String authType) {
+ this.authType = authType;
+ }
+
+ public String getAuthType() {
+ return this.authType;
+ }
+
+ public void setCookies(Cookie... cookies) {
+ this.cookies = cookies;
+ }
+
+ public Cookie[] getCookies() {
+ return this.cookies;
+ }
+
+ /**
+ * Add a header entry for the given name.
+ * If there was no entry for that header name before, the value will be used
+ * as-is. In case of an existing entry, a String array will be created,
+ * adding the given value (more specifically, its toString representation)
+ * as further element.
+ *
Multiple values can only be stored as list of Strings, following the
+ * Servlet spec (see getHeaders accessor). As alternative to
+ * repeated addHeader calls for individual elements, you can
+ * use a single call with an entire array or Collection of values as
+ * parameter.
+ * @see #getHeaderNames
+ * @see #getHeader
+ * @see #getHeaders
+ * @see #getDateHeader
+ * @see #getIntHeader
+ */
+ public void addHeader(String name, Object value) {
+ if (CONTENT_TYPE_HEADER.equalsIgnoreCase(name)) {
+ setContentType((String) value);
+ return;
+ }
+ doAddHeaderValue(name, value, false);
+ }
+
+ @SuppressWarnings("rawtypes")
+ private void doAddHeaderValue(String name, Object value, boolean replace) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ Assert.notNull(value, "Header value must not be null");
+ if (header == null || replace) {
+ header = new HeaderValueHolder();
+ this.headers.put(name, header);
+ }
+ if (value instanceof Collection) {
+ header.addValues((Collection) value);
+ }
+ else if (value.getClass().isArray()) {
+ header.addValueArray(value);
+ }
+ else {
+ header.addValue(value);
+ }
+ }
+
+ public long getDateHeader(String name) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ Object value = (header != null ? header.getValue() : null);
+ if (value instanceof Date) {
+ return ((Date) value).getTime();
+ }
+ else if (value instanceof Number) {
+ return ((Number) value).longValue();
+ }
+ else if (value != null) {
+ throw new IllegalArgumentException("Value for header '" + name + "' is neither a Date nor a Number: "
+ + value);
+ }
+ else {
+ return -1L;
+ }
+ }
+
+ public String getHeader(String name) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ return (header != null ? header.getStringValue() : null);
+ }
+
+ public Enumeration getHeaders(String name) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ return Collections.enumeration(header != null ? header.getStringValues() : new LinkedList());
+ }
+
+ public Enumeration getHeaderNames() {
+ return Collections.enumeration(this.headers.keySet());
+ }
+
+ public int getIntHeader(String name) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ Object value = (header != null ? header.getValue() : null);
+ if (value instanceof Number) {
+ return ((Number) value).intValue();
+ }
+ else if (value instanceof String) {
+ return Integer.parseInt((String) value);
+ }
+ else if (value != null) {
+ throw new NumberFormatException("Value for header '" + name + "' is not a Number: " + value);
+ }
+ else {
+ return -1;
+ }
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public String getMethod() {
+ return this.method;
+ }
+
+ public void setPathInfo(String pathInfo) {
+ this.pathInfo = pathInfo;
+ }
+
+ public String getPathInfo() {
+ return this.pathInfo;
+ }
+
+ public String getPathTranslated() {
+ return (this.pathInfo != null ? getRealPath(this.pathInfo) : null);
+ }
+
+ public void setContextPath(String contextPath) {
+ this.contextPath = contextPath;
+ }
+
+ public String getContextPath() {
+ return this.contextPath;
+ }
+
+ public void setQueryString(String queryString) {
+ this.queryString = queryString;
+ }
+
+ public String getQueryString() {
+ return this.queryString;
+ }
+
+ public void setRemoteUser(String remoteUser) {
+ this.remoteUser = remoteUser;
+ }
+
+ public String getRemoteUser() {
+ return this.remoteUser;
+ }
+
+ public void addUserRole(String role) {
+ this.userRoles.add(role);
+ }
+
+ public boolean isUserInRole(String role) {
+ return (this.userRoles.contains(role) || (this.servletContext instanceof MockServletContext && ((MockServletContext) this.servletContext).getDeclaredRoles().contains(
+ role)));
+ }
+
+ public void setUserPrincipal(Principal userPrincipal) {
+ this.userPrincipal = userPrincipal;
+ }
+
+ public Principal getUserPrincipal() {
+ return this.userPrincipal;
+ }
+
+ public void setRequestedSessionId(String requestedSessionId) {
+ this.requestedSessionId = requestedSessionId;
+ }
+
+ public String getRequestedSessionId() {
+ return this.requestedSessionId;
+ }
+
+ public void setRequestURI(String requestURI) {
+ this.requestURI = requestURI;
+ }
+
+ public String getRequestURI() {
+ return this.requestURI;
+ }
+
+ public StringBuffer getRequestURL() {
+ StringBuffer url = new StringBuffer(this.scheme);
+ url.append("://").append(this.serverName).append(':').append(this.serverPort);
+ url.append(getRequestURI());
+ return url;
+ }
+
+ public void setServletPath(String servletPath) {
+ this.servletPath = servletPath;
+ }
+
+ public String getServletPath() {
+ return this.servletPath;
+ }
+
+ public void setSession(HttpSession session) {
+ this.session = session;
+ if (session instanceof MockHttpSession) {
+ MockHttpSession mockSession = ((MockHttpSession) session);
+ mockSession.access();
+ }
+ }
+
+ public HttpSession getSession(boolean create) {
+ checkActive();
+ // Reset session if invalidated.
+ if (this.session instanceof MockHttpSession && ((MockHttpSession) this.session).isInvalid()) {
+ this.session = null;
+ }
+ // Create new session if necessary.
+ if (this.session == null && create) {
+ this.session = new MockHttpSession(this.servletContext);
+ }
+ return this.session;
+ }
+
+ public HttpSession getSession() {
+ return getSession(true);
+ }
+
+ public void setRequestedSessionIdValid(boolean requestedSessionIdValid) {
+ this.requestedSessionIdValid = requestedSessionIdValid;
+ }
+
+ public boolean isRequestedSessionIdValid() {
+ return this.requestedSessionIdValid;
+ }
+
+ public void setRequestedSessionIdFromCookie(boolean requestedSessionIdFromCookie) {
+ this.requestedSessionIdFromCookie = requestedSessionIdFromCookie;
+ }
+
+ public boolean isRequestedSessionIdFromCookie() {
+ return this.requestedSessionIdFromCookie;
+ }
+
+ public void setRequestedSessionIdFromURL(boolean requestedSessionIdFromURL) {
+ this.requestedSessionIdFromURL = requestedSessionIdFromURL;
+ }
+
+ public boolean isRequestedSessionIdFromURL() {
+ return this.requestedSessionIdFromURL;
+ }
+
+ public boolean isRequestedSessionIdFromUrl() {
+ return isRequestedSessionIdFromURL();
+ }
+
+ public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
+ return (this.userPrincipal != null && this.remoteUser != null && this.authType != null);
+ }
+
+ public void login(String username, String password) throws ServletException {
+ throw new ServletException("Username-password authentication not supported - override the login method");
+ }
+
+ public void logout() throws ServletException {
+ this.userPrincipal = null;
+ this.remoteUser = null;
+ this.authType = null;
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java
new file mode 100644
index 00000000000..550e927a477
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java
@@ -0,0 +1,603 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.util.Assert;
+import org.springframework.util.LinkedCaseInsensitiveMap;
+import org.springframework.web.util.WebUtils;
+
+/**
+ * Mock implementation of the {@link javax.servlet.http.HttpServletResponse} interface.
+ *
+ * Compatible with Servlet 2.5 as well as Servlet 3.0.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 1.0.2
+ */
+public class MockHttpServletResponse implements HttpServletResponse {
+
+ private static final String CHARSET_PREFIX = "charset=";
+
+ private static final String CONTENT_TYPE_HEADER = "Content-Type";
+
+ private static final String CONTENT_LENGTH_HEADER = "Content-Length";
+
+ private static final String LOCATION_HEADER = "Location";
+
+ //---------------------------------------------------------------------
+ // ServletResponse properties
+ //---------------------------------------------------------------------
+
+ private boolean outputStreamAccessAllowed = true;
+
+ private boolean writerAccessAllowed = true;
+
+ private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
+
+ private boolean charset = false;
+
+ private final ByteArrayOutputStream content = new ByteArrayOutputStream();
+
+ private final ServletOutputStream outputStream = new ResponseServletOutputStream(this.content);
+
+ private PrintWriter writer;
+
+ private int contentLength = 0;
+
+ private String contentType;
+
+ private int bufferSize = 4096;
+
+ private boolean committed;
+
+ private Locale locale = Locale.getDefault();
+
+
+ //---------------------------------------------------------------------
+ // HttpServletResponse properties
+ //---------------------------------------------------------------------
+
+ private final List cookies = new ArrayList();
+
+ private final Map headers = new LinkedCaseInsensitiveMap();
+
+ private int status = HttpServletResponse.SC_OK;
+
+ private String errorMessage;
+
+ private String forwardedUrl;
+
+ private final List includedUrls = new ArrayList();
+
+
+ //---------------------------------------------------------------------
+ // ServletResponse interface
+ //---------------------------------------------------------------------
+
+ /**
+ * Set whether {@link #getOutputStream()} access is allowed.
+ * Default is true.
+ */
+ public void setOutputStreamAccessAllowed(boolean outputStreamAccessAllowed) {
+ this.outputStreamAccessAllowed = outputStreamAccessAllowed;
+ }
+
+ /**
+ * Return whether {@link #getOutputStream()} access is allowed.
+ */
+ public boolean isOutputStreamAccessAllowed() {
+ return this.outputStreamAccessAllowed;
+ }
+
+ /**
+ * Set whether {@link #getWriter()} access is allowed.
+ *
Default is true.
+ */
+ public void setWriterAccessAllowed(boolean writerAccessAllowed) {
+ this.writerAccessAllowed = writerAccessAllowed;
+ }
+
+ /**
+ * Return whether {@link #getOutputStream()} access is allowed.
+ */
+ public boolean isWriterAccessAllowed() {
+ return this.writerAccessAllowed;
+ }
+
+ public void setCharacterEncoding(String characterEncoding) {
+ this.characterEncoding = characterEncoding;
+ this.charset = true;
+ updateContentTypeHeader();
+ }
+
+ private void updateContentTypeHeader() {
+ if (this.contentType != null) {
+ StringBuilder sb = new StringBuilder(this.contentType);
+ if (this.contentType.toLowerCase().indexOf(CHARSET_PREFIX) == -1 && this.charset) {
+ sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding);
+ }
+ doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true);
+ }
+ }
+
+ public String getCharacterEncoding() {
+ return this.characterEncoding;
+ }
+
+ public ServletOutputStream getOutputStream() {
+ if (!this.outputStreamAccessAllowed) {
+ throw new IllegalStateException("OutputStream access not allowed");
+ }
+ return this.outputStream;
+ }
+
+ public PrintWriter getWriter() throws UnsupportedEncodingException {
+ if (!this.writerAccessAllowed) {
+ throw new IllegalStateException("Writer access not allowed");
+ }
+ if (this.writer == null) {
+ Writer targetWriter = (this.characterEncoding != null ?
+ new OutputStreamWriter(this.content, this.characterEncoding) : new OutputStreamWriter(this.content));
+ this.writer = new ResponsePrintWriter(targetWriter);
+ }
+ return this.writer;
+ }
+
+ public byte[] getContentAsByteArray() {
+ flushBuffer();
+ return this.content.toByteArray();
+ }
+
+ public String getContentAsString() throws UnsupportedEncodingException {
+ flushBuffer();
+ return (this.characterEncoding != null) ?
+ this.content.toString(this.characterEncoding) : this.content.toString();
+ }
+
+ public void setContentLength(int contentLength) {
+ this.contentLength = contentLength;
+ doAddHeaderValue(CONTENT_LENGTH_HEADER, contentLength, true);
+ }
+
+ public int getContentLength() {
+ return this.contentLength;
+ }
+
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ if (contentType != null) {
+ int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX);
+ if (charsetIndex != -1) {
+ String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length());
+ this.characterEncoding = encoding;
+ this.charset = true;
+ }
+ updateContentTypeHeader();
+ }
+ }
+
+ public String getContentType() {
+ return this.contentType;
+ }
+
+ public void setBufferSize(int bufferSize) {
+ this.bufferSize = bufferSize;
+ }
+
+ public int getBufferSize() {
+ return this.bufferSize;
+ }
+
+ public void flushBuffer() {
+ setCommitted(true);
+ }
+
+ public void resetBuffer() {
+ if (isCommitted()) {
+ throw new IllegalStateException("Cannot reset buffer - response is already committed");
+ }
+ this.content.reset();
+ }
+
+ private void setCommittedIfBufferSizeExceeded() {
+ int bufSize = getBufferSize();
+ if (bufSize > 0 && this.content.size() > bufSize) {
+ setCommitted(true);
+ }
+ }
+
+ public void setCommitted(boolean committed) {
+ this.committed = committed;
+ }
+
+ public boolean isCommitted() {
+ return this.committed;
+ }
+
+ public void reset() {
+ resetBuffer();
+ this.characterEncoding = null;
+ this.contentLength = 0;
+ this.contentType = null;
+ this.locale = null;
+ this.cookies.clear();
+ this.headers.clear();
+ this.status = HttpServletResponse.SC_OK;
+ this.errorMessage = null;
+ }
+
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
+
+ public Locale getLocale() {
+ return this.locale;
+ }
+
+
+ //---------------------------------------------------------------------
+ // HttpServletResponse interface
+ //---------------------------------------------------------------------
+
+ public void addCookie(Cookie cookie) {
+ Assert.notNull(cookie, "Cookie must not be null");
+ this.cookies.add(cookie);
+ }
+
+ public Cookie[] getCookies() {
+ return this.cookies.toArray(new Cookie[this.cookies.size()]);
+ }
+
+ public Cookie getCookie(String name) {
+ Assert.notNull(name, "Cookie name must not be null");
+ for (Cookie cookie : this.cookies) {
+ if (name.equals(cookie.getName())) {
+ return cookie;
+ }
+ }
+ return null;
+ }
+
+ public boolean containsHeader(String name) {
+ return (HeaderValueHolder.getByName(this.headers, name) != null);
+ }
+
+ /**
+ * Return the names of all specified headers as a Set of Strings.
+ *
As of Servlet 3.0, this method is also defined HttpServletResponse.
+ * @return the Set of header name Strings, or an empty Set if none
+ */
+ public Set getHeaderNames() {
+ return this.headers.keySet();
+ }
+
+ /**
+ * Return the primary value for the given header as a String, if any.
+ * Will return the first value in case of multiple values.
+ * As of Servlet 3.0, this method is also defined in HttpServletResponse.
+ * As of Spring 3.1, it returns a stringified value for Servlet 3.0 compatibility.
+ * Consider using {@link #getHeaderValue(String)} for raw Object access.
+ * @param name the name of the header
+ * @return the associated header value, or null if none
+ */
+ public String getHeader(String name) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ return (header != null ? header.getStringValue() : null);
+ }
+
+ /**
+ * Return all values for the given header as a List of Strings.
+ * As of Servlet 3.0, this method is also defined in HttpServletResponse.
+ * As of Spring 3.1, it returns a List of stringified values for Servlet 3.0 compatibility.
+ * Consider using {@link #getHeaderValues(String)} for raw Object access.
+ * @param name the name of the header
+ * @return the associated header values, or an empty List if none
+ */
+ public List getHeaders(String name) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ if (header != null) {
+ return header.getStringValues();
+ }
+ else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Return the primary value for the given header, if any.
+ * Will return the first value in case of multiple values.
+ * @param name the name of the header
+ * @return the associated header value, or null if none
+ */
+ public Object getHeaderValue(String name) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ return (header != null ? header.getValue() : null);
+ }
+
+ /**
+ * Return all values for the given header as a List of value objects.
+ * @param name the name of the header
+ * @return the associated header values, or an empty List if none
+ */
+ public List getHeaderValues(String name) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ if (header != null) {
+ return header.getValues();
+ }
+ else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * The default implementation returns the given URL String as-is.
+ * Can be overridden in subclasses, appending a session id or the like.
+ */
+ public String encodeURL(String url) {
+ return url;
+ }
+
+ /**
+ * The default implementation delegates to {@link #encodeURL},
+ * returning the given URL String as-is.
+ *
Can be overridden in subclasses, appending a session id or the like
+ * in a redirect-specific fashion. For general URL encoding rules,
+ * override the common {@link #encodeURL} method instead, applying
+ * to redirect URLs as well as to general URLs.
+ */
+ public String encodeRedirectURL(String url) {
+ return encodeURL(url);
+ }
+
+ public String encodeUrl(String url) {
+ return encodeURL(url);
+ }
+
+ public String encodeRedirectUrl(String url) {
+ return encodeRedirectURL(url);
+ }
+
+ public void sendError(int status, String errorMessage) throws IOException {
+ if (isCommitted()) {
+ throw new IllegalStateException("Cannot set error status - response is already committed");
+ }
+ this.status = status;
+ this.errorMessage = errorMessage;
+ setCommitted(true);
+ }
+
+ public void sendError(int status) throws IOException {
+ if (isCommitted()) {
+ throw new IllegalStateException("Cannot set error status - response is already committed");
+ }
+ this.status = status;
+ setCommitted(true);
+ }
+
+ public void sendRedirect(String url) throws IOException {
+ if (isCommitted()) {
+ throw new IllegalStateException("Cannot send redirect - response is already committed");
+ }
+ Assert.notNull(url, "Redirect URL must not be null");
+ setHeader(LOCATION_HEADER, url);
+ setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ setCommitted(true);
+ }
+
+ public String getRedirectedUrl() {
+ return getHeader(LOCATION_HEADER);
+ }
+
+ public void setDateHeader(String name, long value) {
+ setHeaderValue(name, value);
+ }
+
+ public void addDateHeader(String name, long value) {
+ addHeaderValue(name, value);
+ }
+
+ public void setHeader(String name, String value) {
+ setHeaderValue(name, value);
+ }
+
+ public void addHeader(String name, String value) {
+ addHeaderValue(name, value);
+ }
+
+ public void setIntHeader(String name, int value) {
+ setHeaderValue(name, value);
+ }
+
+ public void addIntHeader(String name, int value) {
+ addHeaderValue(name, value);
+ }
+
+ private void setHeaderValue(String name, Object value) {
+ if (setSpecialHeader(name, value)) {
+ return;
+ }
+ doAddHeaderValue(name, value, true);
+ }
+
+ private void addHeaderValue(String name, Object value) {
+ if (setSpecialHeader(name, value)) {
+ return;
+ }
+ doAddHeaderValue(name, value, false);
+ }
+
+ private boolean setSpecialHeader(String name, Object value) {
+ if (CONTENT_TYPE_HEADER.equalsIgnoreCase(name)) {
+ setContentType((String) value);
+ return true;
+ }
+ else if (CONTENT_LENGTH_HEADER.equalsIgnoreCase(name)) {
+ setContentLength(Integer.parseInt((String) value));
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
+ private void doAddHeaderValue(String name, Object value, boolean replace) {
+ HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+ Assert.notNull(value, "Header value must not be null");
+ if (header == null) {
+ header = new HeaderValueHolder();
+ this.headers.put(name, header);
+ }
+ if (replace) {
+ header.setValue(value);
+ }
+ else {
+ header.addValue(value);
+ }
+ }
+
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ public void setStatus(int status, String errorMessage) {
+ this.status = status;
+ this.errorMessage = errorMessage;
+ }
+
+ public int getStatus() {
+ return this.status;
+ }
+
+ public String getErrorMessage() {
+ return this.errorMessage;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Methods for MockRequestDispatcher
+ //---------------------------------------------------------------------
+
+ public void setForwardedUrl(String forwardedUrl) {
+ this.forwardedUrl = forwardedUrl;
+ }
+
+ public String getForwardedUrl() {
+ return this.forwardedUrl;
+ }
+
+ public void setIncludedUrl(String includedUrl) {
+ this.includedUrls.clear();
+ if (includedUrl != null) {
+ this.includedUrls.add(includedUrl);
+ }
+ }
+
+ public String getIncludedUrl() {
+ int count = this.includedUrls.size();
+ if (count > 1) {
+ throw new IllegalStateException(
+ "More than 1 URL included - check getIncludedUrls instead: " + this.includedUrls);
+ }
+ return (count == 1 ? this.includedUrls.get(0) : null);
+ }
+
+ public void addIncludedUrl(String includedUrl) {
+ Assert.notNull(includedUrl, "Included URL must not be null");
+ this.includedUrls.add(includedUrl);
+ }
+
+ public List getIncludedUrls() {
+ return this.includedUrls;
+ }
+
+
+ /**
+ * Inner class that adapts the ServletOutputStream to mark the
+ * response as committed once the buffer size is exceeded.
+ */
+ private class ResponseServletOutputStream extends DelegatingServletOutputStream {
+
+ public ResponseServletOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ public void write(int b) throws IOException {
+ super.write(b);
+ super.flush();
+ setCommittedIfBufferSizeExceeded();
+ }
+
+ public void flush() throws IOException {
+ super.flush();
+ setCommitted(true);
+ }
+ }
+
+
+ /**
+ * Inner class that adapts the PrintWriter to mark the
+ * response as committed once the buffer size is exceeded.
+ */
+ private class ResponsePrintWriter extends PrintWriter {
+
+ public ResponsePrintWriter(Writer out) {
+ super(out, true);
+ }
+
+ public void write(char buf[], int off, int len) {
+ super.write(buf, off, len);
+ super.flush();
+ setCommittedIfBufferSizeExceeded();
+ }
+
+ public void write(String s, int off, int len) {
+ super.write(s, off, len);
+ super.flush();
+ setCommittedIfBufferSizeExceeded();
+ }
+
+ public void write(int c) {
+ super.write(c);
+ super.flush();
+ setCommittedIfBufferSizeExceeded();
+ }
+
+ public void flush() {
+ super.flush();
+ setCommitted(true);
+ }
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockHttpSession.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockHttpSession.java
new file mode 100644
index 00000000000..3caa9213ee4
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockHttpSession.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionContext;
+
+import org.springframework.util.Assert;
+
+/**
+ * Mock implementation of the {@link javax.servlet.http.HttpSession} interface.
+ *
+ * Compatible with Servlet 2.5 as well as Servlet 3.0.
+ *
+ *
Used for testing the web framework; also useful for testing application
+ * controllers.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @author Mark Fisher
+ * @author Sam Brannen
+ * @since 1.0.2
+ */
+@SuppressWarnings("deprecation")
+public class MockHttpSession implements HttpSession {
+
+ public static final String SESSION_COOKIE_NAME = "JSESSION";
+
+ private static int nextId = 1;
+
+ private final String id;
+
+ private final long creationTime = System.currentTimeMillis();
+
+ private int maxInactiveInterval;
+
+ private long lastAccessedTime = System.currentTimeMillis();
+
+ private final ServletContext servletContext;
+
+ private final Map attributes = new LinkedHashMap();
+
+ private boolean invalid = false;
+
+ private boolean isNew = true;
+
+
+ /**
+ * Create a new MockHttpSession with a default {@link org.springframework.mock.web.MockServletContext}.
+ *
+ * @see org.springframework.mock.web.MockServletContext
+ */
+ public MockHttpSession() {
+ this(null);
+ }
+
+ /**
+ * Create a new MockHttpSession.
+ *
+ * @param servletContext the ServletContext that the session runs in
+ */
+ public MockHttpSession(ServletContext servletContext) {
+ this(servletContext, null);
+ }
+
+ /**
+ * Create a new MockHttpSession.
+ *
+ * @param servletContext the ServletContext that the session runs in
+ * @param id a unique identifier for this session
+ */
+ public MockHttpSession(ServletContext servletContext, String id) {
+ this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
+ this.id = (id != null ? id : Integer.toString(nextId++));
+ }
+
+ public long getCreationTime() {
+ return this.creationTime;
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public void access() {
+ this.lastAccessedTime = System.currentTimeMillis();
+ this.isNew = false;
+ }
+
+ public long getLastAccessedTime() {
+ return this.lastAccessedTime;
+ }
+
+ public ServletContext getServletContext() {
+ return this.servletContext;
+ }
+
+ public void setMaxInactiveInterval(int interval) {
+ this.maxInactiveInterval = interval;
+ }
+
+ public int getMaxInactiveInterval() {
+ return this.maxInactiveInterval;
+ }
+
+ public HttpSessionContext getSessionContext() {
+ throw new UnsupportedOperationException("getSessionContext");
+ }
+
+ public Object getAttribute(String name) {
+ Assert.notNull(name, "Attribute name must not be null");
+ return this.attributes.get(name);
+ }
+
+ public Object getValue(String name) {
+ return getAttribute(name);
+ }
+
+ public Enumeration getAttributeNames() {
+ return Collections.enumeration(this.attributes.keySet());
+ }
+
+ public String[] getValueNames() {
+ return this.attributes.keySet().toArray(new String[this.attributes.size()]);
+ }
+
+ public void setAttribute(String name, Object value) {
+ Assert.notNull(name, "Attribute name must not be null");
+ if (value != null) {
+ this.attributes.put(name, value);
+ if (value instanceof HttpSessionBindingListener) {
+ ((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name, value));
+ }
+ }
+ else {
+ removeAttribute(name);
+ }
+ }
+
+ public void putValue(String name, Object value) {
+ setAttribute(name, value);
+ }
+
+ public void removeAttribute(String name) {
+ Assert.notNull(name, "Attribute name must not be null");
+ Object value = this.attributes.remove(name);
+ if (value instanceof HttpSessionBindingListener) {
+ ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
+ }
+ }
+
+ public void removeValue(String name) {
+ removeAttribute(name);
+ }
+
+ /**
+ * Clear all of this session's attributes.
+ */
+ public void clearAttributes() {
+ for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = it.next();
+ String name = entry.getKey();
+ Object value = entry.getValue();
+ it.remove();
+ if (value instanceof HttpSessionBindingListener) {
+ ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
+ }
+ }
+ }
+
+ /**
+ * Invalidates this session then unbinds any objects bound to it.
+ *
+ * @throws IllegalStateException if this method is called on an already invalidated session
+ */
+ public void invalidate() {
+ if (this.invalid) {
+ throw new IllegalStateException("The session has already been invalidated");
+ }
+
+ // else
+ this.invalid = true;
+ clearAttributes();
+ }
+
+ public boolean isInvalid() {
+ return this.invalid;
+ }
+
+ public void setNew(boolean value) {
+ this.isNew = value;
+ }
+
+ public boolean isNew() {
+ return this.isNew;
+ }
+
+ /**
+ * Serialize the attributes of this session into an object that can be
+ * turned into a byte array with standard Java serialization.
+ *
+ * @return a representation of this session's serialized state
+ */
+ public Serializable serializeState() {
+ HashMap state = new HashMap();
+ for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = it.next();
+ String name = entry.getKey();
+ Object value = entry.getValue();
+ it.remove();
+ if (value instanceof Serializable) {
+ state.put(name, (Serializable) value);
+ }
+ else {
+ // Not serializable... Servlet containers usually automatically
+ // unbind the attribute in this case.
+ if (value instanceof HttpSessionBindingListener) {
+ ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
+ }
+ }
+ }
+ return state;
+ }
+
+ /**
+ * Deserialize the attributes of this session from a state object created by
+ * {@link #serializeState()}.
+ *
+ * @param state a representation of this session's serialized state
+ */
+ @SuppressWarnings("unchecked")
+ public void deserializeState(Serializable state) {
+ Assert.isTrue(state instanceof Map, "Serialized state needs to be of type [java.util.Map]");
+ this.attributes.putAll((Map) state);
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java
new file mode 100644
index 00000000000..9ce5f8d5c0b
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.util.Assert;
+
+/**
+ * Mock implementation of the {@link javax.servlet.RequestDispatcher} interface.
+ *
+ * Used for testing the web framework; typically not necessary for
+ * testing application controllers.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @author Sam Brannen
+ * @since 1.0.2
+ */
+public class MockRequestDispatcher implements RequestDispatcher {
+
+ private final Log logger = LogFactory.getLog(getClass());
+
+ private final String resource;
+
+
+ /**
+ * Create a new MockRequestDispatcher for the given resource.
+ * @param resource the server resource to dispatch to, located at a
+ * particular path or given by a particular name
+ */
+ public MockRequestDispatcher(String resource) {
+ Assert.notNull(resource, "resource must not be null");
+ this.resource = resource;
+ }
+
+
+ public void forward(ServletRequest request, ServletResponse response) {
+ Assert.notNull(request, "Request must not be null");
+ Assert.notNull(response, "Response must not be null");
+ if (response.isCommitted()) {
+ throw new IllegalStateException("Cannot perform forward - response is already committed");
+ }
+ getMockHttpServletResponse(response).setForwardedUrl(this.resource);
+ if (logger.isDebugEnabled()) {
+ logger.debug("MockRequestDispatcher: forwarding to [" + this.resource + "]");
+ }
+ }
+
+ public void include(ServletRequest request, ServletResponse response) {
+ Assert.notNull(request, "Request must not be null");
+ Assert.notNull(response, "Response must not be null");
+ getMockHttpServletResponse(response).addIncludedUrl(this.resource);
+ if (logger.isDebugEnabled()) {
+ logger.debug("MockRequestDispatcher: including [" + this.resource + "]");
+ }
+ }
+
+ /**
+ * Obtain the underlying {@link org.springframework.mock.web.MockHttpServletResponse}, unwrapping
+ * {@link javax.servlet.http.HttpServletResponseWrapper} decorators if necessary.
+ */
+ protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) {
+ if (response instanceof MockHttpServletResponse) {
+ return (MockHttpServletResponse) response;
+ }
+ if (response instanceof HttpServletResponseWrapper) {
+ return getMockHttpServletResponse(((HttpServletResponseWrapper) response).getResponse());
+ }
+ throw new IllegalArgumentException("MockRequestDispatcher requires MockHttpServletResponse");
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockServletConfig.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockServletConfig.java
new file mode 100644
index 00000000000..c62ec1520d0
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockServletConfig.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+import org.springframework.util.Assert;
+
+/**
+ * Mock implementation of the {@link javax.servlet.ServletConfig} interface.
+ *
+ *
Used for testing the web framework; typically not necessary for
+ * testing application controllers.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @since 1.0.2
+ */
+public class MockServletConfig implements ServletConfig {
+
+ private final ServletContext servletContext;
+
+ private final String servletName;
+
+ private final Map initParameters = new LinkedHashMap();
+
+
+ /**
+ * Create a new MockServletConfig with a default {@link MockServletContext}.
+ */
+ public MockServletConfig() {
+ this(null, "");
+ }
+
+ /**
+ * Create a new MockServletConfig with a default {@link MockServletContext}.
+ * @param servletName the name of the servlet
+ */
+ public MockServletConfig(String servletName) {
+ this(null, servletName);
+ }
+
+ /**
+ * Create a new MockServletConfig.
+ * @param servletContext the ServletContext that the servlet runs in
+ */
+ public MockServletConfig(ServletContext servletContext) {
+ this(servletContext, "");
+ }
+
+ /**
+ * Create a new MockServletConfig.
+ * @param servletContext the ServletContext that the servlet runs in
+ * @param servletName the name of the servlet
+ */
+ public MockServletConfig(ServletContext servletContext, String servletName) {
+ this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
+ this.servletName = servletName;
+ }
+
+
+ public String getServletName() {
+ return this.servletName;
+ }
+
+ public ServletContext getServletContext() {
+ return this.servletContext;
+ }
+
+ public void addInitParameter(String name, String value) {
+ Assert.notNull(name, "Parameter name must not be null");
+ this.initParameters.put(name, value);
+ }
+
+ public String getInitParameter(String name) {
+ Assert.notNull(name, "Parameter name must not be null");
+ return this.initParameters.get(name);
+ }
+
+ public Enumeration getInitParameterNames() {
+ return Collections.enumeration(this.initParameters.keySet());
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockServletContext.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockServletContext.java
new file mode 100644
index 00000000000..7851a77e497
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/MockServletContext.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+import javax.activation.FileTypeMap;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ObjectUtils;
+import org.springframework.web.util.WebUtils;
+
+/**
+ * Mock implementation of the {@link javax.servlet.ServletContext} interface.
+ *
+ * Compatible with Servlet 2.5 and partially with Servlet 3.0. Can be configured to
+ * expose a specific version through {@link #setMajorVersion}/{@link #setMinorVersion};
+ * default is 2.5. Note that Servlet 3.0 support is limited: servlet, filter and listener
+ * registration methods are not supported; neither is cookie or JSP configuration.
+ * We generally do not recommend to unit-test your ServletContainerInitializers and
+ * WebApplicationInitializers which is where those registration methods would be used.
+ *
+ *
Used for testing the Spring web framework; only rarely necessary for testing
+ * application controllers. As long as application components don't explicitly
+ * access the {@code ServletContext}, {@code ClassPathXmlApplicationContext} or
+ * {@code FileSystemXmlApplicationContext} can be used to load the context files
+ * for testing, even for {@code DispatcherServlet} context definitions.
+ *
+ *
For setting up a full {@code WebApplicationContext} in a test environment,
+ * you can use {@code AnnotationConfigWebApplicationContext},
+ * {@code XmlWebApplicationContext}, or {@code GenericWebApplicationContext},
+ * passing in an appropriate {@code MockServletContext} instance. You might want
+ * to configure your {@code MockServletContext} with a {@code FileSystemResourceLoader}
+ * in that case to ensure that resource paths are interpreted as relative filesystem
+ * locations.
+ *
+ *
A common setup is to point your JVM working directory to the root of your
+ * web application directory, in combination with filesystem-based resource loading.
+ * This allows to load the context files as used in the web application, with
+ * relative paths getting interpreted correctly. Such a setup will work with both
+ * {@code FileSystemXmlApplicationContext} (which will load straight from the
+ * filesystem) and {@code XmlWebApplicationContext} with an underlying
+ * {@code MockServletContext} (as long as the {@code MockServletContext} has been
+ * configured with a {@code FileSystemResourceLoader}).
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @author Sam Brannen
+ * @since 1.0.2
+ * @see #MockServletContext(org.springframework.core.io.ResourceLoader)
+ * @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext
+ * @see org.springframework.web.context.support.XmlWebApplicationContext
+ * @see org.springframework.web.context.support.GenericWebApplicationContext
+ * @see org.springframework.context.support.ClassPathXmlApplicationContext
+ * @see org.springframework.context.support.FileSystemXmlApplicationContext
+ */
+public class MockServletContext implements ServletContext {
+
+ /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value}. */
+ private static final String COMMON_DEFAULT_SERVLET_NAME = "default";
+
+ private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir";
+
+ private final Log logger = LogFactory.getLog(getClass());
+
+ private final Map contexts = new HashMap();
+
+ private final Map initParameters = new LinkedHashMap();
+
+ private final Map attributes = new LinkedHashMap();
+
+ private final Set declaredRoles = new HashSet();
+
+ private final Map namedRequestDispatchers = new HashMap();
+
+ private final ResourceLoader resourceLoader;
+
+ private final String resourceBasePath;
+
+ private String contextPath = "";
+
+ private int majorVersion = 2;
+
+ private int minorVersion = 5;
+
+ private int effectiveMajorVersion = 2;
+
+ private int effectiveMinorVersion = 5;
+
+ private String servletContextName = "MockServletContext";
+
+ private String defaultServletName = COMMON_DEFAULT_SERVLET_NAME;
+
+
+ /**
+ * Create a new MockServletContext, using no base path and a
+ * DefaultResourceLoader (i.e. the classpath root as WAR root).
+ * @see org.springframework.core.io.DefaultResourceLoader
+ */
+ public MockServletContext() {
+ this("", null);
+ }
+
+ /**
+ * Create a new MockServletContext, using a DefaultResourceLoader.
+ * @param resourceBasePath the root directory of the WAR (should not end with a slash)
+ * @see org.springframework.core.io.DefaultResourceLoader
+ */
+ public MockServletContext(String resourceBasePath) {
+ this(resourceBasePath, null);
+ }
+
+ /**
+ * Create a new MockServletContext, using the specified ResourceLoader
+ * and no base path.
+ * @param resourceLoader the ResourceLoader to use (or null for the default)
+ */
+ public MockServletContext(ResourceLoader resourceLoader) {
+ this("", resourceLoader);
+ }
+
+ /**
+ * Create a new MockServletContext using the supplied resource base path and
+ * resource loader.
+ * Registers a {@link org.springframework.mock.web.MockRequestDispatcher} for the Servlet named
+ * {@value #COMMON_DEFAULT_SERVLET_NAME}.
+ * @param resourceBasePath the root directory of the WAR (should not end with a slash)
+ * @param resourceLoader the ResourceLoader to use (or null for the default)
+ * @see #registerNamedDispatcher
+ */
+ public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) {
+ this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
+ this.resourceBasePath = (resourceBasePath != null ? resourceBasePath : "");
+
+ // Use JVM temp dir as ServletContext temp dir.
+ String tempDir = System.getProperty(TEMP_DIR_SYSTEM_PROPERTY);
+ if (tempDir != null) {
+ this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir));
+ }
+
+ registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName));
+ }
+
+ /**
+ * Build a full resource location for the given path,
+ * prepending the resource base path of this MockServletContext.
+ * @param path the path as specified
+ * @return the full resource path
+ */
+ protected String getResourceLocation(String path) {
+ if (!path.startsWith("/")) {
+ path = "/" + path;
+ }
+ return this.resourceBasePath + path;
+ }
+
+ public void setContextPath(String contextPath) {
+ this.contextPath = (contextPath != null ? contextPath : "");
+ }
+
+ /* This is a Servlet API 2.5 method. */
+ public String getContextPath() {
+ return this.contextPath;
+ }
+
+ public void registerContext(String contextPath, ServletContext context) {
+ this.contexts.put(contextPath, context);
+ }
+
+ public ServletContext getContext(String contextPath) {
+ if (this.contextPath.equals(contextPath)) {
+ return this;
+ }
+ return this.contexts.get(contextPath);
+ }
+
+ public void setMajorVersion(int majorVersion) {
+ this.majorVersion = majorVersion;
+ }
+
+ public int getMajorVersion() {
+ return this.majorVersion;
+ }
+
+ public void setMinorVersion(int minorVersion) {
+ this.minorVersion = minorVersion;
+ }
+
+ public int getMinorVersion() {
+ return this.minorVersion;
+ }
+
+ public void setEffectiveMajorVersion(int effectiveMajorVersion) {
+ this.effectiveMajorVersion = effectiveMajorVersion;
+ }
+
+ public int getEffectiveMajorVersion() {
+ return this.effectiveMajorVersion;
+ }
+
+ public void setEffectiveMinorVersion(int effectiveMinorVersion) {
+ this.effectiveMinorVersion = effectiveMinorVersion;
+ }
+
+ public int getEffectiveMinorVersion() {
+ return this.effectiveMinorVersion;
+ }
+
+ public String getMimeType(String filePath) {
+ return MimeTypeResolver.getMimeType(filePath);
+ }
+
+ public Set getResourcePaths(String path) {
+ String actualPath = (path.endsWith("/") ? path : path + "/");
+ Resource resource = this.resourceLoader.getResource(getResourceLocation(actualPath));
+ try {
+ File file = resource.getFile();
+ String[] fileList = file.list();
+ if (ObjectUtils.isEmpty(fileList)) {
+ return null;
+ }
+ Set resourcePaths = new LinkedHashSet(fileList.length);
+ for (String fileEntry : fileList) {
+ String resultPath = actualPath + fileEntry;
+ if (resource.createRelative(fileEntry).getFile().isDirectory()) {
+ resultPath += "/";
+ }
+ resourcePaths.add(resultPath);
+ }
+ return resourcePaths;
+ }
+ catch (IOException ex) {
+ logger.warn("Couldn't get resource paths for " + resource, ex);
+ return null;
+ }
+ }
+
+ public URL getResource(String path) throws MalformedURLException {
+ Resource resource = this.resourceLoader.getResource(getResourceLocation(path));
+ if (!resource.exists()) {
+ return null;
+ }
+ try {
+ return resource.getURL();
+ }
+ catch (MalformedURLException ex) {
+ throw ex;
+ }
+ catch (IOException ex) {
+ logger.warn("Couldn't get URL for " + resource, ex);
+ return null;
+ }
+ }
+
+ public InputStream getResourceAsStream(String path) {
+ Resource resource = this.resourceLoader.getResource(getResourceLocation(path));
+ if (!resource.exists()) {
+ return null;
+ }
+ try {
+ return resource.getInputStream();
+ }
+ catch (IOException ex) {
+ logger.warn("Couldn't open InputStream for " + resource, ex);
+ return null;
+ }
+ }
+
+ public RequestDispatcher getRequestDispatcher(String path) {
+ if (!path.startsWith("/")) {
+ throw new IllegalArgumentException("RequestDispatcher path at ServletContext level must start with '/'");
+ }
+ return new MockRequestDispatcher(path);
+ }
+
+ public RequestDispatcher getNamedDispatcher(String path) {
+ return this.namedRequestDispatchers.get(path);
+ }
+
+ /**
+ * Register a {@link javax.servlet.RequestDispatcher} (typically a {@link org.springframework.mock.web.MockRequestDispatcher})
+ * that acts as a wrapper for the named Servlet.
+ *
+ * @param name the name of the wrapped Servlet
+ * @param requestDispatcher the dispatcher that wraps the named Servlet
+ * @see #getNamedDispatcher
+ * @see #unregisterNamedDispatcher
+ */
+ public void registerNamedDispatcher(String name, RequestDispatcher requestDispatcher) {
+ Assert.notNull(name, "RequestDispatcher name must not be null");
+ Assert.notNull(requestDispatcher, "RequestDispatcher must not be null");
+ this.namedRequestDispatchers.put(name, requestDispatcher);
+ }
+
+ /**
+ * Unregister the {@link javax.servlet.RequestDispatcher} with the given name.
+ *
+ * @param name the name of the dispatcher to unregister
+ * @see #getNamedDispatcher
+ * @see #registerNamedDispatcher
+ */
+ public void unregisterNamedDispatcher(String name) {
+ Assert.notNull(name, "RequestDispatcher name must not be null");
+ this.namedRequestDispatchers.remove(name);
+ }
+
+ /**
+ * Get the name of the default {@code Servlet}.
+ * Defaults to {@value #COMMON_DEFAULT_SERVLET_NAME}.
+ * @see #setDefaultServletName
+ */
+ public String getDefaultServletName() {
+ return this.defaultServletName;
+ }
+
+ /**
+ * Set the name of the default {@code Servlet}.
+ *
Also {@link #unregisterNamedDispatcher unregisters} the current default
+ * {@link javax.servlet.RequestDispatcher} and {@link #registerNamedDispatcher replaces}
+ * it with a {@link org.springframework.mock.web.MockRequestDispatcher} for the provided
+ * {@code defaultServletName}.
+ * @param defaultServletName the name of the default {@code Servlet};
+ * never {@code null} or empty
+ * @see #getDefaultServletName
+ */
+ public void setDefaultServletName(String defaultServletName) {
+ Assert.hasText(defaultServletName, "defaultServletName must not be null or empty");
+ unregisterNamedDispatcher(this.defaultServletName);
+ this.defaultServletName = defaultServletName;
+ registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName));
+ }
+
+ public Servlet getServlet(String name) {
+ return null;
+ }
+
+ public Enumeration getServlets() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public Enumeration getServletNames() {
+ return Collections.enumeration(new HashSet());
+ }
+
+ public void log(String message) {
+ logger.info(message);
+ }
+
+ public void log(Exception ex, String message) {
+ logger.info(message, ex);
+ }
+
+ public void log(String message, Throwable ex) {
+ logger.info(message, ex);
+ }
+
+ public String getRealPath(String path) {
+ Resource resource = this.resourceLoader.getResource(getResourceLocation(path));
+ try {
+ return resource.getFile().getAbsolutePath();
+ }
+ catch (IOException ex) {
+ logger.warn("Couldn't determine real path of resource " + resource, ex);
+ return null;
+ }
+ }
+
+ public String getServerInfo() {
+ return "MockServletContext";
+ }
+
+ public String getInitParameter(String name) {
+ Assert.notNull(name, "Parameter name must not be null");
+ return this.initParameters.get(name);
+ }
+
+ public Enumeration getInitParameterNames() {
+ return Collections.enumeration(this.initParameters.keySet());
+ }
+
+ public boolean setInitParameter(String name, String value) {
+ Assert.notNull(name, "Parameter name must not be null");
+ if (this.initParameters.containsKey(name)) {
+ return false;
+ }
+ this.initParameters.put(name, value);
+ return true;
+ }
+
+ public void addInitParameter(String name, String value) {
+ Assert.notNull(name, "Parameter name must not be null");
+ this.initParameters.put(name, value);
+ }
+
+ public Object getAttribute(String name) {
+ Assert.notNull(name, "Attribute name must not be null");
+ return this.attributes.get(name);
+ }
+
+ public Enumeration getAttributeNames() {
+ return new Vector(this.attributes.keySet()).elements();
+ }
+
+ public void setAttribute(String name, Object value) {
+ Assert.notNull(name, "Attribute name must not be null");
+ if (value != null) {
+ this.attributes.put(name, value);
+ }
+ else {
+ this.attributes.remove(name);
+ }
+ }
+
+ public void removeAttribute(String name) {
+ Assert.notNull(name, "Attribute name must not be null");
+ this.attributes.remove(name);
+ }
+
+ public void setServletContextName(String servletContextName) {
+ this.servletContextName = servletContextName;
+ }
+
+ public String getServletContextName() {
+ return this.servletContextName;
+ }
+
+ public ClassLoader getClassLoader() {
+ return ClassUtils.getDefaultClassLoader();
+ }
+
+ public void declareRoles(String... roleNames) {
+ Assert.notNull(roleNames, "Role names array must not be null");
+ for (String roleName : roleNames) {
+ Assert.hasLength(roleName, "Role name must not be empty");
+ this.declaredRoles.add(roleName);
+ }
+ }
+
+ public Set getDeclaredRoles() {
+ return Collections.unmodifiableSet(this.declaredRoles);
+ }
+
+
+ /**
+ * Inner factory class used to introduce a Java Activation Framework
+ * dependency when actually asked to resolve a MIME type.
+ */
+ private static class MimeTypeResolver {
+
+ public static String getMimeType(String filePath) {
+ return FileTypeMap.getDefaultFileTypeMap().getContentType(filePath);
+ }
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/PassThroughFilterChain.java b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/PassThroughFilterChain.java
new file mode 100644
index 00000000000..b3484a0a83a
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/mock/web/PassThroughFilterChain.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2002-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.mock.web;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.springframework.util.Assert;
+
+/**
+ * Implementation of the {@link javax.servlet.FilterConfig} interface which
+ * simply passes the call through to a given Filter/FilterChain combination
+ * (indicating the next Filter in the chain along with the FilterChain that it is
+ * supposed to work on) or to a given Servlet (indicating the end of the chain).
+ *
+ * @author Juergen Hoeller
+ * @since 2.0.3
+ * @see javax.servlet.Filter
+ * @see javax.servlet.Servlet
+ * @see MockFilterChain
+ */
+public class PassThroughFilterChain implements FilterChain {
+
+ private Filter filter;
+
+ private FilterChain nextFilterChain;
+
+ private Servlet servlet;
+
+
+ /**
+ * Create a new PassThroughFilterChain that delegates to the given Filter,
+ * calling it with the given FilterChain.
+ * @param filter the Filter to delegate to
+ * @param nextFilterChain the FilterChain to use for that next Filter
+ */
+ public PassThroughFilterChain(Filter filter, FilterChain nextFilterChain) {
+ Assert.notNull(filter, "Filter must not be null");
+ Assert.notNull(nextFilterChain, "'FilterChain must not be null");
+ this.filter = filter;
+ this.nextFilterChain = nextFilterChain;
+ }
+
+ /**
+ * Create a new PassThroughFilterChain that delegates to the given Servlet.
+ * @param servlet the Servlet to delegate to
+ */
+ public PassThroughFilterChain(Servlet servlet) {
+ Assert.notNull(servlet, "Servlet must not be null");
+ this.servlet = servlet;
+ }
+
+
+ /**
+ * Pass the call on to the Filter/Servlet.
+ */
+ public void doFilter(ServletRequest request, ServletResponse response) throws ServletException, IOException {
+ if (this.filter != null) {
+ this.filter.doFilter(request, response, this.nextFilterChain);
+ }
+ else {
+ this.servlet.service(request, response);
+ }
+ }
+
+}
diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/orm/hibernate4/HibernateTransactionManagerTests.java b/spring-orm-hibernate4/src/test/java/org/springframework/orm/hibernate4/HibernateTransactionManagerTests.java
new file mode 100644
index 00000000000..65cf39acaf5
--- /dev/null
+++ b/spring-orm-hibernate4/src/test/java/org/springframework/orm/hibernate4/HibernateTransactionManagerTests.java
@@ -0,0 +1,1399 @@
+/*
+ * Copyright 2002-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.orm.hibernate4;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import java.sql.Savepoint;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import javax.sql.DataSource;
+
+import junit.framework.TestCase;
+import org.easymock.MockControl;
+import org.hibernate.FlushMode;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.exception.ConstraintViolationException;
+
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.jdbc.datasource.ConnectionHolder;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
+import org.springframework.transaction.CannotCreateTransactionException;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.UnexpectedRollbackException;
+import org.springframework.transaction.support.TransactionCallback;
+import org.springframework.transaction.support.TransactionCallbackWithoutResult;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.transaction.support.TransactionTemplate;
+
+/**
+ * @author Juergen Hoeller
+ * @since 3.2
+ */
+public class HibernateTransactionManagerTests extends TestCase {
+
+ public void testTransactionCommit() throws Exception {
+ MockControl dsControl = MockControl.createControl(DataSource.class);
+ final DataSource ds = (DataSource) dsControl.getMock();
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ final ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+ MockControl queryControl = MockControl.createControl(Query.class);
+ Query query = (Query) queryControl.getMock();
+
+ final List list = new ArrayList();
+ list.add("test");
+ con.getTransactionIsolation();
+ conControl.setReturnValue(Connection.TRANSACTION_READ_COMMITTED);
+ con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
+ conControl.setVoidCallable(1);
+ con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
+ conControl.setVoidCallable(1);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.getTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ tx.setTimeout(10);
+ txControl.setVoidCallable(1);
+ tx.begin();
+ txControl.setVoidCallable(1);
+ session.connection();
+ sessionControl.setReturnValue(con, 3);
+ session.createQuery("some query string");
+ sessionControl.setReturnValue(query, 1);
+ query.list();
+ queryControl.setReturnValue(list, 1);
+ tx.commit();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+
+ dsControl.replay();
+ conControl.replay();
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+ queryControl.replay();
+
+ LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() {
+ @Override
+ protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
+ return sf;
+ }
+ };
+ lsfb.afterPropertiesSet();
+ final SessionFactory sfProxy = lsfb.getObject();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager();
+ tm.setSessionFactory(sfProxy);
+ tm.setDataSource(ds);
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
+ tt.setTimeout(10);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ Object result = tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sfProxy));
+ assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sfProxy)).getSession();
+ return session.createQuery("some query string").list();
+ }
+ });
+ assertTrue("Correct result list", result == list);
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ dsControl.verify();
+ conControl.verify();
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ queryControl.verify();
+ }
+
+ public void testTransactionRollback() throws Exception {
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+ tx.rollback();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ session.connection();
+ sessionControl.setReturnValue(con, 2);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+
+ PlatformTransactionManager tm = new HibernateTransactionManager(sf);
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ try {
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ throw new RuntimeException("application exception");
+ }
+ });
+ fail("Should have thrown RuntimeException");
+ }
+ catch (RuntimeException ex) {
+ // expected
+ }
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ }
+
+ public void testTransactionRollbackOnly() throws Exception {
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.flush();
+ sessionControl.setVoidCallable(1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+ tx.rollback();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ session.connection();
+ sessionControl.setReturnValue(con, 2);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+
+ PlatformTransactionManager tm = new HibernateTransactionManager(sf);
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ session.flush();
+ status.setRollbackOnly();
+ return null;
+ }
+ });
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ }
+
+ public void testParticipatingTransactionWithCommit() throws Exception {
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ final ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.flush();
+ sessionControl.setVoidCallable(1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+ tx.commit();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ session.connection();
+ sessionControl.setReturnValue(con, 2);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+
+ LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() {
+ @Override
+ protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
+ return sf;
+ }
+ };
+ lsfb.afterPropertiesSet();
+ final SessionFactory sfProxy = lsfb.getObject();
+
+ PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy);
+ final TransactionTemplate tt = new TransactionTemplate(tm);
+ final List l = new ArrayList();
+ l.add("test");
+
+ Object result = tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ return tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ session.flush();
+ return l;
+ }
+ });
+ }
+ });
+ assertTrue("Correct result list", result == l);
+
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ }
+
+ public void testParticipatingTransactionWithRollback() throws Exception {
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+ tx.rollback();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ session.connection();
+ sessionControl.setReturnValue(con, 2);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+
+ PlatformTransactionManager tm = new HibernateTransactionManager(sf);
+ final TransactionTemplate tt = new TransactionTemplate(tm);
+ try {
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ return tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ throw new RuntimeException("application exception");
+ }
+ });
+ }
+ });
+ fail("Should have thrown RuntimeException");
+ }
+ catch (RuntimeException ex) {
+ // expected
+ }
+
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ }
+
+ public void testParticipatingTransactionWithRollbackOnly() throws Exception {
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+ tx.rollback();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ session.connection();
+ sessionControl.setReturnValue(con, 2);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+
+ PlatformTransactionManager tm = new HibernateTransactionManager(sf);
+ final TransactionTemplate tt = new TransactionTemplate(tm);
+
+ try {
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ return tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ status.setRollbackOnly();
+ return null;
+ }
+ });
+ }
+ });
+ fail("Should have thrown UnexpectedRollbackException");
+ }
+ catch (UnexpectedRollbackException ex) {
+ // expected
+ }
+
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ }
+
+ public void testParticipatingTransactionWithWithRequiresNew() throws Exception {
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl session1Control = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session1 = (ImplementingSession) session1Control.getMock();
+ MockControl session2Control = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session2 = (ImplementingSession) session2Control.getMock();
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session1, 1);
+ sf.openSession();
+ sfControl.setReturnValue(session2, 1);
+ session1.beginTransaction();
+ session1Control.setReturnValue(tx, 1);
+ session2.beginTransaction();
+ session2Control.setReturnValue(tx, 1);
+ session2.flush();
+ session2Control.setVoidCallable(1);
+ session1.close();
+ session1Control.setReturnValue(null, 1);
+ session2.close();
+ session2Control.setReturnValue(null, 1);
+ tx.commit();
+ txControl.setVoidCallable(2);
+ session1.isConnected();
+ session1Control.setReturnValue(true, 1);
+ session1.connection();
+ session1Control.setReturnValue(con, 2);
+ session2.isConnected();
+ session2Control.setReturnValue(true, 1);
+ session2.connection();
+ session2Control.setReturnValue(con, 2);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 2);
+
+ sfControl.replay();
+ session1Control.replay();
+ session2Control.replay();
+ conControl.replay();
+ txControl.replay();
+
+ PlatformTransactionManager tm = new HibernateTransactionManager(sf);
+ final TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ final SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
+ assertTrue("Has thread session", holder != null);
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ assertTrue("Not enclosing session", session != holder.getSession());
+ session.flush();
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ return null;
+ }
+ });
+ assertTrue("Same thread session as before",
+ holder.getSession() == ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession());
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ return null;
+ }
+ });
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+
+ sfControl.verify();
+ session1Control.verify();
+ session2Control.verify();
+ conControl.verify();
+ txControl.verify();
+ }
+
+ public void testParticipatingTransactionWithWithNotSupported() throws Exception {
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+ tx.commit();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ session.connection();
+ sessionControl.setReturnValue(con, 2);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+
+ sfControl.replay();
+ sessionControl.replay();
+ conControl.replay();
+ txControl.replay();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager(sf);
+ final TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
+ assertTrue("Has thread session", holder != null);
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
+ return null;
+ }
+ });
+ assertTrue("Same thread session as before",
+ holder.getSession() == ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession());
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ return null;
+ }
+ });
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ }
+
+ public void testTransactionWithPropagationSupports() throws Exception {
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ final ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.flush();
+ sessionControl.setVoidCallable(1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+ sfControl.replay();
+ sessionControl.replay();
+
+ LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() {
+ @Override
+ protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
+ return sf;
+ }
+ };
+ lsfb.afterPropertiesSet();
+ final SessionFactory sfProxy = lsfb.getObject();
+
+ PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy);
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
+
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
+ assertTrue("Is not new transaction", !status.isNewTransaction());
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
+ Session session = sf.openSession();
+ session.flush();
+ session.close();
+ return null;
+ }
+ });
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
+ sfControl.verify();
+ sessionControl.verify();
+ }
+
+ public void testTransactionWithPropagationSupportsAndInnerTransaction() throws Exception {
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl session1Control = MockControl.createControl(ImplementingSession.class);
+ final ImplementingSession session1 = (ImplementingSession) session1Control.getMock();
+ MockControl session2Control = MockControl.createControl(ImplementingSession.class);
+ final ImplementingSession session2 = (ImplementingSession) session2Control.getMock();
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session1, 1);
+ session1.flush();
+ session1Control.setVoidCallable(1);
+ session1.close();
+ session1Control.setReturnValue(null, 1);
+
+ sf.openSession();
+ sfControl.setReturnValue(session2, 1);
+ session2.beginTransaction();
+ session2Control.setReturnValue(tx, 1);
+ session2.connection();
+ session2Control.setReturnValue(con, 2);
+ session2.flush();
+ session2Control.setVoidCallable(1);
+ tx.commit();
+ txControl.setVoidCallable(1);
+ session2.isConnected();
+ session2Control.setReturnValue(true, 1);
+ session2.close();
+ session2Control.setReturnValue(null, 1);
+ sfControl.replay();
+ session1Control.replay();
+ session2Control.replay();
+ txControl.replay();
+
+ LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() {
+ @Override
+ protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
+ return sf;
+ }
+ };
+ lsfb.afterPropertiesSet();
+ final SessionFactory sfProxy = lsfb.getObject();
+
+ PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy);
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
+ final TransactionTemplate tt2 = new TransactionTemplate(tm);
+ tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
+ assertTrue("Is not new transaction", !status.isNewTransaction());
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
+ Session session = sfProxy.openSession();
+ assertSame(session1, session);
+ tt2.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ assertSame(session2, session);
+ session.flush();
+ return null;
+ }
+ });
+ session.flush();
+ session.close();
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
+ return null;
+ }
+ });
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+
+ sfControl.verify();
+ session1Control.verify();
+ session2Control.verify();
+ txControl.verify();
+ }
+
+ public void testTransactionCommitWithReadOnly() throws Exception {
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+ MockControl queryControl = MockControl.createControl(Query.class);
+ Query query = (Query) queryControl.getMock();
+
+ final List list = new ArrayList();
+ list.add("test");
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.setFlushMode(FlushMode.MANUAL);
+ sessionControl.setVoidCallable(1);
+ session.connection();
+ sessionControl.setReturnValue(con, 2);
+ con.setReadOnly(true);
+ conControl.setVoidCallable(1);
+ session.createQuery("some query string");
+ sessionControl.setReturnValue(query, 1);
+ query.list();
+ queryControl.setReturnValue(list, 1);
+ tx.commit();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ con.isReadOnly();
+ conControl.setReturnValue(true, 1);
+ con.setReadOnly(false);
+ conControl.setVoidCallable(1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+
+ conControl.replay();
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+ queryControl.replay();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager(sf);
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setReadOnly(true);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ Object result = tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ return session.createQuery("some query string").list();
+ }
+ });
+ assertTrue("Correct result list", result == list);
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ conControl.verify();
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ queryControl.verify();
+ }
+
+ public void testTransactionCommitWithFlushFailure() throws Exception {
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ tx.commit();
+ SQLException sqlEx = new SQLException("argh", "27");
+ Exception rootCause = null;
+ ConstraintViolationException jdbcEx = new ConstraintViolationException("mymsg", sqlEx, null);
+ txControl.setThrowable(jdbcEx, 1);
+ rootCause = jdbcEx;
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+ tx.rollback();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ session.connection();
+ sessionControl.setReturnValue(con, 2);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+ conControl.replay();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager(sf);
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ final List l = new ArrayList();
+ l.add("test");
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ try {
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ return l;
+ }
+ });
+ fail("Should have thrown DataIntegrityViolationException");
+ }
+ catch (DataIntegrityViolationException ex) {
+ // expected
+ assertEquals(rootCause, ex.getCause());
+ assertTrue(ex.getMessage().indexOf("mymsg") != -1);
+ }
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ conControl.verify();
+ }
+
+ public void testTransactionCommitWithPreBound() throws Exception {
+ MockControl dsControl = MockControl.createControl(DataSource.class);
+ final DataSource ds = (DataSource) dsControl.getMock();
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ final ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ session.getFlushMode();
+ sessionControl.setReturnValue(FlushMode.AUTO, 2);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.connection();
+ sessionControl.setReturnValue(con, 3);
+ con.getTransactionIsolation();
+ conControl.setReturnValue(Connection.TRANSACTION_READ_COMMITTED);
+ con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
+ conControl.setVoidCallable(1);
+ con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
+ conControl.setVoidCallable(1);
+ tx.commit();
+ txControl.setVoidCallable(1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+ session.disconnect();
+ sessionControl.setReturnValue(null, 1);
+
+ dsControl.replay();
+ conControl.replay();
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager();
+ tm.setSessionFactory(sf);
+ tm.setDataSource(ds);
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
+ final List l = new ArrayList();
+ l.add("test");
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+
+ Object result = tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
+ SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
+ assertTrue("Has thread transaction", sessionHolder.getTransaction() != null);
+ Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ assertEquals(session, sess);
+ return l;
+ }
+ });
+ assertTrue("Correct result list", result == l);
+
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
+ assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null);
+ TransactionSynchronizationManager.unbindResource(sf);
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ dsControl.verify();
+ conControl.verify();
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ }
+
+ public void testTransactionRollbackWithPreBound() throws Exception {
+ MockControl dsControl = MockControl.createControl(DataSource.class);
+ final DataSource ds = (DataSource) dsControl.getMock();
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ final ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl tx1Control = MockControl.createControl(Transaction.class);
+ final Transaction tx1 = (Transaction) tx1Control.getMock();
+ MockControl tx2Control = MockControl.createControl(Transaction.class);
+ final Transaction tx2 = (Transaction) tx2Control.getMock();
+
+ session.getFlushMode();
+ sessionControl.setReturnValue(FlushMode.AUTO, 4);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx1, 1);
+ tx1.rollback();
+ tx1Control.setVoidCallable(1);
+ session.clear();
+ sessionControl.setVoidCallable(1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx2, 1);
+ tx2.commit();
+ tx2Control.setVoidCallable(1);
+
+ session.isConnected();
+ sessionControl.setReturnValue(true, 2);
+ session.connection();
+ sessionControl.setReturnValue(con, 6);
+ con.isReadOnly();
+ conControl.setReturnValue(false, 2);
+ session.disconnect();
+ sessionControl.setReturnValue(null, 2);
+
+ dsControl.replay();
+ conControl.replay();
+ sfControl.replay();
+ sessionControl.replay();
+ tx1Control.replay();
+ tx2Control.replay();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager();
+ tm.setSessionFactory(sf);
+ tm.setDataSource(ds);
+ final TransactionTemplate tt = new TransactionTemplate(tm);
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+
+ try {
+ tt.execute(new TransactionCallbackWithoutResult() {
+ public void doInTransactionWithoutResult(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
+ SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
+ assertEquals(tx1, sessionHolder.getTransaction());
+ tt.execute(new TransactionCallbackWithoutResult() {
+ public void doInTransactionWithoutResult(TransactionStatus status) {
+ status.setRollbackOnly();
+ Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ assertEquals(session, sess);
+ }
+ });
+ }
+ });
+ fail("Should have thrown UnexpectedRollbackException");
+ }
+ catch (UnexpectedRollbackException ex) {
+ // expected
+ }
+
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
+ assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null);
+ assertTrue("Not marked rollback-only", !sessionHolder.isRollbackOnly());
+
+ tt.execute(new TransactionCallbackWithoutResult() {
+ public void doInTransactionWithoutResult(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
+ SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
+ assertEquals(tx2, sessionHolder.getTransaction());
+ Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ assertEquals(session, sess);
+ }
+ });
+
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null);
+ TransactionSynchronizationManager.unbindResource(sf);
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ dsControl.verify();
+ conControl.verify();
+ sfControl.verify();
+ sessionControl.verify();
+ tx1Control.verify();
+ tx2Control.verify();
+ }
+
+ public void testTransactionRollbackWithHibernateManagedSession() throws Exception {
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ final ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl tx1Control = MockControl.createControl(Transaction.class);
+ final Transaction tx1 = (Transaction) tx1Control.getMock();
+ MockControl tx2Control = MockControl.createControl(Transaction.class);
+ final Transaction tx2 = (Transaction) tx2Control.getMock();
+
+ sf.getCurrentSession();
+ sfControl.setReturnValue(session, 2);
+ session.getFlushMode();
+ sessionControl.setReturnValue(FlushMode.AUTO, 4);
+ session.getTransaction();
+ sessionControl.setReturnValue(tx1, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx1, 1);
+ tx1.isActive();
+ tx1Control.setReturnValue(false, 1);
+ tx1.rollback();
+ tx1Control.setVoidCallable(1);
+ session.getTransaction();
+ sessionControl.setReturnValue(tx2, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx2, 1);
+ tx2.isActive();
+ tx2Control.setReturnValue(false, 1);
+ tx2.commit();
+ tx2Control.setVoidCallable(1);
+
+ sfControl.replay();
+ sessionControl.replay();
+ tx1Control.replay();
+ tx2Control.replay();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager();
+ tm.setSessionFactory(sf);
+ tm.setPrepareConnection(false);
+ tm.setHibernateManagedSession(true);
+ final TransactionTemplate tt = new TransactionTemplate(tm);
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+
+ try {
+ tt.execute(new TransactionCallbackWithoutResult() {
+ public void doInTransactionWithoutResult(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ tt.execute(new TransactionCallbackWithoutResult() {
+ public void doInTransactionWithoutResult(TransactionStatus status) {
+ status.setRollbackOnly();
+ Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ assertEquals(session, sess);
+ }
+ });
+ }
+ });
+ fail("Should have thrown UnexpectedRollbackException");
+ }
+ catch (UnexpectedRollbackException ex) {
+ // expected
+ }
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+
+ tt.execute(new TransactionCallbackWithoutResult() {
+ public void doInTransactionWithoutResult(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ assertEquals(session, sess);
+ }
+ });
+
+ sfControl.verify();
+ sessionControl.verify();
+ tx1Control.verify();
+ tx2Control.verify();
+ }
+
+ public void testExistingTransactionWithPropagationNestedAndRollback() throws Exception {
+ doTestExistingTransactionWithPropagationNestedAndRollback(false);
+ }
+
+ public void testExistingTransactionWithManualSavepointAndRollback() throws Exception {
+ doTestExistingTransactionWithPropagationNestedAndRollback(true);
+ }
+
+ private void doTestExistingTransactionWithPropagationNestedAndRollback(final boolean manualSavepoint)
+ throws Exception {
+
+ MockControl dsControl = MockControl.createControl(DataSource.class);
+ final DataSource ds = (DataSource) dsControl.getMock();
+ MockControl conControl = MockControl.createControl(Connection.class);
+ Connection con = (Connection) conControl.getMock();
+ MockControl mdControl = MockControl.createControl(DatabaseMetaData.class);
+ DatabaseMetaData md = (DatabaseMetaData) mdControl.getMock();
+ MockControl spControl = MockControl.createControl(Savepoint.class);
+ Savepoint sp = (Savepoint) spControl.getMock();
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+ MockControl queryControl = MockControl.createControl(Query.class);
+ Query query = (Query) queryControl.getMock();
+
+ final List list = new ArrayList();
+ list.add("test");
+ con.isReadOnly();
+ conControl.setReturnValue(false, 1);
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.connection();
+ sessionControl.setReturnValue(con, 3);
+ md.supportsSavepoints();
+ mdControl.setReturnValue(true, 1);
+ con.getMetaData();
+ conControl.setReturnValue(md, 1);
+ con.setSavepoint(ConnectionHolder.SAVEPOINT_NAME_PREFIX + 1);
+ conControl.setReturnValue(sp, 1);
+ con.rollback(sp);
+ conControl.setVoidCallable(1);
+ session.createQuery("some query string");
+ sessionControl.setReturnValue(query, 1);
+ query.list();
+ queryControl.setReturnValue(list, 1);
+ session.isConnected();
+ sessionControl.setReturnValue(true, 1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+ tx.commit();
+ txControl.setVoidCallable(1);
+
+ dsControl.replay();
+ conControl.replay();
+ mdControl.replay();
+ spControl.replay();
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+ queryControl.replay();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager();
+ tm.setNestedTransactionAllowed(true);
+ tm.setSessionFactory(sf);
+ tm.setDataSource(ds);
+ final TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ Object result = tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
+ if (manualSavepoint) {
+ Object savepoint = status.createSavepoint();
+ status.rollbackToSavepoint(savepoint);
+ }
+ else {
+ tt.execute(new TransactionCallbackWithoutResult() {
+ protected void doInTransactionWithoutResult(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
+ status.setRollbackOnly();
+ }
+ });
+ }
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ return session.createQuery("some query string").list();
+ }
+ });
+ assertTrue("Correct result list", result == list);
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ dsControl.verify();
+ conControl.verify();
+ mdControl.verify();
+ spControl.verify();
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ queryControl.verify();
+ }
+
+ public void testTransactionCommitWithNonExistingDatabase() throws Exception {
+ final DriverManagerDataSource ds = new DriverManagerDataSource();
+ LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
+ lsfb.setDataSource(ds);
+ Properties props = new Properties();
+ props.setProperty("hibernate.dialect", HSQLDialect.class.getName());
+ lsfb.setHibernateProperties(props);
+ lsfb.afterPropertiesSet();
+ final SessionFactory sf = lsfb.getObject();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager();
+ tm.setSessionFactory(sf);
+ tm.afterPropertiesSet();
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
+ tt.setTimeout(10);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ try {
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ return session.createQuery("from java.lang.Object").list();
+ }
+ });
+ fail("Should have thrown CannotCreateTransactionException");
+ }
+ catch (CannotCreateTransactionException ex) {
+ // expected
+ }
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ }
+
+ public void testTransactionCommitWithPreBoundSessionAndNonExistingDatabase() throws Exception {
+ final DriverManagerDataSource ds = new DriverManagerDataSource();
+ LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
+ lsfb.setDataSource(ds);
+ Properties props = new Properties();
+ props.setProperty("hibernate.dialect", HSQLDialect.class.getName());
+ lsfb.setHibernateProperties(props);
+ lsfb.afterPropertiesSet();
+ final SessionFactory sf = lsfb.getObject();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager();
+ tm.setSessionFactory(sf);
+ tm.afterPropertiesSet();
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
+ tt.setTimeout(10);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ Session session = sf.openSession();
+ TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
+ try {
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ return session.createQuery("from java.lang.Object").list();
+ }
+ });
+ fail("Should have thrown CannotCreateTransactionException");
+ }
+ catch (CannotCreateTransactionException ex) {
+ // expected
+ SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
+ assertFalse(holder.isSynchronizedWithTransaction());
+ }
+ finally {
+ TransactionSynchronizationManager.unbindResource(sf);
+ session.close();
+ }
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ }
+
+ public void testTransactionCommitWithNonExistingDatabaseAndLazyConnection() throws Exception {
+ DriverManagerDataSource dsTarget = new DriverManagerDataSource();
+ final LazyConnectionDataSourceProxy ds = new LazyConnectionDataSourceProxy();
+ ds.setTargetDataSource(dsTarget);
+ ds.setDefaultAutoCommit(true);
+ ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
+ //ds.setDefaultTransactionIsolationName("TRANSACTION_READ_COMMITTED");
+
+ LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
+ lsfb.setDataSource(ds);
+ Properties props = new Properties();
+ props.setProperty("hibernate.dialect", HSQLDialect.class.getName());
+ props.setProperty("hibernate.temp.use_jdbc_metadata_defaults", "false");
+ lsfb.setHibernateProperties(props);
+ lsfb.afterPropertiesSet();
+ final SessionFactory sf = lsfb.getObject();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager();
+ tm.setSessionFactory(sf);
+ tm.afterPropertiesSet();
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
+ tt.setTimeout(10);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ tt.execute(new TransactionCallback() {
+ public Object doInTransaction(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
+ Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
+ return session.createQuery("from java.lang.Object").list();
+ }
+ });
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ }
+
+ public void testTransactionFlush() throws Exception {
+ MockControl sfControl = MockControl.createControl(SessionFactory.class);
+ final SessionFactory sf = (SessionFactory) sfControl.getMock();
+ MockControl sessionControl = MockControl.createControl(ImplementingSession.class);
+ final ImplementingSession session = (ImplementingSession) sessionControl.getMock();
+ MockControl txControl = MockControl.createControl(Transaction.class);
+ Transaction tx = (Transaction) txControl.getMock();
+
+ sf.openSession();
+ sfControl.setReturnValue(session, 1);
+ session.beginTransaction();
+ sessionControl.setReturnValue(tx, 1);
+ session.flush();
+ sessionControl.setVoidCallable(1);
+ tx.commit();
+ txControl.setVoidCallable(1);
+ session.close();
+ sessionControl.setReturnValue(null, 1);
+
+ sfControl.replay();
+ sessionControl.replay();
+ txControl.replay();
+
+ HibernateTransactionManager tm = new HibernateTransactionManager(sf);
+ tm.setPrepareConnection(false);
+ TransactionTemplate tt = new TransactionTemplate(tm);
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+
+ tt.execute(new TransactionCallbackWithoutResult() {
+ public void doInTransactionWithoutResult(TransactionStatus status) {
+ assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ status.flush();
+ }
+ });
+
+ assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
+ assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
+ sfControl.verify();
+ sessionControl.verify();
+ txControl.verify();
+ }
+
+ protected void tearDown() {
+ assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty());
+ assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
+ assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
+ assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
+ }
+
+
+ public interface ImplementingSession extends Session, SessionImplementor {
+ }
+
+}