2010年7月25日 星期日

Appengine程式碼分享

1. AppEngine整合Spring+JPA  文章 下載程式碼
2. AppEngine整合Struts2+Spring+JPA 文章 下載程式碼

AppEngine整合Struts2+Spring+JPA

STEP 1. 事前準備
1. 請先參考AppEngine整合Spring+JPA
2. 本範例是用Struts2.1.8, 建議是用一樣的版本, 比較不會有問題,下載之後把下面這些JAR檔, 放到Lib裡
  • commons-fileupload-1.2.1.jar
  • commons-io-1.3.2.jar
  • freemarker-2.3.15.jar
  • ognl-2.7.3.jar
  • struts2-core-2.1.8.1.jar
  • struts2-spring-plugin-2.1.8.1.jar
  • xwork-core-2.1.6.jar

STEP 2.因為GAE安全的設定比較嚴謹, 所以必須修改安全設定, 這裡是依照官網的討論用Listener的方式去修改
gae.InitListener

package gae;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import ognl.OgnlRuntime;

public class InitListener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener {
    public void contextInitialized(ServletContextEvent arg0) {
        OgnlRuntime.setSecurityManager(null); 
    }
    public void contextDestroyed(ServletContextEvent arg0) {}
    public void sessionCreated(HttpSessionEvent arg0) {}
    public void sessionDestroyed(HttpSessionEvent arg0) {}
    public void attributeAdded(HttpSessionBindingEvent arg0) {}
    public void attributeRemoved(HttpSessionBindingEvent arg0) {}
    public void attributeReplaced(HttpSessionBindingEvent arg0) {}
}


STEP 3. 修改 Action 及相關的設定
1. 修改 Action: fattom.riddle.TestAction

package fattom.riddle;

import java.util.List;
import fattom.riddle.dao.UserDao;
import fattom.riddle.entity.User;

public class TestAction{
    private UserDao userDao;
    private String name;
    private String action;
private List users;

    public String execute() throws Exception {
        if (name != null) {
            User tmpUser = new User();
            tmpUser.setName(name);
            userDao.persist(tmpUser);
        }

        users = userDao.findAll();

        if (action != null && "delete".equals(action)) {
            for (Object user : users) {
                userDao.remove((User)user);
            }
        }
       
        return "success";
    }

    public void setUserDao(UserDao userDao) {this.userDao = userDao;}
    public void setName(String name) {this.name = name;}
    public void setAction(String action) {this.action = action;}
    public List getUsers() {return users;}
}



2. 新增struts設定檔: src/struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="false" />

    <package name="default" namespace="/" extends="struts-default">
        <action name="test" class="fattom.riddle.TestAction" method="execute">
            <result name="success">/WEB-INF/success.jsp</result>
        </action>
    </package>
</struts>


3. 新增Action回應的VIEW: /WEB-INF/success.jsp

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
    <title>Hello App Engine</title>
</head>
<body>
    <s:iterator value="users">
        <s:property value="id"/>/<s:property value="name"/><br>
     </s:iterator>
</body>
</html>



4. 修改web.xml

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
    <listener>
        <listener-class>gae.InitListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

2010年7月23日 星期五

AppEngine整合Spring+JPA

STEP 1. 事前準備
1. 先準備AppEngine SDK1.3.5版以上
2. 本範例是用Spring 2.5, 建議是用一樣的版本, 比較不會有問題,下載之後把下面這些JAR檔, 放到Lib裡
  • aspectjrt.jar
  • aspectjweaver.jar
  • cglib-nodep-2.1_3.jar
  • commons-logging-1.0.4.jar
  • spring.jar

STEP 2. 建立Entity, DAO, Servlet
1. 建立本範例中的Entity: fattom.riddle.entity.User

package fattom.riddle.entity;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User implements Serializable{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}


2.建立DAO: fattom.riddle.dao.UserDao

package fattom.riddle.dao;

import java.util.List;
import org.springframework.orm.jpa.support.JpaDaoSupport;
import fattom.riddle.entity.User;

public class UserDao extends JpaDaoSupport {

    public void persist(Object user) {
        this.getJpaTemplate().persist(user);
    }
 
    public void remove(Object user) {
        User result = this.getJpaTemplate().find(User.class, ((User)user).getId());
        if(result != null)
            this.getJpaTemplate().remove(result);
    }
    @SuppressWarnings("unchecked")
    public void removeAll() {
        List result = this.getJpaTemplate().find("select e from fattom.riddle.entity.User e");
        for(Object user:result) {
            this.getJpaTemplate().remove((User)user);
        }
    }

    @SuppressWarnings("unchecked")
    public List findAll() {
        List result = this.getJpaTemplate().find("select e from fattom.riddle.entity.User e");
        result.size();
        return result;
    }
}


3. 建立Servlet: fattom.riddle.TestAction

package fattom.riddle;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import fattom.riddle.dao.UserDao;
import fattom.riddle.entity.User;

@SuppressWarnings("serial")
public class TestAction extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        PrintWriter out = response.getWriter();
        response.setContentType("text/plain");

        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        UserDao userDao = (UserDao) context.getBean("userDao");

        if (request.getParameter("name") != null) {
            User tmpUser = new User();
            tmpUser.setName(request.getParameter("name"));
            userDao.persist(tmpUser);
        
        }

        List users = userDao.findAll();
        for (Object user : users) {
            out.println(((User)user).getId() + "/" + ((User)user).getName());
        }
    
        if (request.getParameter("action") != null && "delete".equals(request.getParameter("action"))) {
            for (Object user : users) {
                userDao.remove((User)user);
            }
        }

        out.println("Hello, GAE and Spring world");
    }
}


STEP 3. 設定相關XML
1. META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

    <persistence-unit name="transactions-optional">
        <provider>org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider</provider>
        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>
        </properties>
    </persistence-unit>

</persistence>


2. WEB-INF/applicationContext.xml

 <?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" >
        <property name="persistenceUnitName" value="transactions-optional"/>
    </bean>
  
    <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

  <aop:config proxy-target-class="true">
        <aop:advisor pointcut="execution(* fattom.riddle..dao.*.*(..))" advice-ref="txAdvice"/>
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    <bean id="userDao" class="fattom.riddle.dao.UserDao" scope="singleton">
    </bean>
</beans>



3. WEB-INF/web.xml

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
<servlet>
<servlet-name>Test</servlet-name>
<servlet-class>fattom.riddle.TestAction</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Test</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>


最後, 再寫個 index.html 就可以測試看看有沒有成功囉

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>Hello App Engine</title>
  </head>

  <body>
    <h1>Hello App Engine!</h1>
<form action="test" method="get">
add new user, name = <input type="text" name="name"></input>
<input type="submit" value="OK"></input>
</form>
<br>
<a href="./test?action=delete">delete all users</a>
</br>
  </body>
</html>

2010年7月5日 星期一

Google Code Jam 2010 參賽心得

這是我第一次參加CodeJam
運氣很好有晉級到Round2, 因為出國玩的關係就沒有繼續比下去了
有一些心得可以跟大家分享一下

1. 資格賽的部分, 時間很充裕, 只要完整回答一整題就可以晉級
    不過每一題都要解兩次, 第一次的輸入值會比較簡單
    第二次通常都需要對演算法作一些加速才能在時間內跑完程式
    而且第二次不像第一次一樣, 程式寫錯了, 可以一直重試,
    第二次的解答只有執行一次的機會, 所以一定要再三確認程式沒有問題才去執行
    很多人都是因為第二次的輸入值太大, 程式跑不完, 而Timeout, 要小心!

2. 正式比賽就是比誰寫的快了, 至少要快速的完整解完第一題, 才有機會晉級
    通常, 第一題是最簡單的, 最難的是第三題,
    所以千萬不要因為後面的分數比較高, 就跳著做,
    也不要把所有題目都看完才決定做哪一題, 那一定來不及

3. 有時候, 正式比賽的第一題會比較簡單, 所以必須趕快去解答第二題或第三題
    因為每個人學的領域都不一樣, 建議可以快速的看完第二題或第三題的題目
    選擇有把握的來做, 先做簡單的解就可以了

另外, 這次比賽有個比較特別的地方, 就是用到了Big Number的處理
因為我本身是用JAVA, 在處理大數的部份就非常簡單
我想以後的考試, 可能也會要大家去使用一些基本的API,
建議大家在選擇用哪一種程式語言的時候, 也要考慮到這個問題


=====


Our sincerest apologies!  An email was sent to you in error that indicated that you hadn't advanced to Round 2.  You DID advance; there is no part of our system that thinks you didn't; and we're very sorry for the confusion!  Here is the email you were supposed to receive:


=====

Subject: Congratulations - You're on to Round 2 of Google Code Jam 2010!
Congratulations!  You've proven you're one of the best 3000 contestants in Google Code Jam 2010!

Having placed in the top 1000 in a Round 1 subround, you're now eligible to compete in Round 2.  Round 2 will last 2 hours and 30 minutes, and will take place on Saturday, June 5, 2010 at 14:00 UTC.  Visit http://code.google.com/codejam/schedule.html to find that time in your own time zone, and good luck!

If you have any questions, please visit our FAQ at http://code.google.com/codejam/faq.html, or email us atprogrammingcontest-feedback@google.com.

Congratulations!
The Code Jam Team

=====

Sorry for the mixup, and congratulations again!
The Code Jam Team