I am trying to create an application using spring mvc and hibenate. I have been seeing the exception failed to lazily initialize a collection of role for nearly two days now :( The application runs fine if I eager load the collections. But I don't want it that way.
I tried implementing OpenSessionInViewFilter in web.xml but still the error persisted. I tried to extend OpenSessionInViewFilter and use my own filter, even now the problem remains unsolved. Here is the filter I implemented
public class HibernateFilter extends OpenSessionInViewFilter {
#Override
protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
Session session = super.getSession(sessionFactory);
session.setFlushMode(FlushMode.AUTO);
return session;
}
#Override
protected void closeSession(Session session, SessionFactory sessionFactory) {
try {
if (session != null && session.isOpen() && session.isConnected()) {
try {
session.flush();
} catch (HibernateException e) {
throw new CleanupFailureDataAccessException("Failed to flush session before close: " + e.getMessage(), e);
} catch (Exception e) {
}
}
} finally {
super.closeSession(session, sessionFactory);
}
}
}
I ran the application in debug mode. I find the session to be not null, and the closeSession gets invoked only after it passes through the controller code. But still if I try to fetch a collection in the controller when the session is open it fails :( Here is my web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/blog-servlet.xml</param-value>
</context-param>
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
core.HibernateFilter
</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>mySessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>blog</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>blog</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
What is going wrong?
As #sfussenegger mentioned...I am using sessions to identify the current user. This is my controller code:
#RequestMapping("/show.htm")
public String show(ModelMap model, HttpSession session) {
User u = (User) session.getAttribute("currentUser");
model.addAttribute("user", u);
if (u.getBlogs() != null) {
List<Blog> blogs = new ArrayList<Blog>(u.getBlogs());
model.addAttribute("myBlogs", blogs);
}
return "show";
}
and my jsp iterates over the MYblogs I collected in the model
My controller code:
Integer uid = (Integer) session.getAttribute("currentUser");
User user = getUserDao().findById(uid);
model.addAttribute("user", user);
if (user.getBlogs() != null) {
List<Blog> blogs = new ArrayList<Blog>(user.getBlogs()); //fails here
model.addAttribute("myBlogs", blogs);
}
return "show";
}
exception raised:
StandardWrapperValve[try-blog]: PWC1406: Servlet.service() for servlet try-blog threw exception
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ValueObjects.User.blogs, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
at org.hibernate.collection.PersistentSet.toArray(PersistentSet.java:194)
at java.util.ArrayList.<init>(ArrayList.java:131)
at Controllers.UserController.show(UserController.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:421)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:136)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:326)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:313)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:427)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:333)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:313)
at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:287)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:218)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:94)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:98)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:222)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:166)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:288)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:647)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:579)
at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:831)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:341)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:263)
at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:214)
at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:265)
at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106)
Dick is correct, controller class might be doing something funny.
Another point is make sure you have all the required jar in your classpath such as cglib or javaassist.
It might be easier to use springs openSessionInViewInterceptor instead of OpenSessionInViewFilter (since you are already using spring).
simply add the following on your blog-servlet.xml config (you can of course split this to multiple files)
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors"><list>
<ref bean="openSessionInViewInterceptor" />
</list></property>
</bean>
<bean id="openSessionInViewInterceptor" class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor">
<property name="entityManagerFactory"><ref local="entityManagerFactory"/></property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="ha-admin" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:database="ORACLE" p:showSql="true" />
</property>
<property name="jpaPropertyMap">
<props>
<!-- Enable Hibernate statistics generation
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">/ehcache.xml</prop>
<prop key="hibernate.generate_statistics">true</prop>
-->
</props>
</property>
</bean>
You need to add datasource on the configuration file and remove hibernateFilter from your web.xml.
Most likely you are using detached objects, i.e. object that have been loaded in a different session than the one created by your OpenSessionInViewFilter. This might happen when you store objects in the session and access them from a subsequent request. Is this possible?
Edit:
I'd discourage keeping the User object in the session. Instead, only keep the id and fetch the User object from DB each time it's needed. Hence, instead of your current approach, you should use something like this
User getUserFromSession(HttpSession session) {
Integer userId = (Integer) session.getAttribute("currentUser");
return userId != null ? getObjectById(User.class, userId) : null;
}
Note that fetching an object by id is insanely fast, especially if you've configured Hibernate's second level cache to store User object - so forget about any performance considerations. The main advantage though is that you don't have to deal with detached objects anymore. Detached objects are evil and nobody likes them! ;)
And as #skaffman mentioned, go back to the default OpenSessionInViewFilter as your implementation obviously won't solve your problem.
Hmmm, probably you are not going to change your ORM at this stage - but it is a nice reminder of why "Session-less" ORM's are interesting.
e.g. Ebean ORM ... no sessions, lazy loading just works (no filter required) - means you never hit this issue.
Just an idea: for me it helped to change the order of my filters. I had a url rewrite filter and the order with the session filter was important.
Just a thought...
If your code is failing in the controller, then the Filter is a red herring. Your Hibernate session should still be open at this point, filter or no filter.
Could you post your DAO code and the associated config?
You said that your application runs fine when you eagerly load the collection object.
Since you are using user object from the httpsession from another request, you might have to reattach the user object using refresh or update.
does the following code work?
User u = (User) session.getAttribute("currentUser");
User newUser = service.getUser(u.getUserId);
System.out.println(newUser.getBlogs());
And see if this helps. could you also list the jar files in your classpath.
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value> <!-- or false -->
</init-param>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Related
I'm trying to modify a wicket application to store the session in redis via spring-session. The session is showing up in redis, but I've run into a problem that whenever the application makes a standard wicket ajax call, the response from wicket includes an Ajax-Location header that is interpreted by wicket-ajax-jquery.js triggering a page redirect. But this only happens AFTER the first ajax call has been successful. For example, the first ajax call may look like this:
http://host:port/context/help/admin?0-1.IBehaviorListener.0-smartTable-tableArea-records-0-row-detailToggleCell-detailToggleLink&_=1636756805561
and the response headers do NOT include Ajax-Location. And then later, the next ajax call may look like this:
http://host:port/context/help/admin?1-1.IBehaviorListener.0-smartTable-tableArea-records-0-row-detailToggleCell-detailToggleLink&_=1636756906417
But the response header now includes this:
Ajax-Location: ./admin?2
and instead of just doing the ajax update to the page, the entire page redirects to the URL specified in that header because of code in src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js
Digging down into the wicket-core code using the debugger, consider this where it doesn't produce the Ajax-Location header and works properly:
Step completed: "thread=ba6f07:3", org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.respond(), line=197 bci=169
ba6f07:3[1] print canCallListenerInterfaceAfterExpiry
canCallListenerInterfaceAfterExpiry = false
ba6f07:3[1] print freshPage
freshPage = false
ba6f07:3[1] print isStateless
isStateless = false
ba6f07:3[1] print component
component = "[AjaxLink [Component id = detailToggleLink]]"
and then compare with this where it DOES produce an Ajax-Location header and doesn't work properly:
Breakpoint hit: "thread=ba6f07:7", org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.respond(), line=197 bci=169
ba6f07:7[1] print canCallListenerInterfaceAfterExpiry
canCallListenerInterfaceAfterExpiry = false
ba6f07:7[1] print freshPage
freshPage = true
ba6f07:7[1] print isStateless
isStateless = false
ba6f07:7[1] print component
component = null
The difference being that when it doesn't work, freshPage is true and component is null.
Note: this pattern is fully functional in another similar application that I have and I’ve spent some time comparing the two. Clearly, something is missing from the original application in the app that I’m working on but I haven’t been able to identify it yet.
My redis http session config class looks like this:
import javax.annotation.PostConstruct;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;
import org.springframework.session.web.http.CookieHttpSessionStrategy;
import org.springframework.session.web.http.DefaultCookieSerializer;
#Configuration
#EnableRedisHttpSession
public class MyRedisHttpSessionConfig extends RedisHttpSessionConfiguration
{
private JedisConnectionFactory connectionFactory;
#PostConstruct
public void init()
{
CookieHttpSessionStrategy strategy = new CookieHttpSessionStrategy();
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setCookieName( "SESSION" );
strategy.setCookieSerializer(cookieSerializer);
setHttpSessionStrategy( strategy );
}
#Bean
public JedisConnectionFactory connectionFactory() throws Exception
{
return connectionFactory;
}
public void setConnectionFactory( JedisConnectionFactory connectionFactory )
{
this.connectionFactory = connectionFactory;
}
}
my web.xml has this:
...
<filter>
<filter-name>requestLoggingFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter>
<filter-name>myApplicationWicketFilter</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
<init-param>
<param-name>filterMappingUrlPattern</param-name>
<param-value>/*</param-value>
</init-param>
</filter>
...
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
<filter-mapping>
<filter-name>ariesApplicationWicketFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
...
and my spring beans config file has this:
...
<!-- The RedisHttpSessionConfiguration creates an http Filter bean with name "springSessionRepositoryFilter" which is referenced in web.xml -->
<context:annotation-config/>
<util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>
<bean class="MyRedisHttpSessionConfig">
<property name="connectionFactory" ref="webTierRedisConnectionFactory"/>
</bean>
<bean id="webTierRedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${service-tier:redisSentinelMasterName}"/>
<property name="port" value="${service-tier:redisSentinelHostPortCsv}"/>
<property name="usePool" value="true"/>
<property name="poolConfig">
<bean class="redis.clients.jedis.JedisPoolConfig">
<property name="maxWaitMillis" value="5000"/>
<property name="maxTotal" value="50"/>
<property name="maxIdle" value="5"/>
<property name="minIdle" value="1"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<property name="numTestsPerEvictionRun" value="10"/>
</bean>
</property>
</bean>
...
Ivy Dependencies include:
<!-- these are for redis httpsession -->
<dependency org="redis.clients" name="jedis" rev="2.8.1"/>
<dependency org="org.springframework.data" name="spring-data-redis" rev="1.7.4.RELEASE"/>
<dependency org="org.springframework.data" name="spring-data-keyvalue" rev="1.1.4.RELEASE"/>
<dependency org="org.springframework.session" name="spring-session" rev="1.2.2.RELEASE"/>
and wicket 7.5.0 and spring 4.2.8 stuff.
Anybody have any insights on what might be going on? Why after putting the session into redis (which it is showing up there, I see it (via redis-cli and keys and dump commands), most ajax calls are triggering full page redirects due to response headers from the ajax call including Ajax-Location?
This turned out to be caused by a custom org.apache.wicket.IPageManagerProvider implementation which needed to be replaced with a version that was compatible with redis.
I a'm developing web application for websphere 7.0. It's XML based spring 3.1 application. In my application I use many configuration properties files. But in production we don't have access to file system on websphere server, so we don't have access to spring or properties files or web.xml. Therefore we need override properties from configuration files in websphere administration console. But also we need programmatic access to resolved values of some properties overrided by administrator.
I've found that context:property-placeholder resolve both context parmeters and entry-env from web.xml and override properties from file as it should be in my application, but I don't know how to get properties programatically from context:property-placeholder(it's new PropertySourcesPlaceholderConfigurer).
And in my case I could not get util:properties to be overrided by context parameters or entry-env values. As and PropertyPlaceholderConfigurer.
Also I can't edit Context parameters from websphere administration console. I didn't find this functionality and google doesn't give answers. In console I can edit only servlet initialization parameters or entry-env values.
My situation:
web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/webappconf.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/springServlet</url-pattern>
</servlet-mapping>
<env-entry>
<env-entry-name>AA.AA</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>Override AA.AA</env-entry-value>
</env-entry>
webappconf.xml
any properties resolver definition
<bean id="springService" class="ru.test.krp.SpringService">
<property name="a" value="${AA.AA}" />
<property name="b" value="${BB.BB}" />
<property name="c" value="${CC.CC}" />
<property name="config" ref="any refrence to properties for access from code"/>
</bean>
<bean id="springServlet" class="ru.test.krp.SpringServlet">
<property name="springService" ref="springService"></property>
</bean>
SpringService.java
public class SpringService {
private String a;
private String b;
private String c;
private Properties config;
// getter/setter pairs
I will appreciate any help or ideas.
You can put your configuration properties files into shared libraries. Library shoud be attached to your application.
All that you need to it's only how to reread new configuration.
Java Servlet API can forward requests to another path within the same server (identical host:port). But, forwarding to a different host:port — like proxy do — is another story.
I've tried to do that with Jersey Client, adapting the ServletRequest — method, headers, mediatype and body — to a Jersey ClientRequest (with a different base uri), making the call, and adapting back the Jersey ClientResponse — method, headers, mediatype and body — to the ServletResponse.
Adapting those manually seems wrong to me.
Isn't there a pure Servlet API solution?
Or an HTTP client capable of adapting requests back and forth when changing the host:port?
HTTP-Proxy-Servlet does exactly what you need.
Quick configuration
pom.xml
<dependency>
<groupId>org.mitre.dsmiley.httpproxy</groupId>
<artifactId>smiley-http-proxy-servlet</artifactId>
<version>1.7</version>
</dependency>
web.xml
<servlet>
<servlet-name>solr</servlet-name>
<servlet-class>org.mitre.dsmiley.httpproxy.ProxyServlet</servlet-class>
<init-param>
<param-name>targetUri</param-name>
<param-value>http://solrserver:8983/solr</param-value>
</init-param>
<init-param>
<param-name>log</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>solr</servlet-name>
<url-pattern>/solr/*</url-pattern>
</servlet-mapping>
Spring Integration
see also: HTTP-Proxy-Servlet Issue #15
pom.xml
<dependency>
<groupId>org.mitre.dsmiley.httpproxy</groupId>
<artifactId>smiley-http-proxy-servlet</artifactId>
<version>1.7</version>
</dependency>
ServletWrappingControllerExt.java
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.ServletWrappingController;
public class ServletWrappingControllerExt extends ServletWrappingController
{
private String pathToStrip;
public void setPathToStrip(String pathToStrip)
{
this.pathToStrip = pathToStrip;
}
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception
{
final HttpServletRequest wrapper = new HttpServletRequestWrapper(request)
{
#Override
public String getPathInfo()
{
//Please note that getPathInfo returns null if DispatcherServlet is configured to track url-pattern "/"
//It should be configured to track url-pattern "/*". Below is a sample DispatcherServlet configuration
/*
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
*/
String path = super.getPathInfo();
if (path.startsWith(pathToStrip))
{
final int length = pathToStrip.length();
path = path.substring(length);
}
return path;
}
#Override
public String getServletPath()
{
return super.getServletPath();
}
};
return super.handleRequestInternal(wrapper, response);
}
}
Beans configuration
<bean id="myServletWrapper" class="ServletWrappingControllerExt">
<property name="pathToStrip" value="/solr"/>
<property name="servletClass" value="org.mitre.dsmiley.httpproxy.ProxyServlet" />
<property name="servletName" value="solr" />
<property name="initParameters">
<props>
<prop key="targetUri">http://solrserver:8983/solr</prop>
<prop key="log">true</prop>
</props>
</property>
</bean>
<bean id="myServletUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/solr/**" value-ref="myServletWrapper" />
</map>
</property>
<property name="order" value="1" />
</bean>
You should use javax.net.HttpURLConnection
Here is the psuedo code for that:
URL url = new URL("http://otherserver:otherport/url");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
// set http method if required
connection.setRequestMethod("POST");
// set request header if required
connection.setRequestProperty("header1", "value1");
// check status code
if(connection.getResponseCode() == 200) {
InputStream is = connection.getInputStream();
//transfer is to the required output stream
} else {
//write error
}
As far as I understand You need to send requests from Servlet and get response from other server into yours, may be you need a HTTP Client (Overview) for that.
This question might also help you.
I am trying to get a small sample web app up and running but I have run into a problem injecting the Entity Manager Factory.
My persistence.xml is as follows;
<persistence version="2.0" xmlns=" http://java.sun.com/xml/ns/persistene"
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence ttp://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="main" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/Maindb</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
</properties>
</persistence-unit>
The web application has two functions; return a customer and a list of items.
The CustomerResource object injects the entity manager factory as follows:
#PersistenceUnit(unitName="main")
private EntityManagerFactory emf;
and queries the persistence layer by the following code;
EntityManager em = emf.createEntityManager();
Customer customer = (Customer) em.find(Customer.class, customerID);
This works with no problems (that I am aware of), I get the expected data returned.
The ItemResource object does the same thing against the same persistence unit.
#PersistenceUnit(unitName="main")
private EntityManagerFactory emf;
But the injection fails and emf is always null.
EntityManager em = emf.createEntityManager(); <- emf is null here
I am unsure of what I have done wrong here, my guess is that I am using the entity manager factory incorrectly.
Any help would be much appreciated! Thanks
Update
I was taking out the troublesome code to put in a war file for everyone to look at which helped me isolate the problem.
The issue seems to be with the url patterns I am using.
web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>Item</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Item</servlet-name>
<url-pattern>/Item/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Customer</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Customer</servlet-name>
<url-pattern>/Customer</url-pattern>
</servlet-mapping>
</web-app>
sun-jaxws.xml:
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
<endpoint name="Item" implementation="com.test.item.ItemResource" url-pattern="/Item/*" />
<endpoint name="Customer" implementation="com.test.customer.CustomerResource" url-pattern="/Customer" />
</endpoints>
The item resource right now has two web methods;
Get Item Details
Type: Get
Path: /
Web param: item id
Get Item List
Type: Get
Path: /list
Web param: Item Colour
With the wild cards in the url patterns the entity manager is always null. If I remove the wild cards then I can successfully request an item, put I cannot request a list of items because it is not mapped.
The customer resource requests are always successful because it does not contain any wild cards in the mappings.
Thanks
I am not sure this will answer the question (why is the EMF null in the second case?) but since you're using an application-managed entity manager, do you close the EntityManager properly? Something like this:
public class LoginServlet extends HttpServlet {
#PersistenceUnit(unitName="EmployeeService")
EntityManagerFactory emf;
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
String userId = request.getParameter("user");
// check valid user
EntityManager em = emf.createEntityManager();
try {
User user = em.find(User.class, userId);
if (user == null) {
// return error page
// ...
}
} finally {
em.close();
}
}
But, honestly, I really wonder why you aren't using a container-managed entity manager. It is much simpler to let the container manage its life cycle in my opinion. To get an EntityManager injected:
#PersistenceContext(unitName = "main")
private EntityManager em;
I'm using Spring 3, and trying to set up a simple web-app using annotations to define controller mappings. This seems to be incredibly difficult without peppering all the urls with *.form or *.do
Because part of the site needs to be password protected, these urls are all under /secure. There is a <security-constraint> in the web.xml protecting everything under that root. I want to map all the Spring controllers to /secure/app/.
Example URLs would be:
/secure/app/landingpage
/secure/app/edit/customer/{id}
each of which I would handle with an appropriate jsp/xml/whatever.
So, in web.xml I have this:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/secure/app/*</url-pattern>
</servlet-mapping>
And in despatcher-servlet.xml I have this:
<context:component-scan base-package="controller" />
In the Controller package I have a controller class:
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
#Controller
#RequestMapping("/secure/app/main")
public class HomePageController {
public HomePageController() { }
#RequestMapping(method = RequestMethod.GET)
public ModelAndView getPage(HttpServletRequest request)
{
ModelAndView mav = new ModelAndView();
mav.setViewName("main");
return mav;
}
}
Under /WEB-INF/jsp I have a "main.jsp", and a suitable view resolver set up to point to this. I had things working when mapping the despatcher using *.form, but can't get anything working using the above code.
When Spring starts up it appears to map everything correctly:
13:22:36,762 INFO main annotation.DefaultAnnotationHandlerMapping:399 - Mapped URL path [/secure/app/main] onto handler [controller.HomePageController#2a8ab08f]
I also noticed this line, which looked suspicious:
13:25:49,578 DEBUG main servlet.DispatcherServlet:443 - No HandlerMappings found in servlet 'dispatcher': using default
And at run time any attempt to view /secure/app/main just returns a 404 error in Tomcat, with this log output:
13:25:53,382 DEBUG http-8080-1 servlet.DispatcherServlet:842 - DispatcherServlet with name 'dispatcher' determining Last-Modified value for [/secure/app/main]
13:25:53,383 DEBUG http-8080-1 servlet.DispatcherServlet:850 - No handler found in getLastModified
13:25:53,390 DEBUG http-8080-1 servlet.DispatcherServlet:690 - DispatcherServlet with name 'dispatcher' processing GET request for [/secure/app/main]
13:25:53,393 WARN http-8080-1 servlet.PageNotFound:962 - No mapping found for HTTP request with URI [/secure/app/main] in DispatcherServlet with name 'dispatcher'
13:25:53,393 DEBUG http-8080-1 servlet.DispatcherServlet:677 - Successfully completed request
So... Spring maps a URL, and then "forgets" about that mapping a second later? What is going on?
Thanks.
I have exactly the same problem as you. The way to set 'alwaysUseFullPath' is pretty straightforward. My conf file is as following:
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"
p:order="3" > <!-- a higher value meaning greater in terms of sorting. -->
<property name="alwaysUseFullPath" value="true" />
<property name="interceptors">
<list>
<ref local="myInterceptor" />
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="alwaysUseFullPath" value="true" />
</bean>
Ah. As usual, found the answer after posting the question :-)
Changing the RequestMapping annotation to just /main fixes the problem. The documentation is not very clear on how all this is specified.
Put something like this in your #Configuration class:
#Bean(autowire = Autowire.BY_TYPE)
public AnnotationMethodHandlerAdapter handlerAdapter(){
final AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter = new AnnotationMethodHandlerAdapter();
annotationMethodHandlerAdapter.setAlwaysUseFullPath(true);
return annotationMethodHandlerAdapter;
}