Announcement Announcement Module
Collapse
No announcement yet.
HttpInvoker without web container? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #31
    Mark,

    I've never use jetty embedded in a standalone application. I'm using it as a server and packaging my applications as war files. A number of my apps. have no html output so in effect I'm using jetty as a service container, rather than a web application container, that just happens to expose its services of http. Works fine.

    As you say, it seems like you have to have different sets of classes. One to start the application with the embedded jetty. Then another that the jetty instance the uses. Sounds like it should be doable but I've never done it.

    What are you actually trying to achieve by embedding the servlet container in a standalone application?

    Jonny

    Comment


    • #32
      Originally posted by jwray View Post
      Mark,

      I've never use jetty embedded in a standalone application. I'm using it as a server and packaging my applications as war files. A number of my apps. have no html output so in effect I'm using jetty as a service container, rather than a web application container, that just happens to expose its services of http. Works fine.
      Jonny:

      Using jetty as a service container like you are doing is one of my objectives. The use case for this is I will have multiple rich clients accessing a networked database, and the service/dao layer will be used to expose the database to the client in the form of serialized java objects(hence the use of HttpInvoker)

      As you say, it seems like you have to have different sets of classes. One to start the application with the embedded jetty. Then another that the jetty instance the uses. Sounds like it should be doable but I've never done it.
      True, but the puzzling part to me is this; in the use case I described above, when jetty will act as a service container, and the interfaces, classes, dependencies, web.xml, jetty.xml and spring app context.xml are packaged in the war file, how are you actually starting the embedded jetty instance. The jetty server must be started before the DispatcherServlet may route any traffic through to your services/daos, so how are you accomplishing this? I would think you would have to have access to all three descriptors(jetty.xml, web.xml and spring app context.xml), which are contained in the war file, right? Do you explode the war contents and access the jetty.xml inside a java main class using something similar to:
      Code:
      FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(path/to/jetty.xml);
      What are you actually trying to achieve by embedding the servlet container in a standalone application?
      I was hoping to minimize the refactoring involved. Basically, I have a Swing Client app which needs access to either a database found on local host or a network server. Setting it up this way, if I want to access a datasource other than what I have locally, I should be able to simply change the value on the serviceUrl below from localhost to a network host and use the same codebase.

      Jonny

      Comment


      • #33
        Originally posted by karldmoore View Post
        OK, heres the working example I promised........ I would zip it up an attach it, but my computer isn't playing ball. The project in this example is called timeService.

        Sooooo
        Code:
        tomcat
            webapps
                timeService
                    applicationContext.xml
                    invoker-servlet.xml
                    web.xml
        
                    classes
                        com/test/TimeService.class
                        com/test/TimeServiceImpl.class
                    lib
                        spring.jar
                        commons-logging-1.0.4.jar
        The client will also require commons-codec.jar and commons-httpclient.jar on the classpath as well as the server prereqs.

        Client

        TimeServiceClient
        Code:
        package com.test;
        
        import org.springframework.context.ApplicationContext;
        import org.springframework.context.support.ClassPathXmlApplicationContext;
        
        public class TimeServiceClient
        {
        	public static void main ( String [] args )
        	{
        		ApplicationContext context = new ClassPathXmlApplicationContext ( "client-applicationContext.xml" );
        		TimeService timeService = ( TimeService ) context.getBean ( "timeService" );
        		System.out.println ( timeService.getDate () );
        		sleepPlease ();
        		System.out.println ( timeService.getDate () );
        	}
        	
        	private static void sleepPlease ()
        	{
        		try
        		{
        			Thread.sleep ( 5000 );
        		}
        		catch ( InterruptedException e )
        		{
        			// ignore
        		}
        	}
        }
        client-applicationContext.xml
        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        
        <beans xmlns="http://www.springframework.org/schema/beans"
        	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
             
            <bean id="httpInvokerRequestExecutor" class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"/>
        
            <bean id="timeService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
        		<property name="serviceUrl" value="http://localhost:8080/timeService/invoker/timeService"/>
        		<property name="serviceInterface" value="com.test.TimeService"/>
                <property name="httpInvokerRequestExecutor">
                    <ref bean="httpInvokerRequestExecutor"/>
                </property>
            </bean>
            
        </beans>
        Server

        TimeService
        Code:
        package com.test;
        
        import java.util.Date;
        
        public interface TimeService
        {
        	Date getDate ();
        }
        TimeServiceImpl
        Code:
        package com.test;
        
        import java.util.Date;
        
        public class TimeServiceImpl implements TimeService
        {
        	public Date getDate ()
        	{
        		return new Date ();
        	}
        }
        applicationContext.xml
        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        
        <beans xmlns="http://www.springframework.org/schema/beans"
        	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
               
               <bean id="timeService" class="com.test.TimeServiceImpl"/>
               
        </beans>
        invoker-servlet.xml
        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        
        <beans xmlns="http://www.springframework.org/schema/beans"
        	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
               
        	<bean name="/timeService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
                <property name="service">
                    <ref bean="timeService"/>
                </property>
                <property name="serviceInterface">
                    <value>com.test.TimeService</value>
                </property>
            </bean>
            
        </beans>
        web.xml
        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE web-app PUBLIC
        	"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        	"http://java.sun.com/dtd/web-app_2_3.dtd">
        
        <web-app>
        	<display-name>Time Service</display-name>
        	<description>Time Service</description>
        
        	<listener>
        		<listener-class>
        			org.springframework.web.context.ContextLoaderListener
        		</listener-class>
        	</listener>
        
        	<servlet>
        		<servlet-name>invoker</servlet-name>
        		<servlet-class>
        			org.springframework.web.servlet.DispatcherServlet
        		</servlet-class>
        		<load-on-startup>1</load-on-startup>
        	</servlet>
        
        	<servlet-mapping>
        		<servlet-name>invoker</servlet-name>
        		<url-pattern>/invoker/*</url-pattern>
        	</servlet-mapping>
        
        </web-app>
        So, it looks like your client class and the service interface and impl classes are in the same package . . . could you zip up your example so I could take a look? My situation is that my client class and service interface/impl classes are in different packages. So, my client class is going to need to add the dependency(import), however that may be difficult the way I have my project structured, because currently the client code is in the main project and the service/dao code is in a subproject, which is not formatted like a web app. It should be doable, though, if I mimic the web app dir structure.

        Comment


        • #34
          Mark,

          I'm still not sure what you are trying to achieve with using an embedded jetty instance over a regular one. I've never used an embedded jetty instance, I just start jetty as a regular servlet container and deploy my applications as war files (although you can, as we discovered earlier, use an exploded dir structure). It just happens that some of my applications don't produce html. They expose services instead (although I have one that does both).

          I have exactly what you want. Multiple rich clients accessing networked datasources (eg database, web services, etc.) via a service layer exposed via HttpInvoker. If i want to change servers I just change the serviceURL. So I still don't see what the embedded instance gains you, and it's causing you a lot of problems. Can't you just use a jetty as a standalone server and deploy your services as normal then access those services from the client?

          Jonny


          Originally posted by mark_in_gr View Post
          Jonny:

          Using jetty as a service container like you are doing is one of my objectives. The use case for this is I will have multiple rich clients accessing a networked database, and the service/dao layer will be used to expose the database to the client in the form of serialized java objects(hence the use of HttpInvoker)


          True, but the puzzling part to me is this; in the use case I described above, when jetty will act as a service container, and the interfaces, classes, dependencies, web.xml, jetty.xml and spring app context.xml are packaged in the war file, how are you actually starting the embedded jetty instance. The jetty server must be started before the DispatcherServlet may route any traffic through to your services/daos, so how are you accomplishing this? I would think you would have to have access to all three descriptors(jetty.xml, web.xml and spring app context.xml), which are contained in the war file, right? Do you explode the war contents and access the jetty.xml inside a java main class using something similar to:
          Code:
          FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(path/to/jetty.xml);

          I was hoping to minimize the refactoring involved. Basically, I have a Swing Client app which needs access to either a database found on local host or a network server. Setting it up this way, if I want to access a datasource other than what I have locally, I should be able to simply change the value on the serviceUrl below from localhost to a network host and use the same codebase.

          Jonny

          Comment


          • #35
            Mark,

            I'm still not sure what you are trying to achieve with using an embedded jetty instance over a regular one. I've never used an embedded jetty instance, I just start jetty as a regular servlet container and deploy my applications as war files (although you can, as we discovered earlier, use an exploded dir structure). It just happens that some of my applications don't produce html. They expose services instead (although I have one that does both).

            I have exactly what you want. Multiple rich clients accessing networked datasources (eg database, web services, etc.) via a service layer exposed via HttpInvoker. If i want to change servers I just change the serviceURL. So I still don't see what the embedded instance gains you, and it's causing you a lot of problems. Can't you just use a jetty as a standalone server and deploy your services as normal then access those services from the client?

            Jonny
            The reason for embedding jetty into the app versus starting it manually is ease of maintenance, for one. I don't want to add the complexity of a customer having to stop, start and manage a web/app server. Embedding Jetty allows my application, not a sys admin, to control the servlet container.

            Check out this link if you haven't seen it:
            http://jroller.com/page/sjivan?entry...ty_in_a_spring

            Also, this link at the jetty sight gives more examples of embedding jetty:
            http://docs.codehaus.org/display/JETTY/Embedding+Jetty

            Comment


            • #36
              Mark,

              I think I see what you are trying to do. You basically want a rich client that can access both a local and a remote service the same way by changing the service URL. But, if the local one is used you want the local service container (ie jetty) to be started by the application itself.

              I think the key is thinking about the web application and client application as separate, just as if they were in different jvms. Any classes they need to share (if my case thats service interfaces and DTOs) will need to be in both the client classpath and the web application classpath (WEB-INF/lib). Maybe package the shared code as a separate project into its own jar and then package that as needed?

              Jonny

              Comment


              • #37
                Originally posted by jwray View Post
                Mark,

                I think I see what you are trying to do. You basically want a rich client that can access both a local and a remote service the same way by changing the service URL. But, if the local one is used you want the local service container (ie jetty) to be started by the application itself.

                I think the key is thinking about the web application and client application as separate, just as if they were in different jvms. Any classes they need to share (if my case thats service interfaces and DTOs) will need to be in both the client classpath and the web application classpath (WEB-INF/lib). Maybe package the shared code as a separate project into its own jar and then package that as needed?

                Jonny
                Jonny:

                Great minds think alike!!! That is pretty much what I want to do. I have now structured my project so that the Service Layer and DAO interfaces and impl classes are in a subproject which produces a .jar file, which may be used by the main project(which accesses remote beans by way of HttpInvokerProxyFactoryBean) and the web-app(which contains the contains the subprojects artifact/.jar file in this case).

                Ideally, it would be nice to have a uniform way of starting the embedded Jetty instance, whether it is running locally or on a remote server. There seem to be a few ways to do this, both programatically and declaratively. However, I need to figure out the most practical way to accomplish this.

                For example, if I use the declarative approach, feeding jetty.xml into a Spring ApplicationContext(similar to Sanjiv's example on his blog), I would think I need to explode the web app's war file and use something like Sanjiv is using, i.e.
                Code:
                FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(path/to/jetty.xml);
                to 1) start the Jetty Server and 2) load the web-app

                Here is Sanjiv's jetty.xml file:
                Code:
                <?xml version="1.0" encoding="UTF-8"?>
                <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
                
                <beans>
                    <bean id="Server"
                          class="org.mortbay.jetty.Server" init-method="start" destroy-method="stop">
                        <property name="connectors">
                            <list>
                                <bean id="Connector" class="org.mortbay.jetty.nio.SelectChannelConnector">
                                    <property name="port" value="8181"/>
                                </bean>
                            </list>
                        </property>
                
                        <property name="handler">
                            <bean id="handlers"
                                  class="org.mortbay.jetty.handler.HandlerCollection">
                                <property name="handlers">
                                    <list>
                                        <bean id="contexts"
                                              class="org.mortbay.jetty.handler.ContextHandlerCollection">
                                            <property name="handlers">
                                                <list>
                                                    <bean class="org.mortbay.jetty.webapp.WebAppContext">
                                                        <property name="contextPath" value="/"/>
                                                        <property name="war" value="../conf/web">
                                                        </property>
                                                    </bean>
                                                </list>
                                            </property>
                                        </bean>
                                    </list>
                                </property>
                            </bean>
                        </property>
                    </bean>
                </beans>
                The part I don't quite understand about this is the contextPath and war property settings under WebAppContext. On the Jetty sight, the examples conform more to how you are loading your web-apps.

                The web.xml file is responsible for loading the web-apps Spring App Context file, which must be in the class path.

                That is pretty much it. I will let you know what happens.

                Comment


                • #38
                  Looks like I have it working. At least the app appears to be loading.

                  Comment


                  • #39
                    I seem to now have an issue with deploying a WAR file using org.mortbay.jetty.webapp.WebAppContext. I have tried the war and resourceBase properties, specifying the directory where the WAR file resides, but the context is not recognizing the file.

                    It works, however, when I move an exploded WAR file's contents into the same directory named on the resourceBase property value.

                    Is there a special way to treat this w/Jetty using the XBean configuration?

                    Comment


                    • #40
                      Mark,

                      I have a jetty6 instance working using the WebAppContext and a war file. I uses the constructor arguements, not properties. My config entry file:

                      Code:
                       <New id="ServicesContext" class="org.mortbay.jetty.webapp.WebAppContext">
                            <Arg><Ref id="contexts"/></Arg>
                           <Arg>path to war file or exploded dir</Arg>
                            <Arg>/services</Arg>
                      	  <Set name="ConfigurationClasses"><Ref id="plusConfig"/></Set>
                            <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>
                            <Get name="SessionHandler">
                              <Set name="SessionManager">
                                <New class="org.mortbay.jetty.servlet.HashSessionManager">
                                  <Set name="maxInactiveInterval">600</Set>
                                </New>
                              </Set>
                            </Get>
                          </New>
                      Jonny

                      Originally posted by mark_in_gr View Post
                      I seem to now have an issue with deploying a WAR file using org.mortbay.jetty.webapp.WebAppContext. I have tried the war and resourceBase properties, specifying the directory where the WAR file resides, but the context is not recognizing the file.

                      It works, however, when I move an exploded WAR file's contents into the same directory named on the resourceBase property value.

                      Is there a special way to treat this w/Jetty using the XBean configuration?

                      Comment


                      • #41
                        I just got it working today in fact. Here is my jetty xml context/web app context portions:

                        Code:
                        <bean id="contexts"
                                                      class="org.mortbay.jetty.handler.ContextHandlerCollection">
                                                    <property name="handlers">
                                                        <list>
                                                            <bean class="org.mortbay.jetty.webapp.WebAppContext">
                                                                <property name="contextPath"value="/"/>                                        
                                                                    <property name="war" value="/webapps/app.war"/>
                                                            </bean>
                        I am having another problem now related to Serialization using HttpInvoker. I have an object which itself contains a set of other objects. These other objects have primitives, along w/other objects, as attributes. When attempt to serialize the entire class, I get "StreamCorruptedException Invalid Type Code:40" errors. The class in question has two primitive attributes, one an array of doubles, the other an array of ints. If I make both of these attributes transient, it works w/o the expection.

                        I was under the impression that primitives were automatically serialized, so I am not sure why this is occurring. Any ideas?

                        Comment


                        • #42
                          Originally posted by karldmoore View Post
                          OK, heres the working example I promised........ I would zip it up an attach it, but my computer isn't playing ball. The project in this example is called timeService.

                          Sooooo
                          Code:
                          tomcat
                              webapps
                                  timeService
                                      applicationContext.xml
                                      invoker-servlet.xml
                                      web.xml
                          
                                      classes
                                          com/test/TimeService.class
                                          com/test/TimeServiceImpl.class
                                      lib
                                          spring.jar
                                          commons-logging-1.0.4.jar
                          The client will also require commons-codec.jar and commons-httpclient.jar on the classpath as well as the server prereqs.

                          Client

                          TimeServiceClient
                          Code:
                          package com.test;
                          
                          import org.springframework.context.ApplicationContext;
                          import org.springframework.context.support.ClassPathXmlApplicationContext;
                          
                          public class TimeServiceClient
                          {
                          	public static void main ( String [] args )
                          	{
                          		ApplicationContext context = new ClassPathXmlApplicationContext ( "client-applicationContext.xml" );
                          		TimeService timeService = ( TimeService ) context.getBean ( "timeService" );
                          		System.out.println ( timeService.getDate () );
                          		sleepPlease ();
                          		System.out.println ( timeService.getDate () );
                          	}
                          	
                          	private static void sleepPlease ()
                          	{
                          		try
                          		{
                          			Thread.sleep ( 5000 );
                          		}
                          		catch ( InterruptedException e )
                          		{
                          			// ignore
                          		}
                          	}
                          }
                          client-applicationContext.xml
                          Code:
                          <?xml version="1.0" encoding="UTF-8"?>
                          
                          <beans xmlns="http://www.springframework.org/schema/beans"
                          	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                          	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
                               
                              <bean id="httpInvokerRequestExecutor" class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"/>
                          
                              <bean id="timeService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
                          		<property name="serviceUrl" value="http://localhost:8080/timeService/invoker/timeService"/>
                          		<property name="serviceInterface" value="com.test.TimeService"/>
                                  <property name="httpInvokerRequestExecutor">
                                      <ref bean="httpInvokerRequestExecutor"/>
                                  </property>
                              </bean>
                              
                          </beans>
                          Server

                          TimeService
                          Code:
                          package com.test;
                          
                          import java.util.Date;
                          
                          public interface TimeService
                          {
                          	Date getDate ();
                          }
                          TimeServiceImpl
                          Code:
                          package com.test;
                          
                          import java.util.Date;
                          
                          public class TimeServiceImpl implements TimeService
                          {
                          	public Date getDate ()
                          	{
                          		return new Date ();
                          	}
                          }
                          applicationContext.xml
                          Code:
                          <?xml version="1.0" encoding="UTF-8"?>
                          
                          <beans xmlns="http://www.springframework.org/schema/beans"
                          	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                          	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
                                 
                                 <bean id="timeService" class="com.test.TimeServiceImpl"/>
                                 
                          </beans>
                          invoker-servlet.xml
                          Code:
                          <?xml version="1.0" encoding="UTF-8"?>
                          
                          <beans xmlns="http://www.springframework.org/schema/beans"
                          	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                          	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
                                 
                          	<bean name="/timeService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
                                  <property name="service">
                                      <ref bean="timeService"/>
                                  </property>
                                  <property name="serviceInterface">
                                      <value>com.test.TimeService</value>
                                  </property>
                              </bean>
                              
                          </beans>
                          web.xml
                          Code:
                          <?xml version="1.0" encoding="UTF-8"?>
                          <!DOCTYPE web-app PUBLIC
                          	"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
                          	"http://java.sun.com/dtd/web-app_2_3.dtd">
                          
                          <web-app>
                          	<display-name>Time Service</display-name>
                          	<description>Time Service</description>
                          
                          	<listener>
                          		<listener-class>
                          			org.springframework.web.context.ContextLoaderListener
                          		</listener-class>
                          	</listener>
                          
                          	<servlet>
                          		<servlet-name>invoker</servlet-name>
                          		<servlet-class>
                          			org.springframework.web.servlet.DispatcherServlet
                          		</servlet-class>
                          		<load-on-startup>1</load-on-startup>
                          	</servlet>
                          
                          	<servlet-mapping>
                          		<servlet-name>invoker</servlet-name>
                          		<url-pattern>/invoker/*</url-pattern>
                          	</servlet-mapping>
                          
                          </web-app>
                          Ok, here is my latest dilemna . . .

                          How to get your own class/interface objects to be used as arguments to the method exposed by HttpInvokerProxyFactoryBean.

                          It seems that if I pass a java.lang.Object to a method, it works. However, if I pass one of my own interfaces, I get a java.lang.reflect.InvocationTargetException.

                          Please see this post for more information:
                          http://forum.springframework.org/showthread.php?t=34218

                          This is a tough one. I have been stumped all day on it, and can't find ANYTHING close on the forums. The only thing I have seem is certain posts stating that HttpInvoker uses pass by value rather then pass by reference. Would this be a problem?

                          Comment


                          • #43
                            Originally posted by mark_in_gr View Post
                            I just got it working today in fact. Here is my jetty xml context/web app context portions:

                            Code:
                            <bean id="contexts"
                                                          class="org.mortbay.jetty.handler.ContextHandlerCollection">
                                                        <property name="handlers">
                                                            <list>
                                                                <bean class="org.mortbay.jetty.webapp.WebAppContext">
                                                                    <property name="contextPath"value="/"/>                                        
                                                                        <property name="war" value="/webapps/app.war"/>
                                                                </bean>
                            I am having another problem now related to Serialization using HttpInvoker. I have an object which itself contains a set of other objects. These other objects have primitives, along w/other objects, as attributes. When attempt to serialize the entire class, I get "StreamCorruptedException Invalid Type Code:40" errors. The class in question has two primitive attributes, one an array of doubles, the other an array of ints. If I make both of these attributes transient, it works w/o the expection.

                            I was under the impression that primitives were automatically serialized, so I am not sure why this is occurring. Any ideas?
                            This error seems to be fixed in the latest 2.0.3 build(I got the one from 1/29/07)

                            Comment

                            Working...
                            X