0

ZK on embedded Jetty under Spring

asked 2011-07-12 06:57:49 +0800

ptomli gravatar image ptomli
18

I'm having some trouble getting zkspring-core to work with a ZK application running under embedded Jetty under Spring.


The general layout of the application is that my main() method creates an ApplicationContext, the config of which defines a Jetty server. That server is needing to run the ZK application.

public static void main(String[] args) throws Exception {
	applicationContext = new ClassPathXmlApplicationContext(new String[] {
		// config for services and stuff
		"/META-INF/spring/applicationContext.xml",

		// config for Jetty for the ZK application
		"/META-INF/spring/applicationContext-jettyZk.xml"
	});
	applicationContext.registerShutdownHook();
}

File: applicationContext-jettyZk.xml

<bean id="jettyZk" class="org.eclipse.jetty.server.Server" init-method="start" destroy-method="stop">
	<property name="gracefulShutdown" value="1000"/>

	<property name="threadPool">
		<bean class="org.eclipse.jetty.util.thread.QueuedThreadPool">
			<property name="minThreads" value="1" />
			<property name="maxThreads" value="10" />
		</bean>
	</property>

	<property name="connectors">
		<list>
			<bean class="org.eclipse.jetty.server.nio.SelectChannelConnector">
				<property name="host" value="localhost" />
				<property name="port" value="8443" />
			</bean>
		</list>
	</property>

	<property name="handler">
		<bean class="org.eclipse.jetty.servlet.ServletContextHandler">
			<property name="eventListeners">
				<list>
					<bean class="org.zkoss.spring.web.context.CoreContextListener"/>
					<bean class="com.company.project.util.spring.ContextLoaderListener">
						<property name="contextConfigLocation">
							<value>
								classpath:/META-INF/spring/applicationContext-zk.xml
							</value>
						</property>
					</bean>
					<!-- not sure if this is needed, disabled for now -->
					<!-- <bean class="org.springframework.web.context.request.RequestContextListener"/> -->
					<bean class="org.zkoss.zk.ui.http.HttpSessionListener"/>
				</list>
			</property>
			<property name="servletHandler">
				<bean class="org.eclipse.jetty.servlet.ServletHandler">
					<property name="servlets">
						<list>
							<bean class="org.eclipse.jetty.servlet.ServletHolder">
								<property name="name" value="default"/>
								<property name="servlet">
									<bean class="com.company.project.util.jetty.ClasspathResourceServlet"/>
								</property>
								<property name="initParameters">
									<map>
										<entry key="resourceBase" value="/com/company/project/frontend/zk"/>
										<entry key="gzip" value="0"/>
									</map>
								</property>
								<property name="initOrder" value="1"/>
							</bean>
							<bean class="org.eclipse.jetty.servlet.ServletHolder">
								<property name="name" value="zkLoader"/>
								<property name="servlet">
									<bean class="org.zkoss.zk.ui.http.DHtmlLayoutServlet"/>
								</property>
								<property name="initParameters">
									<map>
										<entry key="update-uri" value="/zkau"/>
									</map>
								</property>
								<property name="initOrder" value="10"/>
							</bean>
							<bean class="org.eclipse.jetty.servlet.ServletHolder">
								<property name="name" value="auEngine"/>
								<property name="servlet">
									<bean class="org.zkoss.zk.au.http.DHtmlUpdateServlet"/>
								</property>
								<property name="initOrder" value="11"/>
							</bean>	
						</list>
					</property>
					<property name="servletMappings">
						<list>
							<bean class="org.eclipse.jetty.servlet.ServletMapping">
								<property name="servletName" value="zkLoader"/>
								<property name="pathSpecs">
									<list>
										<value>*.zul</value>
										<value>*.zhtml</value>
									</list>
								</property>
							</bean>
							<bean class="org.eclipse.jetty.servlet.ServletMapping">
								<property name="servletName" value="auEngine"/>
								<property name="pathSpec" value="/zkau/*"/>
							</bean>
							<bean class="org.eclipse.jetty.servlet.ServletMapping">
								<property name="servletName" value="default"/>
								<property name="pathSpec" value="/"/>
							</bean>
						</list>
					</property>
				</bean>
			</property>
			<property name="sessionHandler">
				<bean class="org.eclipse.jetty.server.session.SessionHandler"/>
			</property>
		</bean>
	</property>
</bean>

The ClasspathResourceServlet is merely there to allow Jetty to load resources from the classpath.


The ContextLoaderListener is documented as

 * An ApplicationContextAware ContextLoaderListener that allows for using the current ApplicationContext,
 * as determined by ApplicationContextAware, as the parent for the Root WebApplicationContext.
 * 
 * Also provides for specifying the contextConfigLocation of the Root WebApplicationContext, because
 * Eclipse Jetty 7 ServletContextHandler does not expose a setInitParameters method.
 * 

I've also had to configure a UiFactory, again to allow ZK to load page definitions from the classpath. I suspect there's a better way to do this though.

Now, I've added zkspring-core and tried to go through the documentation from http://books.zkoss.org/wiki/ZK+Spring+Essentials/Working+with+ZK+Spring/Working+with+ZK+Spring+Core

However, Spring throws a NoSuchBeanDefinitionException when trying to inject a Label from the ZUL.

@Component("dashboardComposer")
@Scope("desktop")
public class DashboardComposer extends GenericSpringComposer {
	private static final long serialVersionUID = 1L;

	@Inject
	private Label helloWorldLabel;

	@EventHandler("btn.onClick")
	public void doIt() {
		helloWorldLabel.setValue("Done!");
	}
}

I noticed that there's a metainfo/zk/config.xml included in the zkspring-core jar, which, indirectly, sets up a ZkSpringUiFactory, so I tried to mimic what it's doing in my ZUL manually, until I figure out a better way of getting ZULs loaded from the classpath. See below that I've added the zkBindingComposer to the apply attribute. I see, in the logs, that Spring happily finds the zkBindingComposer.

<?xml version="1.0" encoding="utf-8"?>
<!-- <?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?> -->
<?variable-resolver class="org.zkoss.spring.DelegatingVariableResolver"?>
<window title="Dashboard" border="normal"
		apply="${zkBindingComposer},${dashboardComposer}"
		xmlns="http://www.zkoss.org/2005/zul"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd">

	<label id="helloWorldLabel" value="Hello World!"/>
	<button id="btn" label="Do it!"/>
</window>

So, I guess my query is multifold.

Is there a better way than providing a custom UiFactory to allow ZK to load ZUL files from the classpath?
Is my custom UiFactory stopping zkspring-core from working? I have tried extending ZkSpringUiFactory for my custom version but that didn't seem to help any.

Thanks in advance

Paul

delete flag offensive retag edit
Be the first one to reply this discussion!
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2011-07-12 06:57:49 +0800

Seen: 433 times

Last updated: Jul 12 '11

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More