亮's profile蚯蚓PhotosBlogListsMore Tools Help

蚯蚓

理想,现实,自由,人性,思想,分享,和谐,美丽
September 19

契约式开发webservice实践之spring-ws+Xmlbeans

契约式开发webservice实践之spring-ws+Xmlbeans
1、开发环境
JDK1.4.2.*
Tomcat6.0.*
Spring-2.5.5
Spring-ws-1.5.4
XmlBeans-2.3


2、确定需要请求和应答的xml实例
Request.xml

<?xml version="1.0" encoding="UTF-8"?>
<wl_request  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://footmarktech.com/samples">
<flights>
 <flight><segment>PEK-CAN<segment><ticketNo>7841234656</ticketNo></flight>
 <flight><segment>PEK-CAN<segment><ticketNo>7841234656</ticketNo></flight>
</flights>
</wl_request>

Response.xml

<?xml version="1.0" encoding="UTF-8"?>
<wl_response  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://footmarktech.com/samples">
<flights>
 <flight><segment>PEK-CAN<segment><ticketNo>7841234656</ticketNo></flight>
 <flight><segment>PEK-CAN<segment><ticketNo>7841234656</ticketNo></flight>
</flights>
</wl_response>

3、设置XmlBeans环境
设置XMLBEANS_HOME
并将 %XMLBEANS_HOME%/bin增加到path路径中

4、使用xmlbeans tool准备数据契约xsd
根据上一步骤请求和应答的实例xml执行如下命令
inst2xsd -enumerations never Request.xml Response.xml
将生成的schema0.xsd文件命名为 Airline.xsd

将 Airline.xsd放在 ${web-context}/WEB-INF目录下
5、使用xmlbeans tool生成OXM数据映射对象
需要说明的是这些对象是跟Xmlbeans耦合比较紧的,不是POJO
执行如下命令
scomp -out Airline.jar Airline.xsd

6、准备运行时和编译时jar包


 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/acegi-security-1.0.7.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/activation-1.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/antlr-2.7.7.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/aopalliance-1.0.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/axiom-api-1.2.6.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/axiom-dom-1.2.6.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/axiom-impl-1.2.6.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/backport-util-concurrent-3.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/bsf-2.3.0.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/cglib-nodep-2.1_3.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-beanutils-1.7.0.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-codec-1.3.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-collections-3.2.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-configuration-1.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-digester-1.8.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-discovery-0.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-el-1.0.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-fileupload-1.2.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-httpclient-3.0.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-io-1.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-lang-2.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-logging-1.1.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-net-1.2.2.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-pool-1.3.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/commons-validator-1.3.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/concurrent-1.3.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/dom4j-1.6.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/ehcache-1.2.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/ezmorph-1.0.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/groovy-all-1.5.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/hibernate-3.2.6.ga.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/hsqldb-1.8.0.7.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/icu4j-3.4.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/jasypt-1.4.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/javassist-3.6.ga.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/jaxen-1.1.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/jaxrpc-1.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/jcaptcha-all-1.0-RC6.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/jcr-1.0.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/jdom-1.0.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/json-lib-2.2.1-jdk13.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/jta-spec1_0_1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/log4j-1.2.15.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/lucene-core-2.2.0.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/mail-1.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/mysql-connector-java-5.1.5-bin.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/ognl-2.7.2.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/oro-2.0.8.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/oscache-2.4.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/pdfbox-0.6.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/poi-3.0.1-FINAL-20070705.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/poi-contrib-3.0.1-FINAL-20070705.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/poi-scratchpad-3.0.1-FINAL-20070705.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/proxool-0.9.0RC3.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/serializer-2.7.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/slf4j-api-1.4.3.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/slf4j-log4j12-1.4.3.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/spring-2.5.5.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/stax-api-1.0.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/wsdl4j-1.6.2.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/wstx-asl-3.2.3.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xalan-2.7.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xercesImpl-2.8.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xfire-all-1.2.6.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xml-apis-1.3.04.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xom-1.1.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xpp3_min-1.1.3.4.0.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xstream-1.2.2.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/axis-saaj-1.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/axis-1.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/spring-oxm-1.5.4.jar" sourcepath="D:/maven-1.0.2/.maven/repository/springframework/srcs/spring-ws-1.5.4-with-dependencies.zip"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/spring-webmvc-2.5.5.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/spring-ws-core-1.5.4.jar" sourcepath="D:/maven-1.0.2/.maven/repository/springframework/srcs/spring-ws-1.5.4-with-dependencies.zip"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/spring-ws-security-1.5.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/spring-ws-support-1.5.4.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/spring-xml-1.5.4.jar" sourcepath="D:/maven-1.0.2/.maven/repository/springframework/srcs/spring-ws-1.5.4-with-dependencies.zip"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/jsr173_1.0_api.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/resolver.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xbean_xpath.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xbean.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xmlbeans-qname.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/xmlpublic.jar"/>
 <classpathentry kind="lib" path="web/src/context/WEB-INF/lib/Airline.jar"/>
 <classpathentry kind="output" path="web/src/context/WEB-INF/classes"/>


Spring-ws1.5.4必须使用springframework2.5版本以上
其对org.springframework.core.io.Resource版本要求较高
必须加入spring-webmvc-2.5.5.jar
org.springframework.web.servlet.FrameworkServlet从2.5版本后被分到spring-webmvc.jar包,并不包含于主spring包内

注,可能有些jar包没有用到
7、书写web.xml

<?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>Web</display-name>
 
 
 
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
 
 
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <servlet>
        <servlet-name>ws-spring-ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
   </servlet>
  
  <servlet-mapping>
        <servlet-name>ws-spring-ws</servlet-name>
        <url-pattern>/spring-ws/*</url-pattern>
    </servlet-mapping>  
 

</web-app>

8、书写业务实现

package demo1;

public class Order {
 private String id;

 public String getId() {
  return id;
 }

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

package demo1;

public interface OrderService {
 Order getOrder(String id);
}

 

package demo1;

public class OrderServiceImpl implements OrderService{
 public Order getOrder(String id) {
  Order order = new Order();
  order.setId(id);
  return order;
 }
 
 
}

书写spring配置放在classpath下
applicationContext.xml

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

<!DOCTYPE beans PUBLIC
    "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">

<beans default-autowire="no" default-lazy-init="false" default-dependency-check="none">
  <bean id="orderService" class="demo1.OrderServiceImpl"/>
</beans>

9、书写Spring-ws EndPoint

package demo1;

import org.springframework.oxm.Marshaller;
import org.springframework.ws.server.endpoint.AbstractMarshallingPayloadEndpoint;

import com.footmarktech.samples.WlRequestDocument;
import com.footmarktech.samples.WlResponseDocument;

public class SampleMarshallingEndpoint extends
  AbstractMarshallingPayloadEndpoint {

 private final OrderService orderService;

 public SampleMarshallingEndpoint(OrderService orderService,
   Marshaller marshaller) {
  super(marshaller);
  this.orderService = orderService;
 }

 protected Object invokeInternal(Object request) throws Exception {
  com.footmarktech.samples.WlRequestDocument ab = null;
  ab = (WlRequestDocument)request;
 
  //TODO invoke orderService
 
  WlResponseDocument rs = (WlResponseDocument) WlResponseDocument.Factory.newInstance();
  rs.addNewWlResponse().addNewFlights().addNewFlight().setTicketNo(ab.getWlRequest().getFlights().getFlightArray(0).getTicketNo());
  return rs;
 }
}


10、书写ws-spring-ws-servlet.xml
放置于${web-context}/WEB-INF目录下


<?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="messageFactory" class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
 <property name="payloadCaching" value="true"/>
</bean>

<bean id="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />

<bean id="orderEndPoint" class="demo1.SampleMarshallingEndpoint">
        <constructor-arg><ref bean="orderService"/></constructor-arg>
        <constructor-arg><ref bean="xmlBeansMarshaller"/></constructor-arg>
</bean>

<bean id="payloadMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
        <property name="defaultEndpoint" ref="orderEndPoint"/>
</bean>

 
   
<bean id="echo" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
   <property name="schema">
     <bean class="org.springframework.xml.xsd.SimpleXsdSchema">
       <property name="xsd" value="/WEB-INF/Airline.xsd"/>
     </bean>
   </property>
   <property name="portTypeName" value="Echo"/>
   <property name="locationUri" value="http://localhost:8080/ss1/spring-ws/echo/services"/>
 </bean>

</beans>

11、开发客户端

配置applicationContext1.xml放置于 classpath demo1.client包内

 


<?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="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />

<bean id="messageFactory" class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
 <property name="payloadCaching" value="true"/>
</bean>   
   
<bean id="webServiceTemplate1" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory" />
<property name="marshaller" ref="xmlBeansMarshaller" />
<property name="unmarshaller" ref="xmlBeansMarshaller" />
<property name="messageSender">
 <bean class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
  <property name="readTimeout" value="0" />
 </bean>
</property>
<property name="defaultUri" value="http://localhost:8080/ss1/spring-ws/echo/services" />
</bean>
   
   

</beans>

 

 

package demo1.client;

import java.io.File;
import java.io.IOException;

import javax.xml.transform.Source;

import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.jdom.JDOMException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.xml.transform.ResourceSource;
import org.springframework.xml.transform.StringResult;

import com.csair.smscenter.webservice.SendSMDocument;
import com.csair.smscenter.webservice.SendSMResponseDocument;
import com.footmarktech.samples.WlRequestDocument;
import com.footmarktech.samples.WlResponseDocument;

public class EchoClient {
 public static void RequestSpring() {
  ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext1.xml", EchoClient.class);
  WebServiceTemplate webServiceTemplate = (WebServiceTemplate) applicationContext
    .getBean("webServiceTemplate1");
  WlRequestDocument request = WlRequestDocument.Factory.newInstance();
  request.addNewWlRequest().addNewFlights().addNewFlight().setTicketNo(new Long(1231235555).longValue());
 
  WlResponseDocument response = (WlResponseDocument)webServiceTemplate.marshalSendAndReceive(request);
  System.out.println(response.getWlResponse().getFlights().getFlightArray(0).getTicketNo());
 }

 public static void main(String[] args) throws IOException, JDOMException {
  RequestSpring();

 }

}

12、参考资料
http://xmlbeans.apache.org/
http://static.springframework.org/spring-ws/sites/1.5/reference/html/index.html

http://mdasgin.blogspot.com/2008/06/web-servisleri-bir-makinede-sunulan.html

 

September 17

xmlbeans根据xml实例生成schema并创建oxm映射对象

inst2xsd -enumerations never test.xml
scomp -out test.jar schema0.xsd
March 26

终于实现了Tapestry4 EntityForm和QueryTable的组件化

取代以前的BaseEditPage 和 BaseListingPage 两个基础抽象类,所有的Page统一继承自 BasePage(自定义的继承自org.apache.tapestry.html.BasePage)
实现BasePage的单一化
 
QueryTable的实现思路
传入Query和Parameters 取代掉source参数,用Query和Parameters构建一个model提供给TableView
 
看下demo 类
EmployeeList.java
package app.demo.web.pages;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.event.PageBeginRenderListener;
import org.apache.tapestry.event.PageEvent;
import common.tapestry.components.table.QueryTable;
import common.tapestry.html.BasePage;
public abstract class EmployeeList extends BasePage implements
  PageBeginRenderListener {
 
 public abstract String getName();
 public void pageBeginRender(PageEvent event) {
 }
 QueryTable getTable_1() {
  return (QueryTable) getComponent("table1");
 }
 public void doSubmit() {
  Map map = new HashMap();
  map.put("A", "1");
  
  String hql = "select a from Employee a where 1=:A";
  if(StringUtils.isNotBlank(getName())){
   hql = hql +" and a.Name like :name";
   map.put("name", "%" + getName() +"%");
  }
  getTable_1().setQueryAndParameters(hql, map);
 }
 public void activateExternalPage(Object[] obj,IRequestCycle cycle){
  super.activateExternalPage(obj, cycle);
  getTable_1().setQueryAction(false);
 }
}
html模板
<t3
jwcid="table1@ext:QueryTable"
title="ognl:components.border.title"
columns="a_Name:名字:Name,a_Age:年龄:Age,a_Remark:备注:Remark,a_Birthday:生日:Birthday,!Operate:操作:operate" class="data_window"
cellSpacing="1" cellPadding="3" border="0" pageSize="10">
<t3 jwcid="OperateColumnValue@Block">
<a jwcid="@ExternalLink" page="EmployeeEdit" parameters="ognl:{components.table1.row.Id}" > 查 看</a>
<a jwcid="delete@ext:EntityDeleteLink" entity="ognl:components.table1.row">删除</a>
</t3>
</t3>
 
 
March 24

Extension Tapestry4`s restart service to clear my login cookies

接上篇,自定义一个logout service 把我的login cookies 清楚掉

Tapestry .java

package common.tapestry;

public final  class Tapestry {
  public static final String LOGOUT_SERVICE = "logout";
}

LogoutService.java
package common.tapestry.engine;

import java.io.IOException;

import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.engine.RestartService;

import common.tapestry.Tapestry;

public class LogoutService extends RestartService {
 private LoginCookiesManager loginCookiesManager;


 public void setLoginCookiesManager(
   LoginCookiesManager loginCookiesManager) {
  this.loginCookiesManager = loginCookiesManager;
 }

 public void service(IRequestCycle cycle) throws IOException {
  loginCookiesManager.removeCookies();
  super.service(cycle);
 }

 public String getName() {
  return Tapestry.LOGOUT_SERVICE;
 }
}

hivemodule.xml
<?xml version="1.0"?>
<module id="common.tapestry" version="1.0.0">

 <!-- extends tapestry RestartService and clear the login cookies info-->
    <service-point id="LogoutService" interface="org.apache.tapestry.engine.IEngineService">
        <invoke-factory>
            <construct class="common.tapestry.engine.LogoutService">
             <set-service property="request" service-id="tapestry.globals.HttpServletRequest" />
                <set-service property="response" service-id="tapestry.globals.HttpServletResponse" />
                <set-object property="servletPath" value="app-property:org.apache.tapestry.servlet-path" />
                <set-object property="linkFactory" value="infrastructure:linkFactory" />
                <set-object property="loginCookiesManager" value="service:common.tapestry.LoginCookiesManager"/>
             </construct>
        </invoke-factory>
    </service-point>

    <contribution configuration-id="tapestry.services.ApplicationServices">
        <service name="logout" object="service:common.tapestry.LogoutService" />
    </contribution>

</module>

in your Pages
<a jwcid="@ServiceLink" href="#" service="ognl:@common.tapestry.Tapestry@LOGOUT_SERVICE" target="_top">退出</a>

How to use cookies in tapestry4? my Tapestry4.1.5`LoginCookiesManagerImpl

How to use cookies in tapestry4? my Tapestry4.1.5`LoginCookiesManagerImpl

思路
首先BasePage是需要登陆的 protected ,
BasePage实现org.apache.tapestry.event.PageValidateListener方法,判断asm对象Visit是否已经登陆
如没visit==null,去cookies找回用户名和密码从cycle中获得Login页面
Login页面实现common.tapestry.IConstructVisit接口。LoginPage登陆时保存用户名密码到cookies中,并对cookies的值加密,
cookies的key是baseUrl+key,取回时对cookies值解密,加密解密的password放到Application的meta信息中

实现代码如下
抽象接口LoginCookiesManager

package common.tapestry.engine;

public interface LoginCookiesManager {
 
 String APPLICATION_META_KEY_DEFAULT_COOKIES_IS_ENCRYPTION = "common.tapestry.default-cookies-encrypt";//是否需要加密,默认加密
 String APPLICATION_META_KEY_DEFAULT_COOKIES_ENCRYPTION_KEY = "common.tapestry.default-cookies-encryption-key";//加密的password

 public static final String COOKIES_KEY_LOGIN_USERNAME = "USERNAME";
 public static final String COOKIES_KEY_LOGIN_PASSWORD = "PASSWORD";
 
 /**
  * 将用户名和密码写入cookies
  * @param username
  * @param password
  * @param maxAge
  */
 void writeCookies(String username,String password,int maxAge);
 /**
  * 清除用户名和密码cookies
  */
 void removeCookies();
 /**
  * 从cookies中获得用户名
  * @return
  */
 String getUsername();
 /**
  * 从cookies中获得密码
  * @return
  */
 String getPassword();
}

LoginCookiesManagerImpl 实现

package common.tapestry.engine;

import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.tapestry.engine.IPropertySource;
import org.apache.tapestry.services.AbsoluteURLBuilder;
import org.apache.tapestry.services.CookieSource;
import org.apache.tapestry.web.WebRequest;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;

public class LoginCookiesManagerImpl implements LoginCookiesManager {
 private static StandardPBEStringEncryptor standardPBEStringEncryptor = new StandardPBEStringEncryptor();
 private IPropertySource applicationPropertySource;
 private CookieSource cookieSource;
 private WebRequest request;
 private AbsoluteURLBuilder absoluteURLBuilder;

 public void setApplicationPropertySource(
   IPropertySource applicationPropertySource) {
  this.applicationPropertySource = applicationPropertySource;
  String encrypKey = getCookiesEncryptionKey();
  standardPBEStringEncryptor.setPassword(encrypKey);
 }

 private String decrypt(String value) {
  String tmp = value;
  try {
   tmp = standardPBEStringEncryptor.decrypt(value);
  } catch (EncryptionOperationNotPossibleException e) {
   throw new ApplicationRuntimeException("please clear your cookies");
  }
  return tmp;
 }

 private String encrypt(String value) {
  return standardPBEStringEncryptor.encrypt(value);
 }

 private String getCookiesEncryptionKey() {
  String temp = applicationPropertySource
    .getPropertyValue(APPLICATION_META_KEY_DEFAULT_COOKIES_ENCRYPTION_KEY);
  return (temp != null) ? temp : "crypassword";
 }

 private boolean isCookiesEncryption() {
  String temp = applicationPropertySource
    .getPropertyValue(APPLICATION_META_KEY_DEFAULT_COOKIES_IS_ENCRYPTION);
  return (temp != null) ? Boolean.valueOf(temp).booleanValue() : true;
 }

 public void removeCookies() {
  String cookiesKeyLogin_username = generateApplicationCookiesKey_Login__Username();
  String cookiesKeyLogin_password = generateApplicationCookiesKey_Login__Password();
  cookieSource.removeCookieValue(cookiesKeyLogin_username);
  cookieSource.removeCookieValue(cookiesKeyLogin_password);
 }

 public void writeCookies(String username, String password, int maxAge) {
  writeCookiesValue_Login__Username(username, maxAge);
  writeCookiesValue_Login__Password(password, maxAge);
 }

 public String getUsername() {
  String value = cookieSource
    .readCookieValue(generateApplicationCookiesKey_Login__Username());
  if (isCookiesEncryption()) {
   value = decrypt(value);
  }
  return value;
 }

 public String getPassword() {
  String value = cookieSource
    .readCookieValue(generateApplicationCookiesKey_Login__Password());
  if (isCookiesEncryption()) {
   value = decrypt(value);
  }
  return value;
 }

 private void writeCookiesValue_Login__Username(String username, int maxAge) {
  String key = generateApplicationCookiesKey_Login__Username();
  String value = username;
  if (isCookiesEncryption()) {
   value = encrypt(username);
  }
  cookieSource.writeCookieValue(key, value, maxAge);
 }

 private void writeCookiesValue_Login__Password(String password, int maxAge) {
  String key = generateApplicationCookiesKey_Login__Password();
  String value = password;
  if (isCookiesEncryption()) {
   value = encrypt(password);
  }
  cookieSource.writeCookieValue(key, value, maxAge);
 }

 private String generateApplicationCookiesKey_Login__Username() {
  return generateApplicationCookiesKey(COOKIES_KEY_LOGIN_USERNAME);
 }

 private String generateApplicationCookiesKey_Login__Password() {
  return generateApplicationCookiesKey(COOKIES_KEY_LOGIN_PASSWORD);
 }

 private String generateApplicationCookiesKey(String key) {
  String contextPath = request.getContextPath();
  return absoluteURLBuilder.constructURL(contextPath + "/") + key;
 }

 public void setCookieSource(CookieSource cookieSource) {
  this.cookieSource = cookieSource;
 }

 public void setRequest(WebRequest request) {
  this.request = request;
 }

 public void setAbsoluteURLBuilder(AbsoluteURLBuilder absoluteURLBuilder) {
  this.absoluteURLBuilder = absoluteURLBuilder;
 }

}

hivemodule.xml配置

<?xml version="1.0"?>
<module id="common.tapestry" version="1.0.0">
<service-point id="LoginCookiesManager" interface="common.tapestry.engine.LoginCookiesManager">
<invoke-factory>
   <construct class="common.tapestry.engine.LoginCookiesManagerImpl" >
     <set-object property="cookieSource" value="infrastructure:cookieSource"/>
     <set-service property="absoluteURLBuilder" service-id="tapestry.request.AbsoluteURLBuilder"/>
              <set-service property="request" service-id="tapestry.globals.WebRequest"/>  
              <set-object property="applicationPropertySource" value="service:tapestry.props.ApplicationPropertySource"/>             
      </construct>
  </invoke-factory> 
</service-point>

<contribution configuration-id="tapestry.Infrastructure">
    <property name="loginCookiesManager" object="service:common.tapestry.LoginCookiesManager"/>
</contribution>
</module>

使用

在BasePage中获得该service

public LoginCookiesManager getLoginCookiesManager() {
  LoginCookiesManager svc = (LoginCookiesManager) getRequestCycle().getInfrastructure().getProperty("loginCookiesManager");
  return svc;
 }
 
/**
  * 判断用户是否已经登陆
  *
  * @return
  */
 private boolean isUserLoggedIn() {
  Object asmVisit = this.getRequestCycle().getInfrastructure().getApplicationStateManager().get(ASM_VISIT);

  if (!(asmVisit instanceof IVisit)) {
   throw new ApplicationRuntimeException(
     "The visit class must implements " + IVisit.class);
  }
  IVisit visit = (IVisit) asmVisit;
  if (visit == null || (visit != null && !visit.isLoggedIn())) {
   IPage loginPage = getRequestCycle().getPage(PAGE_LOGIN);
   if (loginPage instanceof IConstructVisit) {
    //从cookies中找回用户名和密码
    String cookiesLoginUsername = getLoginCookiesManager().getUsername();
    String cookiesLoginPassword = getLoginCookiesManager().getPassword();
    IConstructVisit constructVisit = (IConstructVisit) loginPage;
    visit = constructVisit.doConstructVisit(this.getRequestCycle(),
      cookiesLoginUsername, cookiesLoginPassword);
   } else {
    throw new ApplicationRuntimeException("The " + PAGE_LOGIN
      + " class must implements " + IConstructVisit.class);
   }
  }
  if (visit == null)
   return Boolean.FALSE.booleanValue();
  return visit.isLoggedIn();
 } 


Login类必须实现如下接口
package common.tapestry;

import org.apache.tapestry.IRequestCycle;

public interface IConstructVisit {
 public IVisit doConstructVisit(IRequestCycle cycle, String username,String password);
}

 

Tapestry4.1.5`s common Base Border Component

Tapestry4.1.5`s common Base Border Component

考虑到每个项目都必须具有Border组件,所以把这个组件提到Base项目的ext组件库
但是每个项目的基本css又各不相同,这个css可以使用Tapestry的meta提供给Border
我在{yourTapestyServlet}.application中增加
<meta key="common.tapestry.components.border.stylesheets" value="css/POJO*.css,css/sys*.css"/>
其value是一个通配符表达式,灵感来源于spring的加载*.xml的写法,","号分割多个匹配

来看我们的Border.jwc规范

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE component-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">

<component-specification allow-body="yes" allow-informal-parameters="no" class="common.tapestry.components.Border">                        
<parameter name="title"/>
<parameter name="ajaxDelegate"/>

<component id="shell" type="Shell">
    <binding name="title" value="ognl:title+' - '+messages.getMessage('appname')"/>
    <binding name="doctype" value="literal:html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;" />
 <binding name="delegate" value="new org.apache.tapestry.components.BlockRenderer(components.remainingHead)"/>
    <binding name="renderBaseTag" value="ognl:false" />
    <binding name="disableTapestryMeta" value="ognl:true" />
    <inherited-binding name="ajaxDelegate" parameter-name="ajaxDelegate" />
    <binding name="stylesheets" value="ognl:stylesheets"/>   
</component>

<inject property="httpServletRequest" object="service:tapestry.globals.HttpServletRequest"/>
<inject property="webContext" object="service:tapestry.globals.WebContext"/>

<!--
<inject property="stylesheetResource" type="meta" object="common.tapestry.components.border.stylesheets"/>
-->
</component-specification>

html模板

<html jwcid="shell">
<head jwcid="remainingHead@Block">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body jwcid="@Body">
<span jwcid="@RenderBody"/>
</body>
</html>


Border.java

package common.tapestry.components;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.tapestry.BaseComponent;
import org.apache.tapestry.IAsset;
import org.apache.tapestry.asset.ContextAsset;
import org.apache.tapestry.web.WebContext;
import org.apache.tapestry.web.WebContextResource;
import org.springframework.core.io.Resource;
import org.springframework.web.context.support.ServletContextResource;
import org.springframework.web.context.support.ServletContextResourcePatternResolver;

public abstract class Border extends BaseComponent {
 // public abstract String getStylesheetResource(); //inject meta can`not
 // use?

 public abstract HttpServletRequest getHttpServletRequest();

 public abstract WebContext getWebContext();

 public static final String APPLICATION_META_KEY_DEFAULT_BORDER_STYLE = "common.tapestry.components.border.stylesheets";
 public static final String DEFAULT_STYLESHEET_RESOURCE = "css/system_*.css";

 public String getStylesheetResource() {
  String tmp = getPage().getRequestCycle().getInfrastructure()
    .getApplicationPropertySource().getPropertyValue(
      APPLICATION_META_KEY_DEFAULT_BORDER_STYLE);
  return (tmp != null) ? tmp : DEFAULT_STYLESHEET_RESOURCE;
 }

 public abstract IAsset[] getCssAsset();

 public abstract void setCssAsset(IAsset[] oo);

 public IAsset[] getStylesheets() {

  if (getCssAsset() == null) {

   String _stylesheetResource = (getStylesheetResource() != null) ? getStylesheetResource()
     : DEFAULT_STYLESHEET_RESOURCE;
   List list = new ArrayList();
   ServletContext _servletContext = getHttpServletRequest()
     .getSession().getServletContext();
   ServletContextResourcePatternResolver servletContextResourcePatternResolver = new ServletContextResourcePatternResolver(
     _servletContext);

   String[] _stylesheetResources = _stylesheetResource.split(",");

   for (int i = 0; i < _stylesheetResources.length; i++) {

    try {
     Resource[] resources = servletContextResourcePatternResolver
       .getResources(_stylesheetResources[i]);

     for (int j = 0; j < resources.length; j++) {
      ServletContextResource resource = (ServletContextResource) resources[j];

      WebContextResource _resourceLocation = new WebContextResource(
        getWebContext(), resource.getPath());
      IAsset asset = new ContextAsset(
        common.tapestry.TapestryUtils
          .getContextPath(getPage()
            .getRequestCycle()),
        _resourceLocation, getLocation(), getPage()
          .getRequestCycle());
      list.add(asset);
     }

    } catch (IOException e) {
     e.printStackTrace();
    }
   }

IAsset[] tmp = (IAsset[])list.toArray(new IAsset[list.size()]);
   setCssAsset(tmp);
  }
  return getCssAsset();
 }
}

March 21

Tapestry4.1.5 how to inject spring`s bean to pages

Tapestry4.1.5 how to inject spring`s bean to pages

1、in web.xml config spring

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>

2、put the tapestry-spring-1.0.0.jar to your classpath
you can download here
http://howardlewisship.com/tapestry-javaforge/tapestry-spring/


ok you can use  <inject property="userInfoService" object="spring:userInfoService"/> in your .page file
or use Annotations inject the service

but how to get the spring`s beans in the java code ?
--------------------------------------------------------------

3、config your ${yourApp}/WEB-INF/hivemodule.xml

<contribution configuration-id="tapestry.Infrastructure">
    <property name="springObjectProvider" object="service:hivemind.lib.SpringObjectProvider"/>
</contribution>

put the springObjectProvider to the tapestry.Infrastructure

ok in your code you can

org.apache.hivemind.service.ObjectProvider springprovider springprovider = (ObjectProvider) infrastructure.getProperty("springprovider");

YourSpringBean yourSpringBean = (YourSpringBean)springprovider.provideObject(null, null, yourSpringBeanId, null);

 

 

皮鞋又坏了

皮鞋又坏了,该买新的了
May 14

Tapestry5的无侵入式框架实现use Annotations?

Tapestry5称使用JDK5的Annotations实现无侵入式的框架,我看起来Annotations依然是侵入到了类,:(
敏捷的思维正在一步步渗透到Java Framework中,现在不仅要求类与类之间要解藕,类和Framework之间也要解耦,
 
途径:1)硬编码,extends/implements
      2)xml
      3)Framework的实践约定,比如说 public void **doActionListener(),方法名称的匹配说明了这是个Action监听器,够敏捷吧
 
我期待的Tapestry Control BackingBean是更纯的Java类,看来这个实现除了xml + implments,只剩下Framework的约定才能实现了,毕竟不用xml,不用Annotations,不用extends/implements 你得告诉Framework container 这个BackingBean 是怎么跟template粘起来的!