More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  蚯蚓PhotosProfileFriendsMore Tools Explore the Spaces community

蚯蚓

理想,现实,自由,人性,思想,分享,和谐,美丽
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粘起来的!
 
May 06

革命

“在我们力图改善文明这个整体的种种努力中,我们还必须始终在这个给定的整体中进行工作,旨在点滴建设,而不是全盘的建构,并在发展的每一个阶段中都运用既有的历史材料,一步一步地改进细节,而不是力图重新建设这个整体。”

——著名政治思想家弗里德里希·冯·哈耶克

April 28

DAO exception/business exception 粒度

Interface UserInfo{
public void login(String userName,String password) throw Exception/RuntimeException/or CustomException/or CustomRuntimeException
}
 
UserNotFonundException extends Exception ?
 
PassWordWorngException ?
 
Whe in Action/listener
use try{
 
}catch(){
          throw new ApplicationRuntimeException(e.getMessage());
}
 
困惑中~
Exception handling in DAOs
 

DAO / Service层的划分

由于Hibernate等ORM映射tools的出现,DAO并不在直接跟数据库RDB打交道,而是多了 应用服务器持久层,从广义上讲RDB也算是持久,
应用服务器对象持久层 是为了能管理ORM映射的对象的状态和周期而存在的
 
DAO ---> Persisent  ---->RDB
 
View more entries