Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Wednesday, June 10, 2009

Yet Another Android Mobile Phone HelloWorld Tutorial

注明:版权归德明泰所有。此为转载。

开eclipse,新建一个android工程。
先得用xml画布局。可以拿个例子干写,可以用我发的那个可视化工具,eclipse自己也有个大米花的功能,可以给控件设属性,总之配合着来吧,反正最终的xml也简单。写一个xml就行了,位置是res/layout/main.xml
这是我写的
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/main"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<EditText
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
>
</EditText>
<Button
android:id="@+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Click Me"
>
</Button>
</LinearLayout>
最外层是一个Layout的大面板,控件往上扔就行了。我弄了一个文本框一个按钮。layout属性的fill_parent表示是跟爸爸一样,就是填满。wrap_content的意思好像是根据内容定长度。其他的都简单。那个id要选好,前面的@+id/是固定的,后面要起一个名字,程序里就用丫。
ec里能看到设计图。图懒得贴了,自己执行了看吧。
然后就写代码呗。我就贴关键部分。其中带底色的是建了and工程自动生成的,其他是我写的。
public class helloworld extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        clickMe = (Button)this.findViewById(R.id.button);
        editText = (TextView)this.findViewById(R.id.text);
        clickMe.setOnClickListener(new OnClickListener(){
            @Override
            public void onClick(View v) {
                editText.setText("Hello world!!!");               
            }});
    }
    private Button clickMe;
    private TextView editText;
}
先声明俩变量,按钮和文本框的。然后用this.findViewById,把控件找出来,id就是前面你丫写xml时候设的id。要用一个强制转换。这样那变量就跟实际的控件连上了,以后用就行了。
下面就简单了,弄上个listener,不多说了。其实除了那画xml跟)this.findViewById,真没啥新鲜玩意儿了。。。跟写普通java程序一样了。
简单吧!!!!
最后来个效果图

俩控件的水平方向layout都是fill_parent,所以撑满了

Saturday, April 11, 2009

Myeclipse Hibernate Session 在查询数据库后不更新的问题解决方案

最近的一个项目, 在更改数据库之后,再次查询,发现返回值总是在变化,有时候和数据库一致,有时候却仿佛回滚到了原来的状态。 这个问题是查询的时候,使用了以前的Session缓存。 虽然在数据更改之后,Hibernate会更新缓存,但是以前的session没有在finally关掉,所以缓存存在周期超过了一个transaction; 同时,又没有设置查询不使用缓存,所以造成了这个问题。

这个问题应该非常的常见,因为使用的代码是Hibernate生成的。 修复的办法是修改Hibernate生成的代码,设置Session不使用缓存(session.setCacheable ),然后在finally里面关掉Session.close(),并且每次都把Session清空(这个是在HibernateSessionFactory里面的getSession里面,加上Session.clear())。三管齐下,不过这是专门用来解决需要每次查询都更新的情况。 具体的对缓存的管理,大家还是按照项目的需求具体设置吧。

首先,遗弃原始的getSession() 方法, 使用新版的getClearSession() 方法。

    public static Session getClearSession() throws HibernateException {
Session session = (Session) threadLocal.get();

if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
session.clear();
return session;
}
然后在需要的地方调用新方法,并设置关闭缓存

    public List findRefreshAll() {
log.debug("finding all TkTimeEntry instances");
try {
String queryString = "from TkTimeEntry";
Query queryObject = getClearSession().createQuery(queryString);
queryObject.setCacheable(false);
return queryObject.list();
}
catch (RuntimeException re) {
log.error("find all failed", re);
throw re;
}
}
最后,在transaction使用session的时候,关闭session.
    public List<TkTimeEntry> RetrieveAllTimeEntry() {
TkTimeEntryDAO dao = new TkTimeEntryDAO();
Transaction trans = null;
try {
trans = dao.getSession().beginTransaction();
List<TkTimeEntry> timeEntryList = dao.findRefreshAll();
trans.commit();
return timeEntryList;

}
catch (HibernateException e) {
if (trans != null)
trans.rollback();
log.fatal(e);
return null;
}
finally
{
dao.getSession().close();
}

}

Wednesday, April 8, 2009

How to: Throw Custom Exception in Jax-ws

There is an excellent article on Faults and exceptions in JAX-WS, however, it doesn’t say how to throw custom exception clearly. Another post mentioned the below information, which I found most useful after google search to solve the problem. Again, it is still not correct solution.

Make the exception look like a normal JAX-WS generated exception.   That
would basically mean defining a JAXB bean for the data that has all the
getter/setters and such for the data and making the exception look like:
@WebFault
public class MyException extends Exception {
     MyFaultInfo faultInfo;
     public MyException(String msg, MyFaultInfo mfi) {
            ...
     }
     public MyFaultInfo getFaultInfo() {
         return faultInfo;
     }
}
That is basically the "JAX-WS" standard way of doing it and would be portable.  
The entire schema for the exception is defined in the JAXB MyFaultInfo bean.

If you look into jax-ws defination of @WebFault, it is basically on the client side, and was automatically generated! There is no point putting them in the server code. I had to admit that the explanation was clear and I write the following code to solve this problem

public class CustomException extends Exception {

private WSStatus faultInfo = null;

public CustomException(String message, WSStatus faultInfo)
{
super(message);
this.faultInfo = faultInfo;
}
public CustomException(String message, WSStatus faultInfo, Throwable cause)
{
super(message,cause);
this.faultInfo = faultInfo;
}

public CustomException(Exception ex)
{
super(ex.getMessage(),ex.getCause());
}

public WSStatus getErrorCode()
{
if(faultInfo==null)
faultInfo = new WSStatus();
return faultInfo;
}
}


Note that the generated code on client side would be something like CustomException_Exception extends Exception, so make sure you catch/throw the right exception.

Monday, April 6, 2009

Jax-ws on Tomcat: reconnect from Hibernate to MySQL using c3p0 connection pool

You are on this page because you have seen the following error:

org.hibernate.util.JDBCExceptionReporter: The last packet successfully received from the server was 56697 seconds ago. The last packet sent successfully to the server was 56697 seconds ago, which  is longer than the server configured value of ‘wait_timeout’. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property ‘autoReconnect=true’ to avoid this problem.

I guess you have already using ?autoReconnect=true in the JDBC URL (this evidently wasn’t working) and wonder why.

I also guess that you have tried google tons of articles trying to solve this problem. Well, you have come to the right place. I spend sometime on this issue and finnally solved this problem, almost encountered every bit of chaos.

Firstly, I would like to reference few good posts:

  • http://www.databasesandlife.com/automatic-reconnect-from-hibernate-to-mysql/
    • This one throws some light, but it is a bit old, so the connection pool was old fation and the author suggest to “ create a file c3p0.properties which must be in the root of the classpath with content c3p0.testConnectionOnCheckout=true” , which is expensive and not used anymore. Read it yourself for details. 
  • c3p0 - JDBC3 Connection and Statement Pooling This is offical document so refer to this when you can’t decide what to do! 
    • Hibernate's C3P0ConnectionProvider explicitly sets 7 c3p0 configuration properties, based on your hibernate configuration, overriding any configuration you may have set in a c3p0.properties file. If you are using Hibernate's C3P0ConnectionProvider you must set the following properties in your hibernate configuration, using hibernate-specific configuration keys. All other properties must be defined as usual in a c3p0.properties file. This is confusing, and will hopefully be simplified some time in the future, but for now...
    • The following properties must be set in your hibernate configuration:
    • 未命名
    • Remember -- these, and only these, properties must be defined in your hibernate configuration, or else they will be set to hibernate-specified defaults. All other configuration properties that you wish to set should be defined in a c3p0.properties file.
    • The easiest way to set these are actually using myeclipse hibernate.cfg.xml configuration editer. Make sure you set all config related to c3p0 and add “hibernate.” before the setting. For instance, change “c3p0.min_size” to “hibernate.c3p0.min_size”. See above table as well. If you are not using myeclipse, just edit the xml in text editor.

With the above information, You are almost there, except you need the jar files in the classpath. Otherwise, you will get exception java.lang.NoClassDefFoundError for HibernateSessionFactory. In myeclipse, jar is not included as default hibernate support, so you need to add advanced support.

This problem annoying me for almost two weeks, and everytime I check my log4j and tomcat log, I saw this warning. Not sure if it really is a serious problem, but using connection pool definately enhance Hibernate performace.

Wednesday, March 25, 2009

java how to convert int to Byte array, and how to assign int value to Byte

Byte only have a constructor which takes Byte itself, so anything like

Byte b = new Byte(1);

or

Byte b = 1;

will all fail;

 

The easiest way to assign int to Byte is using the empty constructor, then = operator.

Byte b;

b = 1;

To convert int to Byte array, try the following:

t[0] =(Byte)( foo >> 24 );
t[1] =(Byte)( (foo << 8) >> 24 );
t[2] =(Byte)( (foo << 16) >> 24 );
t[3] =(Byte)( (foo << 24) >> 24 );