<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Google Stop Blog - Make a change &#187; Programming Language</title>
	<atom:link href="http://googlestop.com/blog/category/programming-language/feed/" rel="self" type="application/rss+xml" />
	<link>http://googlestop.com/blog</link>
	<description>Just another weblog of Charry</description>
	<lastBuildDate>Sat, 07 Jan 2012 09:51:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>How to exit a Java app gracefully</title>
		<link>http://googlestop.com/blog/2010/11/how-to-exit-a-java-app-gracefully/</link>
		<comments>http://googlestop.com/blog/2010/11/how-to-exit-a-java-app-gracefully/#comments</comments>
		<pubDate>Sun, 21 Nov 2010 03:06:10 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming Language]]></category>
		<category><![CDATA[Unix&Linux]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/2010/11/how-to-exit-a-java-app-gracefully/</guid>
		<description><![CDATA[标题：如何优雅的退出Java程序 本文中信号拦截代码来自下面的博客： http://twit88.com/blog/2007/09/27/do-a-graceful-shutdown-of-your-java-application-when-ctr-c-kill/ 在UNIX下，通常我们结束一个进程，最常用的方式就是使用kill –9 &#60;PID&#62;，这个方法最简单，但是会带来一个问题，程序可能正在执行某些操作，而这些操作不能被突然中断，否则会造成一些资源的泄露，或者数据完整性的问题。 在UNIX下，信号可以被用来解决这个问题，我们应该比较熟悉kill这个命令，通常使用的命令kill –9 中的kill其实不是‘杀死’的意思，而是‘发送’。kill –9 就是把 SIGKILL（数字代码为9）的信号发送到目标进程。在Java中，可以捕获这些信号： Runtime.getRuntime().addShutdownHook(…); 当我们执行Ctrl+C或者kill命令的时候，信号Handler会被通知到，这个Handler在一个新的线程中（并非主线程），我们可以在这个Handler里面处理资源释放等问题，注意这里的kill没有带参数，其实等同于kill -15，如果使用kill -9就会直接干掉目标进程，资源得不到回收。具体做法可参考上面的链接。 当Java捕捉到SIGTERM信号的时候，它会执行子线程中的shutdown(); 代码，理论上我们可以把资源清理工作放在这里，我们知道，这个信号监听的线程和主线程，分别在处在两个线程中，这里的代码执行完毕后，它并不管主线程里面的代码是否执行完毕，直接就把整个进程结束了。假设我们有一个长循环在主线程中，它可能会在循环没有执行完毕就殒命了。这个不是我们想要的，解决也很简单：在两个线程中增加同步机制就可以了。 尝试一： 设置一个标志位(notifiedMainThreadToExit = false)，当收到SIGTERM信号后，在子线程中设置notifiedMainThreadToExit为true，然后sleep(Long.MAX_VALUE)，主线程轮询这个标识位，一旦发现该变量为true，就退出循环，并且释放资源。 问题出现了：主线程的确退出了，可是子线程一直长眠，这个会导致整个进程都不会退出。后来我在主线程退出前，执行System.exit，问题依旧。理论上：System.exit执行后，它会结束该虚拟机中的所有线程，不知道为什么在这里行不通。 尝试二： 设置两个标识位(notifiedMainThreadToExit = false, notifiedSignalHandlerToExit = false)，当子线程收到信号后，它通知主线程(set notifiedMainThreadToExit = true)：“我收到SIGTERM信号了，你可以准备收工了”，然后，子线程并不马上退出，也不永久休眠，而是轮训等待主线程通知自己。当主线程接受到子线程的通知后，退出循环，然后通知子线程(set notifiedSignalHandlerToExit = true)：“我已经准备好了，你也可以收工了”，这样两个线程都可以正常的退出。 结论： 尝试二是可行的，且两个线程间不会产生Race Condition，因为没有两个线程同时写的问题，所以很安全。这里可以下载例子。最后提醒，文章提到的kill，是不带参数的，不要用kill -9。 [ad]]]></description>
			<content:encoded><![CDATA[<p>标题：如何优雅的退出Java程序    <br />本文中信号拦截代码来自下面的博客：     <br /><a href="http://twit88.com/blog/2007/09/27/do-a-graceful-shutdown-of-your-java-application-when-ctr-c-kill/">http://twit88.com/blog/2007/09/27/do-a-graceful-shutdown-of-your-java-application-when-ctr-c-kill/</a></p>
<p>在UNIX下，通常我们结束一个进程，最常用的方式就是使用kill –9 &lt;PID&gt;，这个方法最简单，但是会带来一个问题，程序可能正在执行某些操作，而这些操作不能被突然中断，否则会造成一些资源的泄露，或者数据完整性的问题。</p>
<p>在UNIX下，<a href="http://en.wikipedia.org/wiki/Signal_(computing)">信号</a>可以被用来解决这个问题，我们应该比较熟悉kill这个命令，通常使用的命令kill –9 中的kill其实不是‘杀死’的意思，而是‘发送’。kill –9 就是把 SIGKILL（数字代码为9）的信号发送到目标进程。在Java中，可以捕获这些信号：</p>
<blockquote><p>Runtime.getRuntime().addShutdownHook(…);</p>
</blockquote>
<p>当我们执行Ctrl+C或者kill命令的时候，信号Handler会被通知到，这个Handler在一个新的线程中（并非主线程），我们可以在这个Handler里面处理资源释放等问题，注意这里的kill没有带参数，其实等同于kill -15，如果使用kill -9就会直接干掉目标进程，资源得不到回收。具体做法可参考上面的链接。</p>
<p>当Java捕捉到SIGTERM信号的时候，它会执行子线程中的shutdown(); 代码，理论上我们可以把资源清理工作放在这里，我们知道，这个信号监听的线程和主线程，分别在处在两个线程中，这里的代码执行完毕后，它并不管主线程里面的代码是否执行完毕，直接就把整个进程结束了。假设我们有一个长循环在主线程中，它可能会在循环没有执行完毕就殒命了。这个不是我们想要的，解决也很简单：在两个线程中增加同步机制就可以了。</p>
<p>尝试一：    <br />设置一个标志位(notifiedMainThreadToExit = false)，当收到SIGTERM信号后，在子线程中设置notifiedMainThreadToExit为true，然后sleep(Long.MAX_VALUE)，主线程轮询这个标识位，一旦发现该变量为true，就退出循环，并且释放资源。</p>
<p>问题出现了：主线程的确退出了，可是子线程一直长眠，这个会导致整个进程都不会退出。后来我在主线程退出前，执行System.exit，问题依旧。理论上：System.exit执行后，它会结束该虚拟机中的所有线程，不知道为什么在这里行不通。</p>
<p>尝试二：    <br />设置两个标识位(notifiedMainThreadToExit = false, notifiedSignalHandlerToExit = false)，当子线程收到信号后，它通知主线程(set notifiedMainThreadToExit = true)：“我收到SIGTERM信号了，你可以准备收工了”，然后，子线程并不马上退出，也不永久休眠，而是轮训等待主线程通知自己。当主线程接受到子线程的通知后，退出循环，然后通知子线程(set notifiedSignalHandlerToExit = true)：“我已经准备好了，你也可以收工了”，这样两个线程都可以正常的退出。</p>
<p>结论：    <br />尝试二是可行的，且两个线程间不会产生Race Condition，因为没有两个线程同时写的问题，所以很安全。<a href="http://googlestop.com/download/viper.zip">这里</a>可以下载例子。最后提醒，文章提到的kill，是不带参数的，不要用kill -9。</p>
<p>[ad]</p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2010/11/how-to-exit-a-java-app-gracefully/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>基于文件系统的生产者和消费者问题</title>
		<link>http://googlestop.com/blog/2010/08/%e5%9f%ba%e4%ba%8e%e6%96%87%e4%bb%b6%e7%b3%bb%e7%bb%9f%e7%9a%84%e7%94%9f%e4%ba%a7%e8%80%85%e5%92%8c%e6%b6%88%e8%b4%b9%e8%80%85%e9%97%ae%e9%a2%98/</link>
		<comments>http://googlestop.com/blog/2010/08/%e5%9f%ba%e4%ba%8e%e6%96%87%e4%bb%b6%e7%b3%bb%e7%bb%9f%e7%9a%84%e7%94%9f%e4%ba%a7%e8%80%85%e5%92%8c%e6%b6%88%e8%b4%b9%e8%80%85%e9%97%ae%e9%a2%98/#comments</comments>
		<pubDate>Sat, 07 Aug 2010 07:05:49 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[Architecture Design]]></category>
		<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming Language]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/2010/08/%e5%9f%ba%e4%ba%8e%e6%96%87%e4%bb%b6%e7%b3%bb%e7%bb%9f%e7%9a%84%e7%94%9f%e4%ba%a7%e8%80%85%e5%92%8c%e6%b6%88%e8%b4%b9%e8%80%85%e9%97%ae%e9%a2%98/</guid>
		<description><![CDATA[周末的时候和team讨论了下如何用最简单的方式，提高数据文件的单位时间传输吞吐量。下面是一个简单的应用场景： 一个目录(DIR1)，有很多Producer向这个目录里面放文件，同时有很多的Consumer负责从这个目录里面消费这些文件，插入数据库或者做其他的操作，然后删除或者移走这些文件。 假设条件： 一个文件中转目录DIR1，这个目录位于一个网络存储上 一个生产者，每一秒钟向DIR1里面放一个文件 若干个消费者，假设有8个，其实是8个不同的服务器，都可以访问DIR1，多台服务器可以起负载均衡的作用，任何一台或者几台出问题，整个数据流不会中断 解析一个文件大约需要2-14秒 最后一点：位于网络存储上的目录DIR1，我们认为它是不会出问题的，它不是这里的问题核心 这个场景很普遍，很多公司大概都会用到，尤其是那么比较老的系统(Legacy System)，下面是两种方案： 方案一 Consumer循环扫描DIR1，一旦发现有文件，循环解析这些文件，这里有8台服务器，也就是说有8个Consumer一起这样做。代码如下： public void run() { System.out.println("Created consumer:" + threadName); while (true) { File file = new File(Constant.STAGING_FOLDER); File files[] = file.listFiles(); for (int i = 0; i < files.length; ++i) { File f = files[i]; parse(Constant.STAGING_FOLDER + "/" + f.getName()); } Commons.sleep(); } } [...]]]></description>
			<content:encoded><![CDATA[<p>周末的时候和team讨论了下如何用最简单的方式，提高数据文件的单位时间传输吞吐量。下面是一个简单的应用场景：</p>
<p><strong>一个目录(DIR1)，有很多Producer向这个目录里面放文件，同时有很多的Consumer负责从这个目录里面消费这些文件，插入数据库或者做其他的操作，然后删除或者移走这些文件。</strong></p>
<p><strong>假设条件：</strong></p>
<ul>
<li>一个文件中转目录DIR1，这个目录位于一个网络存储上</li>
<li>一个生产者，每一秒钟向DIR1里面放一个文件</li>
<li>若干个消费者，假设有8个，其实是8个不同的服务器，都可以访问DIR1，多台服务器可以起负载均衡的作用，任何一台或者几台出问题，整个数据流不会中断</li>
<li>解析一个文件大约需要2-14秒</li>
<li>最后一点：位于网络存储上的目录DIR1，我们认为它是不会出问题的，它不是这里的问题核心</li>
</ul>
<p>这个场景很普遍，很多公司大概都会用到，尤其是那么比较老的系统(Legacy System)，下面是两种方案：</p>
<h3>方案一</h3>
<p>Consumer循环扫描DIR1，一旦发现有文件，循环解析这些文件，这里有8台服务器，也就是说有8个Consumer一起这样做。代码如下：</p>
<pre>
	public void run() {
		System.out.println("Created consumer:" + threadName);

		while (true) {
			File file = new File(Constant.STAGING_FOLDER);
			File files[] = file.listFiles();
			for (int i = 0; i < files.length; ++i) {
				File f = files[i];
				parse(Constant.STAGING_FOLDER + "/" + f.getName());
			}

			Commons.sleep();
		}
	}
</pre>
<p>看起来很简单，可是上面的代码效率非常的差，多个Consumer有很大的几率拿到相同的文件，当某个Consumer尝试去解析一个文件时，却发现这个文件已经被别的Consumer解析过了，并且文件也都删除或者移走了。这样浪费的很多的CPU时间。</p>
<p>可以用下面的方案来替代：</p>
<h3>方案二</h3>
<pre>
	public void run() {
		System.out.println("Created consumer:" + threadName);

		while (true) {
			File file = new File(Constant.STAGING_FOLDER);
			File files[] = file.listFiles();

			int nCapacity = files.length > Constant.CAPACITY ? Constant.CAPACITY
					: files.length;
			System.out.println(this.threadName + " found " + nCapacity
					+ " files");

			for (int i = 0; i < nCapacity; ++i) {
				File f = files[i];
				f.renameTo(new File(Constant.TMP_FOLDER + "/" + f.getName()));
			}

			for (int i = 0; i < nCapacity; ++i) {
				parse(Constant.TMP_FOLDER + "/" + files[i].getName());
			}

			Commons.sleep();
		}
	}
</pre>
<p>它和方案一的不同之处在于：它每次扫描完目录后，最多只取前若干个文件，这里是10个。并且，它不急于去处理文件，而是把文件马上移动到一个临时工作目录，其他的的操作都是相同的。</p>
<p>对于这个方案，有个附加条件：这个临时工作目录tmp，一定要和staging目录在同一个文件系统(filesystem)，这样的话，mv操作就只是修改一下inode，几乎瞬间完成。</p>
<h3>比较（Benchmarking)</h3>
<p>为了测试两中方案的效率差别，我写了一个模拟程序(<a href="http://googlestop.com/download/SimConsumer.7z">http://googlestop.com/download/SimConsumer.7z</a>)，它有7个class：</p>
<ol>
<li>App.java - 程序入口</li>
<li>Commons.java - 共享的函数</li>
<li>Constant.java – 配置参数</li>
<li>Producer.java - 生产者，每隔一秒向目录staging里丢一个文件</li>
<li>AbstractConsumer.java – 抽象消费者，定义消费者的一些基本属性和行为</li>
<li>Consumer1.java - 具体消费者，实现方案一</li>
<li>Consumer2.java - 具体消费者，实现方案二</li>
</ol>
<p>在App.java中，你可以指定调用Consumer1还是Consumer2。</p>
<p>对于前者(Consumer1)，staging目录下的文件数目不停的增长，并且如log显示，有很多冲突：一个Consumer准备处理的文件已经被其他的Consumer处理完了，造成了很多无效的操作，由于消费速度更不上生产速度，DIR1被撑爆只是时间的问题。</p>
<p>对于后者(Consumer2)，staging目录下的文件几乎马上就会被移动到tmp目录下，大部分时间，文件数都为0。而tmp目录下，在程序稳定后大概保存在20多个文件左右，保持一个动态的平衡。用这种方式，你也会看到很多冲突，但是只会发生在程序刚开始，原因是，刚开始的时候，8个线程几乎是同时去访问staging目录，势必拿到很多相同的文件，待到稳定后，就很少有冲突发生了。</p>
<p>这两种方案都是最基本的，没有借助于第三方工具完成的，成本是最低的，其实还有一些其他的方案，可能会借助一些服务来实现，比如消息分发、数据库等。有时间的话，我继续补充。</p>
<p>[ad]</p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2010/08/%e5%9f%ba%e4%ba%8e%e6%96%87%e4%bb%b6%e7%b3%bb%e7%bb%9f%e7%9a%84%e7%94%9f%e4%ba%a7%e8%80%85%e5%92%8c%e6%b6%88%e8%b4%b9%e8%80%85%e9%97%ae%e9%a2%98/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>NoSuchMethodError of BeanUtils.copyProperty(due to wrong access level)</title>
		<link>http://googlestop.com/blog/2010/03/nosuchmethoderror-of-beanutils-copypropertydue-to-wrong-access-level/</link>
		<comments>http://googlestop.com/blog/2010/03/nosuchmethoderror-of-beanutils-copypropertydue-to-wrong-access-level/#comments</comments>
		<pubDate>Fri, 26 Mar 2010 14:40:40 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/?p=621</guid>
		<description><![CDATA[为了节省开发时间，今天打算做一个数据集合类，可以直接将java中的ResultSet，或者其他Collection派生类的内容copy到该集合中，然后加入自定义的一些方法，比如支持直接导出Excel、CSV、KDF、Image、HTML等。这里借助Apache Commons BeanUtils的和反射(Reflection)，将数据库中的一行记录保存为一个对象，然后插入数据集中，结果老是报错如下： USING CONVERTER org.apache.commons.beanutils.converters.IntegerConverter@1befab0 java.lang.reflect.InvocationTargetException: Cannot set id at org.apache.commons.beanutils.BeanUtilsBean.copyProperty(BeanUtilsBean.java:449) at org.apache.commons.beanutils.BeanUtils.copyProperty(BeanUtils.java:129) &#8230; &#8230; Caused by: java.lang.NoSuchMethodException: Property &#8216;id&#8217; has no setter method at org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:1746) at org.apache.commons.beanutils.BeanUtilsBean.copyProperty(BeanUtilsBean.java:447) 代码段如下： private void dumpResultSet(ResultSet rs, Class clazz) throws Exception { ResultSetMetaData metaData = (ResultSetMetaData) rs.getMetaData(); int colCnt = metaData.getColumnCount(); Field[] fields = clazz.getDeclaredFields(); while (rs.next()) { [...]]]></description>
			<content:encoded><![CDATA[<p>为了节省开发时间，今天打算做一个数据集合类，可以直接将java中的ResultSet，或者其他Collection派生类的内容copy到该集合中，然后加入自定义的一些方法，比如支持直接导出Excel、CSV、KDF、Image、HTML等。这里借助Apache Commons BeanUtils的和反射(Reflection)，将数据库中的一行记录保存为一个对象，然后插入数据集中，结果老是报错如下：</p>
<blockquote><p>USING CONVERTER org.apache.commons.beanutils.converters.IntegerConverter@1befab0<br />
<span style="color: #ff0000;"> java.lang.reflect.InvocationTargetException: Cannot set id</span><br />
at org.apache.commons.beanutils.BeanUtilsBean.copyProperty(BeanUtilsBean.java:449)<br />
at org.apache.commons.beanutils.BeanUtils.copyProperty(BeanUtils.java:129)</p>
<p>&#8230; &#8230;<br />
Caused by: <span style="color: #ff0000;">java.lang.NoSuchMethodException: Property &#8216;id&#8217; has no setter method</span><br />
at org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:1746)<br />
at org.apache.commons.beanutils.BeanUtilsBean.copyProperty(BeanUtilsBean.java:447)</p></blockquote>
<p>代码段如下：</p>
<pre>
private void dumpResultSet(ResultSet rs, Class clazz) throws Exception {
	ResultSetMetaData metaData = (ResultSetMetaData) rs.getMetaData();
	int colCnt = metaData.getColumnCount();
	Field[] fields = clazz.getDeclaredFields();

	while (rs.next()) {
		Object newInstance = clazz.newInstance();

		for (int i = 1; i &lt;= colCnt; i++) {
			try {
				Object value = rs.getObject(i);
				for (int j = 0; j &lt; fields.length; j++) {
					Field f = fields[j];
					if (f.getName().equalsIgnoreCase(
							metaData.getColumnName(i).replaceAll(&quot;_&quot;, &quot;&quot;))) {

						log.info(&quot;f.getName:&quot; + f.getName());

						BeanUtils.copyProperty(newInstance, f.getName(),
								value);
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		list.add(newInstance);
	}
}
</pre>
<p>The root cause: <span style="color: #ff0000;">public </span>is required for class UserInfo, or else you&#8217;ll get the &#8216;<span style="color: #ff0000;">NoSuchMethodError</span>&#8216; exception, DO NOT ignore the access level</p>
<pre>
public class UserInfo {
	private int id;
	private String user;
	private String password;

	public UserInfo() {
	}

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
}
</pre>
<p>Eclipse一直提示：NoSuchMethodError，可是UserInfo里面明明有对应的setter方法，最后，才鬼使神差的发现，只要将UserInfo整个类声明为public就可以了。我一直都把注意力放到是否把setter和getter设置为public，却忽略了Bean的访问级别，希望碰到类似问题的朋友可以注意一下。</p>
<p>[ad]</p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2010/03/nosuchmethoderror-of-beanutils-copypropertydue-to-wrong-access-level/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A XFire error and solution</title>
		<link>http://googlestop.com/blog/2008/12/a-xfire-error-and-solution/</link>
		<comments>http://googlestop.com/blog/2008/12/a-xfire-error-and-solution/#comments</comments>
		<pubDate>Mon, 15 Dec 2008 10:54:39 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Web Service]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/2008/12/15/a-xfire-error-and-solution/</guid>
		<description><![CDATA[when i tried to deploy my web service with XFire, i got the following error message: Exception in thread &#34;main&#34; org.codehaus.xfire.annotations.AnnotationException: Service class cannot be abstract: com.webserviceproject.xifre… the root cause is mis-matched dependency libs, for my case, i’ve imported xfire-annotation-1.2.6.jar and xfire-annotation-1.1.1.jar at the same time. coz i used the wrong pom.xml as below: &#160;&#160;&#160;&#160;&#160;&#160;&#160; [...]]]></description>
			<content:encoded><![CDATA[<p>when i tried to deploy my web service with XFire, i got the following error message:</p>
<blockquote><p>Exception in thread &quot;main&quot; org.codehaus.xfire.annotations.AnnotationException: Service class cannot be abstract: com.webserviceproject.xifre…</p>
</blockquote>
<p>the root cause is mis-matched dependency libs, for my case, i’ve imported xfire-annotation-1.2.6.jar and xfire-annotation-1.1.1.jar at the same time. coz i used the wrong pom.xml as below:</p>
<blockquote><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <strike>&lt;dependency&gt;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;groupId&gt;org.codehaus.xfire&lt;/groupId&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;artifactId&gt;xfire-jaxb2&lt;/artifactId&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;version&gt;1.1.1&lt;/version&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/dependency&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;dependency&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;groupId&gt;org.codehaus.xfire&lt;/groupId&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;artifactId&gt;xfire-spring&lt;/artifactId&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;version&gt;1.1.1&lt;/version&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/dependency&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;dependency&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;groupId&gt;org.codehaus.xfire&lt;/groupId&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;artifactId&gt;xfire-java5&lt;/artifactId&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;version&gt;1.1.1&lt;/version&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/dependency&gt;</strike>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br />&#160;&#160;&#160;&#160;&#160; <font color="#ff0000"></font><font color="#008000">&lt;dependency&gt;        <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;groupId&gt;org.codehaus.xfire&lt;/groupId&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;artifactId&gt;xfire-all&lt;/artifactId&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;version&gt;1.2.6&lt;/version&gt;         <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/dependency&gt;</font></p>
</blockquote>
<p>see, actually i’ve imported XFire lib twice(1.1.1 &amp; 1.2.6), that’s the reason why the Java complains, we just need the dependency in green.</p>
<p>good luck.</p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2008/12/a-xfire-error-and-solution/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASP.net 发布的小问题</title>
		<link>http://googlestop.com/blog/2008/11/aspnet-%e5%8f%91%e5%b8%83%e7%9a%84%e5%b0%8f%e9%97%ae%e9%a2%98/</link>
		<comments>http://googlestop.com/blog/2008/11/aspnet-%e5%8f%91%e5%b8%83%e7%9a%84%e5%b0%8f%e9%97%ae%e9%a2%98/#comments</comments>
		<pubDate>Thu, 20 Nov 2008 13:13:34 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming Language]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/2008/11/20/aspnet-%e5%8f%91%e5%b8%83%e7%9a%84%e5%b0%8f%e9%97%ae%e9%a2%98/</guid>
		<description><![CDATA[Exception Details: System.Data.SqlClient.SqlException: Failed to update database &#8220;C:InetpubwwwrootSSRAPP_DATAASPNETDB.MDF&#8221; because the database is read-only. 上面的例子通常发生在publish一个新开发的web application的时候，解决方法很简单：即修改App_Data这个目录的Security属性，加入用户&#8221;NETWORK SERVICE&#8221;，并设置该用户可以对这个目录有Write权限。 [ad]]]></description>
			<content:encoded><![CDATA[<p>Exception Details: System.Data.SqlClient.SqlException: Failed to update database &#8220;C:InetpubwwwrootSSRAPP_DATAASPNETDB.MDF&#8221; because the database is read-only.</p>
<p>上面的例子通常发生在publish一个新开发的web application的时候，解决方法很简单：即修改App_Data这个<strong>目录</strong>的Security属性，加入用户&#8221;NETWORK SERVICE&#8221;，并设置该用户可以对这个目录有Write权限。</p>
<p>[ad]</p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2008/11/aspnet-%e5%8f%91%e5%b8%83%e7%9a%84%e5%b0%8f%e9%97%ae%e9%a2%98/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# LDAP Wrapper</title>
		<link>http://googlestop.com/blog/2008/11/c-ldap-wrapper/</link>
		<comments>http://googlestop.com/blog/2008/11/c-ldap-wrapper/#comments</comments>
		<pubDate>Sat, 15 Nov 2008 09:01:42 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming Language]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/2008/11/15/c-ldap-wrapper/</guid>
		<description><![CDATA[Before you try to run the following code, please download Novel LDAP lib: http://forge.novell.com/modules/xfcontent/downloads.php/ldapcsharp/ldapcsharp/CsharpLDAP-v2.1.10/ using System; using System.Collections.Generic; using System.Text; using Novell.Directory.Ldap; namespace LDAPUtility { class LDAPUtil { private string ldapHost = "ssuzdc3"; private int ldapPort = 389; LdapConnection ldapConn = null; private void Connect() { try { // Creating an LdapConnection instance ldapConn = [...]]]></description>
			<content:encoded><![CDATA[<p>Before you try to run the following code, please download Novel LDAP lib:</p>
<p><a title="http://forge.novell.com/modules/xfcontent/downloads.php/ldapcsharp/ldapcsharp/CsharpLDAP-v2.1.10/" href="http://forge.novell.com/modules/xfcontent/downloads.php/ldapcsharp/ldapcsharp/CsharpLDAP-v2.1.10/">http://forge.novell.com/modules/xfcontent/downloads.php/ldapcsharp/ldapcsharp/CsharpLDAP-v2.1.10/</a></p>
<pre>
using System;
using System.Collections.Generic;
using System.Text;
using Novell.Directory.Ldap;

namespace LDAPUtility
{
    class LDAPUtil
    {
        private string ldapHost = "ssuzdc3";
        private int ldapPort = 389;
        LdapConnection ldapConn = null;

        private void Connect()
        {
            try
            {
                // Creating an LdapConnection instance
                ldapConn = new LdapConnection();

                // Connect function will create a socket connection to the server
                ldapConn.Connect(ldapHost, ldapPort);

                // Bind function with null user dn and password value will perform anonymous bind
                // to LDAP server
                ldapConn.Bind(null, null);
            }
            catch (Exception e)
            {
                // failed to connect to server
            }
        }

        private void Disconnect()
        {
            ldapConn.Disconnect();
            ldapConn = null;
        }

        public string GetSupervisor(string id)
        {
            Connect();

            string boss = "";
            try
            {
                LdapSearchResults lsc = ldapConn.Search("OU=Users,OU=Suzhou,DC=charry,DC=org",
                LdapConnection.SCOPE_ONE,
                "sAMAccountName=" + id,
                null,
                false);

                while (lsc.hasMore())
                {
                    LdapEntry nextEntry = null;
                    try
                    {
                        nextEntry = lsc.next();
                    }
                    catch (LdapException e)
                    {
                        // Exception is thrown, go for next entry
                        continue;
                    }

                    LdapAttribute attribute = nextEntry.getAttribute("manager");
                    boss = attribute.StringValue;
                }
            }
            catch (Exception e)
            {
                // exception
            }

            Disconnect();

            return GetAMAcountName(boss);
        }

        private string GetFullName(string id)
        {
            // CN=Wang, Charry,OU=Users,OU=Suzhou,DC=charry,DC=org
            int end = id.IndexOf("OU=");

            id = id.Substring(3, end - 4);
            id = id.Replace("\", "");

            return id;
        }

        // convert distinguished name to AMAcountName
        public string GetAMAcountName(string id)
        {
            id = GetFullName(id);
            Connect();

            string tmp = "";
            try
            {
                LdapSearchResults lsc = ldapConn.Search("OU=Users,OU=Suzhou,DC=charry,DC=org",
                LdapConnection.SCOPE_ONE,
                "displayName=" + id,
                null,
                false);

                while (lsc.hasMore())
                {
                    LdapEntry nextEntry = null;
                    try
                    {
                        nextEntry = lsc.next();
                    }
                    catch (LdapException e)
                    {
                        // Exception is thrown, go for next entry
                        continue;
                    }

                    LdapAttribute attribute = nextEntry.getAttribute("sAMAccountName");
                    tmp = attribute.StringValue;
                }
            }
            catch (Exception e)
            {
                // exception
            }

            Disconnect();

            return tmp;
        }

        public string GetDisplayName(string id)
        {
            Connect();
            string name = "";
            // get fullname

            try
            {
                LdapSearchResults lsc = ldapConn.Search("OU=Users,OU=Suzhou,DC=charry,DC=org",
                LdapConnection.SCOPE_ONE,
                "sAMAccountName=" + id,
                null,
                false);

                while (lsc.hasMore())
                {
                    LdapEntry nextEntry = null;
                    try
                    {
                        nextEntry = lsc.next();
                    }
                    catch (LdapException e)
                    {
                        // Exception is thrown, go for next entry
                        continue;
                    }

                    
                    LdapAttribute attribute = nextEntry.getAttribute("displayName");
                    name = attribute.StringValue;
                }
            }
            catch (Exception e)
            {
                // exception
            }

            Disconnect();

            return name;
        }

        public string GetEmail(string id)
        {
            Connect();
            string email = "";
            try
            {
                LdapSearchResults lsc = ldapConn.Search("OU=Users,OU=Suzhou,DC=charry,DC=org",
                LdapConnection.SCOPE_ONE,
                "sAMAccountName=" + id,
                null,
                false);

                while (lsc.hasMore())
                {
                    LdapEntry nextEntry = null;
                    try
                    {
                        nextEntry = lsc.next();
                    }
                    catch (LdapException e)
                    {
                        // Exception is thrown, go for next entry
                        continue;
                    }

                    LdapAttribute attribute = nextEntry.getAttribute("mail");
                    email = attribute.StringValue;
                }
            }
            catch (Exception e)
            {
                // exception
            }

            Disconnect();

            return email;
        }

        public static void test()
        {
            string ldapHost = "ssuzdc3";
            int ldapPort = 389;

            try
            {
                // Creating an LdapConnection instance
                LdapConnection ldapConn = new LdapConnection();

                // Connect function will create a socket connection to the server
                ldapConn.Connect(ldapHost, ldapPort);

                // Bind function with null user dn and password value will perform anonymous bind
                // to LDAP server
                ldapConn.Bind(null, null);

                // Searches in the Marketing container and return all child entries just below this
                // container i.e. Single level search
                LdapSearchResults lsc = ldapConn.Search("OU=Users,OU=Suzhou,DC=charry,DC=org",
                LdapConnection.SCOPE_ONE,
                "sAMAccountName=qinick",
                null,
                false);

                while (lsc.hasMore())
                {
                    LdapEntry nextEntry = null;
                    try
                    {
                        nextEntry = lsc.next();
                    }
                    catch (LdapException e)
                    {
                        Console.WriteLine("Error: " + e.LdapErrorMessage);
                        // Exception is thrown, go for next entry
                        continue;
                    }

                    Console.WriteLine("n" + nextEntry.DN);
                    LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
                    System.Collections.IEnumerator ienum = attributeSet.GetEnumerator();
                    while (ienum.MoveNext())
                    {
                        LdapAttribute attribute = (LdapAttribute)ienum.Current;
                        string attributeName = attribute.Name;
                        string attributeVal = attribute.StringValue;
                        Console.WriteLine(attributeName + "value:" + attributeVal);
                    }
                }
                ldapConn.Disconnect();

            }
            catch (Exception e)
            {
                string x = e.Message;
            }

            Console.Read();
        }
    }
}
</pre>
<p>[ad]</p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2008/11/c-ldap-wrapper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Problem with JFreechart</title>
		<link>http://googlestop.com/blog/2008/07/problem-with-jfreechart/</link>
		<comments>http://googlestop.com/blog/2008/07/problem-with-jfreechart/#comments</comments>
		<pubDate>Mon, 07 Jul 2008 15:21:22 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[AWT]]></category>
		<category><![CDATA[JFreeChart]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/2008/07/07/problem-with-jfreechart/</guid>
		<description><![CDATA[一个基于Tomcat的程序里面用到了JFreeChart，偶尔用浏览器访问时，PC端安装的XManager的XServer会自动的打开，然后Tomcat就莫名其妙的挂掉。在没有安装XManager的PC上通常就不会出这种情况。查看一下log，如下： Can&#8217;t connect to X11 window server using &#8216;:0.0&#8242; as the value of the DISPLAY variable. 搜之，此乃awt的bug。加入以下参数启动即可： -Djava.awt.handless=true 如果是Tomcat，把上面的参数加到环境变量：CATALINA_OTPS里即可。 [ad]]]></description>
			<content:encoded><![CDATA[<p>一个基于Tomcat的程序里面用到了JFreeChart，偶尔用浏览器访问时，PC端安装的XManager的XServer会自动的打开，然后Tomcat就莫名其妙的挂掉。在没有安装XManager的PC上通常就不会出这种情况。查看一下log，如下：</p>
<blockquote><p>Can&#8217;t connect to X11 window server using &#8216;:0.0&#8242; as the value of the DISPLAY variable.</p></blockquote>
<p>搜之，此乃awt的bug。加入以下参数启动即可：</p>
<blockquote><p>-Djava.awt.handless=true</p></blockquote>
<p>如果是Tomcat，把上面的参数加到环境变量：CATALINA_OTPS里即可。</p>
<p>[ad]</p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2008/07/problem-with-jfreechart/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Upload the 3rd party artifact to local Archiva</title>
		<link>http://googlestop.com/blog/2008/04/upload-the-3rd-party-artifact-to-local-archiva/</link>
		<comments>http://googlestop.com/blog/2008/04/upload-the-3rd-party-artifact-to-local-archiva/#comments</comments>
		<pubDate>Fri, 11 Apr 2008 13:35:02 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Configuration]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/2008/04/11/upload-the-3rd-party-artifact-to-local-archiva/</guid>
		<description><![CDATA[Maven is a powerful build tool, more and more developers migrate to it, so do I. Below is the command for deploy the 3rd artifact to your local Archiva: mvn deploy:deploy-file -DrepositoryId=internal -Durl=http://ssuzsws02:8080/archiva/repository/internal -DgroupId=com.amd.sws -DartifactId=mysql-connector-java -Dversion=3.0.17 -Dpackaging=jar -Dfile=test.jar but before you issue this command, you should add the following lines to your local settings.xml &#60;servers&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>Maven is a powerful build tool, more and more developers migrate to it, so do I. Below is the command for deploy the 3rd artifact to your local Archiva:</p>
<p>mvn deploy:deploy-file -DrepositoryId=internal -Durl=<a href="http://ssuzsws02:8080/archiva/repository/internal">http://ssuzsws02:8080/archiva/repository/internal</a> -DgroupId=com.amd.sws -DartifactId=mysql-connector-java -Dversion=3.0.17 -Dpackaging=jar -Dfile=test.jar</p>
<p>but before you issue this command, you should add the following lines to your local settings.xml</p>
<pre>
&lt;servers&gt;
  &lt;server&gt;
   &lt;id&gt;internal&lt;/id&gt;
   &lt;username&gt;admin&lt;/username&gt;
   &lt;password&gt;mypassword&lt;/password&gt;
  &lt;/server&gt;
&lt;/servers&gt;
</pre>
<p>FYI.: when you upload your jar file to Archiva, you can&#8217;t see it immediately, please be patient and wait several minutes, the artifact list will be synced soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2008/04/upload-the-3rd-party-artifact-to-local-archiva/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hibernate, SocketTimeOutException错误</title>
		<link>http://googlestop.com/blog/2007/12/hibernate-sockettimeoutexception%e9%94%99%e8%af%af/</link>
		<comments>http://googlestop.com/blog/2007/12/hibernate-sockettimeoutexception%e9%94%99%e8%af%af/#comments</comments>
		<pubDate>Wed, 19 Dec 2007 15:49:49 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/2007/12/19/hibernate-sockettimeoutexception%e9%94%99%e8%af%af/</guid>
		<description><![CDATA[项目中用到Hibernate，部署的时候发现，过了一段时间后，Hibernate就不能正常工作了，时间很有规律，通常是在部署后的若干个小时。错误日志如下： ** BEGIN NESTED EXCEPTION ** java.net.SocketTimeoutException MESSAGE: Read timed out STACKTRACE: java.net.SocketTimeoutException: Read timed out     at java.net.SocketInputStream.socketRead0(Native Method)     at java.net.SocketInputStream.read(Unknown Source)     at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:1392)     at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:1539)     at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:1930)     at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1168)     at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1279)     at com.mysql.jdbc.MysqlIO.sqlQuery(MysqlIO.java:1225)     at com.mysql.jdbc.Connection.execSQL(Connection.java:2278)     at com.mysql.jdbc.Connection.execSQL(Connection.java:2237)     at com.mysql.jdbc.Connection.execSQL(Connection.java:2218)     at com.mysql.jdbc.Connection.commit(Connection.java:1155)     [...]]]></description>
			<content:encoded><![CDATA[<p>项目中用到Hibernate，部署的时候发现，过了一段时间后，Hibernate就不能正常工作了，时间很有规律，通常是在部署后的若干个小时。错误日志如下：</p>
<blockquote><p>** BEGIN NESTED EXCEPTION **</p>
<p>java.net.SocketTimeoutException<br />
MESSAGE: Read timed out</p>
<p>STACKTRACE:</p>
<p>java.net.SocketTimeoutException: Read timed out<br />
    at java.net.SocketInputStream.socketRead0(Native Method)<br />
    at java.net.SocketInputStream.read(Unknown Source)<br />
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:1392)<br />
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:1539)<br />
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:1930)<br />
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1168)<br />
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1279)<br />
    at com.mysql.jdbc.MysqlIO.sqlQuery(MysqlIO.java:1225)<br />
    at com.mysql.jdbc.Connection.execSQL(Connection.java:2278)<br />
    at com.mysql.jdbc.Connection.execSQL(Connection.java:2237)<br />
    at com.mysql.jdbc.Connection.execSQL(Connection.java:2218)<br />
    at com.mysql.jdbc.Connection.commit(Connection.java:1155)<br />
    at org.hibernate.transaction.JDBCTransaction.commitAndResetAutoCommit(JDBCTransaction.java:139)<br />
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:115)<br />
    at com.amd.BizB.test(BizB.java:27)<br />
    at org.apache.jsp.index_jsp._jspService(index_jsp.java:109)<br />
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)<br />
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)<br />
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:393)<br />
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:320)<br />
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)<br />
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)<br />
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)<br />
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)<br />
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)<br />
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)<br />
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)<br />
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)<br />
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)<br />
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)<br />
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)<br />
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:581)<br />
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)<br />
    at java.lang.Thread.run(Unknown Source)</p></blockquote>
<p>最后发现是由于配置文件Hibernate.cfg.xml没有写好，少加了若干的项(注意黑体部分)</p>
<p><strong>&lt;property name=&#8221;connection.autocommit&#8221;&gt;true&lt;/property&gt;</strong></p>
<p>&lt;property name=&#8221;connection.url&#8221;&gt;jdbc:mysql://ssuzsws01:3306/foo?<strong>autoReconnect=true</strong>&lt;/property&gt;</p>
<p>加了这些选项后，就正常了，希望对遇到类似问题的朋友有帮助。</p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2007/12/hibernate-sockettimeoutexception%e9%94%99%e8%af%af/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>为什么不用SEH</title>
		<link>http://googlestop.com/blog/2007/07/%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%8d%e7%94%a8seh/</link>
		<comments>http://googlestop.com/blog/2007/07/%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%8d%e7%94%a8seh/#comments</comments>
		<pubDate>Tue, 17 Jul 2007 01:55:35 +0000</pubDate>
		<dc:creator>Charry</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[VC]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://googlestop.com/blog/2007/07/16/%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%8d%e7%94%a8seh/</guid>
		<description><![CDATA[前些时候，在论坛上看到一个朋友说SEH怎么怎么不好，一定不要用它。其实存在即合理。就像GOTO，不能因为它破坏了程序的流程，就不用它，适当的使用，还是可以事半功倍的。 大家知道SEH是Windows操作系统提供的一种异常处理机制，它和C++无关。在Compiler编译的时候，就把这个机制加入了我们的程序中。在VC下可以用__try, __finally, __except, __leave等关键字来标识。由于SEH可以捕获硬件异常(Hardware Exception)和软件异常(Software Exception)，它比C++的异常机制能捕获更多的异常，所以有朋友不喜欢这点，认为它掩盖了错误。其实这种说法是也是合情合理的，毕竟掩盖错误不是最好的解决方案，找出问题的所在才是我们应该做的。可是在现实中，我们不可能找到所有的bug，或者由于时间的关系，来不及修补这个bug，不如先用SEH挡一挡，何尝不可。 就像我之前的一个项目，程序在一个地方偶尔会Crash掉，而且这个地方如果不能正常执行丝毫不影响整个程序的运作，不会对用户造成损失，在找出问题真正的原因之前，我们完全可以用SEH捕获异常。  下面的例子也是一个SEH优势的体现 BOOL SafeDiv(INT32 dividend, INT32 divisor, INT32 *pResult) {     __try     {         *pResult = dividend / divisor;     }     __except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ?              EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)     {         return FALSE;     }     return TRUE; } SafeDiv用来做除法操作，它的返回值指出函数是否执行成功。pResult指向最终的结果，如果不用SEH，这类Hardware Exception会导致程序Crash，这里引入了SEH，我们在发现有除零错误的时候，让函数返回FALSE，调用处通过检查函数的返回值就可以判断除法运算是否成功，没必要就因为一个除零错误导致程序Crash掉。 由于SEH是Windows操作系统特有的机制，所以它不适合用在那些跨平台的代码，这种情况不用也罢，既然SEH是一个Windows的一个很好的异常处理机制，我们虽不能滥用它，适当的、合理的使用还是值得推荐的。 P.S. For details [...]]]></description>
			<content:encoded><![CDATA[<p>前些时候，在论坛上看到一个朋友说SEH怎么怎么不好，一定不要用它。其实存在即合理。就像GOTO，不能因为它破坏了程序的流程，就不用它，适当的使用，还是可以事半功倍的。</p>
<p>大家知道SEH是Windows操作系统提供的一种异常处理机制，它和C++无关。在Compiler编译的时候，就把这个机制加入了我们的程序中。在VC下可以用__try, __finally, __except, __leave等关键字来标识。由于SEH可以捕获硬件异常(Hardware Exception)和软件异常(Software Exception)，它比C++的异常机制能捕获更多的异常，所以有朋友不喜欢这点，认为它掩盖了错误。其实这种说法是也是合情合理的，毕竟掩盖错误不是最好的解决方案，找出问题的所在才是我们应该做的。可是在现实中，我们不可能找到所有的bug，或者由于时间的关系，来不及修补这个bug，不如先用SEH挡一挡，何尝不可。</p>
<p>就像我之前的一个项目，程序在一个地方偶尔会Crash掉，而且这个地方如果不能正常执行丝毫不影响整个程序的运作，不会对用户造成损失，在找出问题真正的原因之前，我们完全可以用SEH捕获异常。</p>
<p> 下面的例子也是一个SEH优势的体现</p>
<p>BOOL SafeDiv(INT32 dividend, INT32 divisor, INT32 *pResult)<br />
{<br />
    __try<br />
    {<br />
        *pResult = dividend / divisor;<br />
    }<br />
    __except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ?<br />
             EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)<br />
    {<br />
        return FALSE;<br />
    }<br />
    return TRUE;<br />
}</p>
<p>SafeDiv用来做除法操作，它的返回值指出函数是否执行成功。pResult指向最终的结果，如果不用SEH，这类Hardware Exception会导致程序Crash，这里引入了SEH，我们在发现有除零错误的时候，让函数返回FALSE，调用处通过检查函数的返回值就可以判断除法运算是否成功，没必要就因为一个除零错误导致程序Crash掉。</p>
<p>由于SEH是Windows操作系统特有的机制，所以它不适合用在那些跨平台的代码，这种情况不用也罢，既然SEH是一个Windows的一个很好的异常处理机制，我们虽不能滥用它，适当的、合理的使用还是值得推荐的。</p>
<p>P.S.<br />
For details about SEH, check this: <a href="http://www.google.com/search?hl=en&amp;q=Programming+Applications+for+Microsoft+Windows">http://www.google.com/search?hl=en&amp;q=Programming+Applications+for+Microsoft+Windows</a></p>
]]></content:encoded>
			<wfw:commentRss>http://googlestop.com/blog/2007/07/%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%8d%e7%94%a8seh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

