Romotc‘s gae blog http://www.romotc.com/ Life just a dish of gossip 2010-03-16T11:03:53Z romotc http://www.romotc.com/entry/ vps共享ip方法 说说如何能让外网访问内网的IIS,这个应该是你虚拟机网络设置的问题,虚拟机有4种网络连接模式: 
1、Bridge:这种方式最简单,直接将虚拟网卡桥接到一个物理网卡上面,和linux下一个网卡 绑定两个不同地址类似,实际上是将网卡设置为混杂模式,从而达到侦听多个IP的能力. 
在此种模式下,虚拟机内部的网卡(例如linux下的eth0)直接连到了物理网卡所在的网络上,可以想象为虚拟机和host机处于对等的地位,在网络关系上是平等的,没有谁在谁后面的问题. 
使用这种方式很简单,前提是你可以得到1个以上的地址.对于想进行种种网络实验的朋友不太适合,因为你无法对虚拟机的网络进行控制,它直接出去了. 

2、nat方式:这种方式下host内部出现了一个虚拟的网卡vmnet8(默认情况下),如果你有过做nat服务器的经验,这里的vmnet8就相当于连接到内网的网卡,而虚拟机本身则相当于运行在内网上的机器,虚拟机内的网卡(eth0)则独立于vmnet8. 
你会发现在这种方式下,vmware自带的dhcp会默认地加载到vmnet8界面上,这样虚拟机就可以使用dhcp服务.更为重要的是,vmware自带了nat服务,提供了从vmnet8到外网的地址转 换,所以这种情况是一个实实在在的nat服务器在运行,只不过是供虚拟机用的. 很显然,如果你只有一个外网地址,此种方式很合适. 

3、hostonly: 
这应该是最为灵活的方式,有兴趣的话可以进行各种网络实验.和nat唯一的不同的是,此种方式下,没有地址转换服务,因此,默认情况下,虚拟机只能到主机访问,这也是hostonly的名字的意义. 默认情况下,也会有一个dhcp服务加载到vmnet1上.这样连接到vmnet8上的虚拟机仍然可以设置成dhcp,方便系统的配置. 
是不是这种方式就没有办法连接到外网呢,当然不是,事实上,这种方式更为灵活,你可以使用自己的方式,从而达到最理想的配置,例如: 
a.使用自己dhcp服务:首先停掉vmware自带的dhcp服务,使dhcp服务更为统一. 
b.使用自己的nat,方便加入防火墙.windows host可以做nat的方法很多,简单的如windows xp的internet共享,复杂的如windows server里的nat服务. 
c. 使用自己的防火墙.因为你可以完全控制vmnet1,你可以加入(或试验)防火墙在vmnet1和外网的网卡间. 
从以上可以看出,hostonly这种模式和普通的nat server带整个内网上网的情形类似,因此你可以方便的进行与之有关的实验,比如防火强的设置等 

4、not use方式 
既是不使用网络,虚拟系统为一个单机. 
========================================================================= 
1、Bridge模式(一切都跟host一样,只有ip不能与host相同) 
ip 192.168.39.222 
netmask:255.255.252.0 
gateway:192.168.39.254 
Primary nameserve:192.168.39.252 

2、NAT模式 
首先在host中查看VMnet8的IP(e.g. 192.168.255.1). 
启动VMware,点Edit下Virtual Network Setting… ,弹出Virtual network Editor对话框; 
查看NAT选项卡,记录NAT的Gateway IP address:192.168.255.2 
在config中,填写: 
ip:192.168.255.5(与192.168.255.1在同一个网段的不同地址) 
netmask:255.255.255.0(与192.168.255.1的隐码相同) 
Gateway IP:填写VMware中的NAT网关192.168.255.2 
Primary nameserver:填写与主机中一样的网关192.168.39.252,这样就可以上网冲浪了. 
如果填写192.168.255.1,则不能连上外网.这里也可以不停,总之不能写错误的地址 

3、hostonly模式 
(1)查看你的连接外网的网卡的属性,选择“高级”标签,设置成允许共享,并设定允许的网络接口为VMNET1 

(2)再插看一下你的VMnet1 的属性,看一下TCP/IP协议的设置,你发现已经被自动设置为 

192.168.0.1/255.255.255.0

(3)windows下的设置完成,转入到跑linux的虚拟机.将你的eth0的ip地址设置为静态的(如果安装时没有选静态的话) . 

按红帽子图标->系统设置->网络(或其它你了解的方法) 
ip: 192.168.0.2(或其它在此网段上的地址) 
netmask: 255.255.255.0 
default gateway: 192.168.0.1 (VMnet1的地址) 
dns:输入你自己的DNS (host中用的DNS) 
保存设置.如果你还没有设置好主机名称: 
cd /etc/sysconfig 
vi network 
编辑HOSTNAME 
cd /etc 
vi hosts 
加入: 
192.168.0.2 yourhostname 
重新启动服务 
su 
/sbin/service network restart 
(4)测试一下 
网关: ping 192.168.0.1 
dns: ping dnsserver 

============================= 
(1)Bridged方式 
用这种方式,虚拟系统的IP可设置成与本机系统在同一网段,虚拟系统相当于网络内的一台.独立的机器,与本机共同插在一个Hub上,网络内其他机器可访问虚拟系统,虚拟系统也可访问网络内其他机器,当然与本机系统的双向访问也不成问题. 

(2)NAT方式 
这种方式也可以实现本机系统与虚拟系统的双向访问.但网络内其他机器不能访问虚拟系统,虚拟系统可通过本机系统用NAT协议访问网络内其他机器.NAT方式的IP地址配置方法:虚拟系统先用DHCP自动获得IP地址,本机系统里的VMware services会为虚拟系统分配一个IP,之后如果想每次启动都用固定IP的话,在虚拟系统里直接设定这个IP即可. 

(3)host-only方式 
顾名思义这种方式只能进行虚拟机和主机之间的网络通信,既网络内其他机器不能访问虚拟系统,虚拟系统也不能访问其他机器. 

(4)not use方式 
既是不使用网络,虚拟系统为一个单机. 

一般来说,Bridged方式最方便好用.但如果本机系统是win2000而网线没插(或者根本没有网卡),网络很可能不可用(大部分用PCI网卡的机器都如此),此时就只能用NAT方式或host-only,之前所说的那两块虚拟网卡就是适应这两种网络准备的.

本文网址:http://www.romotc.com/20100316/41001.html

]]>
None 2010-03-16T11:03:53Z
http://www.romotc.com/entry/java-bean-rules JavaBean不得不知的几点规范 1。为 JavaBean 创建属性时,必须牢记:缩略语通常被视为一个独立的单词,而不是单个字母。例如,URL 对应的属性名应该用 url,相应的 getUrl()/setUrl(),所以 ID 还是用 id 作为属性吧,相应的 getId()/setId()。

2。第二个字母为大写的属性名要区别对待。如果属性名的第二个字母是大写的,那么该属性名直接用作 getter/setter 方法中 get/set 的后部分,就是说大小写不变。这就是为什么 sName 对应的存取方法是 getsName()/setsName() 的原因,不能不说这条规则很令人费解。

3。属性是首字母大写,次字母小写是,你永远都找不到它的 getter/setter 方法的,对这个属性的使用是会害人的。

4。对于 boolean 类型属性的 getter 方法是 isXxx() 还是 getXxx() 就自己决定了,isXxx() 应该更接近于自然语言,更顺溜些。

5。还有一个我们很少碰触到的是关于可索引属性的 getter/setter 方法(这方面 C# 表现的比 Java 要优秀),比如有属性

 

private OrderItem[] orderItem;

 

那它相应的 getter/setter 除常见的两个外,还有带索引参数的两个版本,如下:

public OrderItem[] getOrderItem();
public void setOrderItem(OrderItem[] newArray);
public OrderItem[] getOrderItem(int index);
public void setOrderItem(int index, OrderItem orderItem);

 

相关阅读:

本文网址:http://www.romotc.com/2010/02/28/java-bean-rules.html

]]>
None 2010-02-28T00:40:52Z
http://www.romotc.com/entry/gae-sdk1.3 gae sdk1.3发布支持大文件上传并增加1GB容量
原本AppEngine提供1GB的datastore來儲存,但是圖片檔案一樣是儲存在datastore。這次AppEngine直接再送1GB的datastore儲存空間,而且程式撰寫起來更是異常的簡單。不過不知道是否支援304的header就是了。單檔可以儲存50MB,真是超級大的。

其實看到這個消息個人感覺蠻無言的,因為前天才剛寫完圖片上傳的程式(詳見美食邦的圖片網址),並且handle了304的request header。

相关阅读:

本文网址:http://www.romotc.com/2010/01/2/gae-sdk1.3.html

]]>
None 2010-01-02T13:17:17Z
http://www.romotc.com/entry/myeclipse6-subscriptionj-code-2012 myeclipse6 2012年注册码

myeclipse 6.0 注册码 2012年过期 绝对可用,www.bigdogonline.cn人品担保..
myeclipse 6.0 注册码 过期时间2012年
user:googlebibaiduhao
Serial:tLR8ZC-855575-67547956337287439

user:baidubigooglehao
Serial:oLR8ZC-855575-6754795423520224

本文网址:http://www.romotc.com/2010/01/2/myeclipse6-subscriptionj-code-2012.html

]]>
None 2010-01-02T13:02:22Z
http://www.romotc.com/entry/ gae本地调试查看datastore和queuetask信息 相关阅读:

本文网址:http://www.romotc.com/2010012/29002.html

]]>
None 2010-01-02T12:29:36Z
http://www.romotc.com/entry/wave-invitation 8个wave邀请,先到先得啦。 之前就听说过号称很神奇的wave,昨天没事随手申请了一下,没想到今天就收到了google wave team的邮件说申请成功了。

进去看了几段视频果然很强大,统共有8个邀请 欢迎大家跟我一起wave!

 

相关阅读:

本文网址:http://www.romotc.com/2009/12/18/wave-invitation.html

]]>
None 2009-12-18T14:14:30Z
http://www.romotc.com/entry/rubbish-yone-host 超烂的炎黄空间 这一个月被炎黄折腾的没脾气了,公司大了服务确实是越来越差!

这个月一来接到客户的投诉电话不下15次,白天的时候空间慢的像蜗牛。下了班给他们客服留言,不回答!留言在有问必答,竟然回复我说现在访问挺快的!NND,我一看就来气了。抄起电话,给他们打电话。打通了,客服人员竟然还是那句话,让我在慢的时候给他们打电话。

炎黄的客服有毛病啊,自己的空间负载是多少不知道啊。竟然能想到这样推脱的办法。真是服气了。

yone的空间不是一般的差,我在上面买了2个空间。其中企业站的因为存在文件上传下载的情况,精确的流量是多少我不好确定,但Ip数量已经是少的不能再少了。另外一个放的是一个半死不活的网站,凭借一个比较好的关键词和以前搜集的一些文章每天只保持着数百的访问量。就是这样小流量的网站访问速度就慢的要死,国内空间比国外空间的访问速度还能慢一个数量级!在打过N个电话之后彻底没脾气了,看来最后的2个月也是熬不过去了。换服走人!

朋友们谁有比较好用的国内服务器给推荐一下,国内网通线路需要支持.net2.0。先谢过

本文网址:http://www.romotc.com/2009/11/27/rubbish-yone-host.html

]]>
None 2009-11-27T13:42:58Z
http://www.romotc.com/entry/ 信用卡丢失后在三家银行的不同遭遇 最近忙的昏天黑地的,脑袋有点不太好用。

没办法信用卡号码被别人知道是件比较闹心的事情。

倒不担心在国内能有什么问题,国内的网银大部分都是需要输入密码才可以消费的(招商的貌似跟国际接轨不需要输密码@淘宝)。但在国外情况就不一样了,只要知道卡号、有效年月和卡背后的三位数字就可以消费。

给三家银行打电话吧,看看还有什么补救的办法没。

兴业银行客服:

态度倒是还蛮好,但说起visa以及境外消费客服大妹就有点摸不着头脑了。刚开始还非常好心的劝我说,您发现卡片消费有异常可以联系客服...WK..这样都行?被别人盗用了卡银行还能负责了?

算了,算了。反正这张卡也不常用,注销掉吧。一说注销客服大妹就开始劝我了,说兴业的积分活动怎么怎么好。末了还帮我查了积分,还没刷几次竟然有1万多积分了。稍微差了一下,貌似一万积分也干不了啥。抵住诱惑,坚决注销! 大妹没办法,说你先冷静冷静想想吧,5天之后会有人联系你(借口是我没有权限,客服专员会在5个工作日之内联系你~).

招商银行客服:

招行的客服电话打起来比较顺心,办事也很利索。说明来意之后,客服妹妹很快就给我指了2条明路:

1.使用招行的visa验证服务:可以解决境外消费的安全顾虑。

2.对于国内网上消费的担心可以通过关闭网上支付功能。 虽然客服MM对visa验证服务的理解还不太透彻,但总算给指了条道。顺着这条道我google到visa验证服务的一些信息:

(3)开通VISA验证服务之后,我的卡片只能在有参加VISA验证服务的网络商店上购物吗? 您开通此服务的VISA信用卡可以在任何境外商店上进行网络购物,不止限于已经加入VISA验证服务的网络商店,因为此项服务只是让您的网络购物更加安全,而不会限制您的购物范围。

(4)、VISA验证服务容易使用吗? 非常容易,您甚至感觉不到它的存在。您只需输入密码便可以 完成验证,就好像您在ATM自动提款机使用时需输入密码一样。 虽然最终也不能100%的解决境外消费的安全隐患(在没有启用visa验证服务的网站还是可以不输入密码直接消费),但至少可以看出招行对用户使用信用卡安全方面的用心。

 

中信客服:

因为之前跟中信的客服打过一次交道,在打中信客服电话之前已经有了心理准备。在听了N个提示音和广告、拨了N个转接短号之后终于进到客服排队。电话显示3分钟了,还没通?我等...4分钟...还不通?我等等等...5分钟...我K!还没人理我?连语音系统都不忍心了,提示说麻烦留下信用卡号稍后让客服人员给我回电。我K,你tmd就不能通过我手机号码识别出来我是哪个啊?这么长的信用卡号我哪能记住。

不行啊,为了我随时可能被盗用的白花花的银子,这气还得接着受啊。

再拨! 中信的语音系统真是个迷宫,竟然从入口找不到我上次走的那条路了。好不容易又到一个人工客服的入口,赶紧的我抢着排队!哎,这次倒是挺快就排上了。好,松一口气,对这话筒用非常舒缓的语气对客服MM说明我的来意。貌似这MM今天心情不好,但还是非常有礼貌的克制了一下自己的脾气给我解答:

MM:你当时通过柜台开通了网上支付了吗?如果开通了就可以网上支付的!如果没有开通,我也帮不上你...

我抢断:我已经开通网上支付了,不过我现在要关闭它..visa能不能关闭网上支付功能啊?

MM:...我帮不上你忙....那样你可以拨打95558 然后1103问他们一下看能不能做... 我迷惑:(难道我拨的电话不是95558,这MM不是信用卡系统的?)哦,那我打他们电话问一下吧。

挂了电话一看,我K刚才明明拨的就是95558嘛?都是中信客服,干么还分这么清楚呢?

因为之前就有心理准备 另加 我今天超有耐心,我还拨这该死的95558。

感谢刚才那个客服MM,有了她的指导总算不用走迷宫了。我95558后直接110,通了。??这么放的广告是啥基金证券??直接110也能走错?不管了,不听广告直接3. 进去了...等待...排队... 通了! 把一番话再次回放给这个客服MM听了一遍,这MM倒是挺通情达理外加。简单聊了几句大致了解中信这方面是没啥好办法。只能销卡(销卡也是蜗牛般的慢),如果对资金安全特别担心(你要是不担心 期间损失了钱肯定是你自己扛着)可以申请挂失(60快大洋)。NND 挂失就要60,你tm的跟小偷是一家的咋地?坐地为王,交60快保护费才能免自己损失!

 

对用卡人的一点建议:

1.如果你非常讨厌麻烦且没有足够的自信和精力去跟银行交涉,请使用密码而非签名。

2.visa卡拿到手之后拿小刀把卡背面的3位数字挂掉。这样只有自己知道这三位数字,即使别人拿到你的卡或者卡片丢失也不必担心卡片被盗用。

3.引用卡号码、有效年月、身份证号码也属机密信息!甚至在国内都不需要卡片后面的三位数字,只要知道卡号以及有效年月和身份证号码就可以购买机票... 总是信用卡是个非常危险的东西...

本文网址:http://www.romotc.com/?p=19001

]]>
None 2009-11-21T13:11:40Z
http://www.romotc.com/entry/linux-tomcat-basedir-environment-variable linux安装tomcat报The BASEDIR environment variable is not defined correctly

解压tomcat,export JAVA_HOME之后启动tomcat莫名其妙的报错:

The BASEDIR environment variable is not defined correctly This environment variable is needed to run this program

把$CATALINA_HOME/bin目录下所有.sh文件添加一个可执行权限即可

本文网址:http://www.romotc.com/2009/11/4/linux-tomcat-basedir-environment-variable.html

]]>
None 2009-11-04T09:41:12Z
http://www.romotc.com/entry/ gae报错:javax.swing.tree.TreeNode is a restricted class的解决办法 报错信息:

javax.swing.tree.TreeNode is a restricted class. Please see the Google App Engine developer's guide for more details.

 

问题原因:

freemarker使用到了gae不允许的class

 

解决办法:

工程内新建freemarker.core.TextBlock覆盖freemarker类

具体代码如下:package freemarker.core;

 

import java.io.IOException;

 

import freemarker.core.Comment;

import freemarker.core.Environment;

import freemarker.core.LibraryLoad;

import freemarker.core.Macro;

import freemarker.core.TemplateElement;

 

/**

* A TemplateElement representing a block of plain text.

*

* @version $Id: TextBlock.java,v 1.17 2004/01/06 17:06:42 szegedia Exp $

*/

public final class TextBlock extends TemplateElement

{

private static final char[] EMPTY_CHAR_ARRAY = new char[0];

static final TextBlock EMPTY_BLOCK = new TextBlock(EMPTY_CHAR_ARRAY, false);

// We're using char[] instead of String for storing the text block because

// Writer.write(String) involves copying the String contents to achar[]

// using String.getChars(), and then calling Writer.write(char[]).By

// using Writer.write(char[]) directly, we avoid array copying on each

// write.

private char[] text;

private final boolean unparsed;

 

public TextBlock(String text)

{

this(text, false);

}

 

public TextBlock(String text, boolean unparsed)

{

this(text.toCharArray(), unparsed);

}

 

private TextBlock(char[] text, boolean unparsed)

{

this.text = text;

this.unparsed = unparsed;

}

 

/**

* Simply outputs the text.

*/

public void accept(Environment env) throws IOException

{

env.getOut().write(text);

}

 

public String getCanonicalForm()

{

String text = new String(this.text);

if (unparsed)

{

return "<#noparse>" + text + "";

}

return text;

}

 

public String getDescription()

{

String s = new String(text).trim();

if (s.length() == 0)

{

return "whitespace";

}

if (s.length() > 20)

{

s = s.substring(0, 20) + "...";

s = s.replace('\n', ' ');

s = s.replace('\r', ' ');

}

return "text block (" + s + ")";

}

 

TemplateElement postParseCleanup(boolean stripWhitespace)

{

if (text.length == 0)

return this;

int openingCharsToStrip = 0, trailingCharsToStrip = 0;

boolean deliberateLeftTrim = deliberateLeftTrim();

boolean deliberateRightTrim = deliberateRightTrim();

if (!stripWhitespace || text.length == 0)

{

return this;

}

if (parent.parent == null && previousSibling() == null)

return this;

if (!deliberateLeftTrim)

{

trailingCharsToStrip = trailingCharsToStrip();

}

if (!deliberateRightTrim)

{

openingCharsToStrip = openingCharsToStrip();

}

if (openingCharsToStrip == 0 && trailingCharsToStrip == 0)

{

return this;

}

this.text = substring(text, openingCharsToStrip, text.length

- trailingCharsToStrip);

if (openingCharsToStrip > 0)

{

this.beginLine++;

this.beginColumn = 1;

}

if (trailingCharsToStrip > 0)

{

this.endColumn = 0;

}

return this;

}

 

/**

* Scans forward the nodes on the same line to see whether there is a

* deliberate left trim in effect. Returns true if the left trim was

* present.

*/

private boolean deliberateLeftTrim()

{

boolean result = false;

for (TemplateElement elem = this.nextTerminalNode(); elem != null

&& elem.beginLine == this.endLine; elem = elem

.nextTerminalNode())

{

if (elem instanceof TrimInstruction)

{

TrimInstruction ti = (TrimInstruction) elem;

if (!ti.left && !ti.right)

{

result = true;

}

if (ti.left)

{

result = true;

int lastNewLineIndex = lastNewLineIndex();

if (lastNewLineIndex >= 0 || beginColumn == 1)

{

char[] firstPart = substring(text, 0,

lastNewLineIndex + 1);

char[] lastLine = substring(text, 1 + lastNewLineIndex);

if (trim(lastLine).length == 0)

{

this.text = firstPart;

this.endColumn = 0;

} else

{

int i = 0;

while (Character.isWhitespace(lastLine[i]))

{

i++;

}

char[] printablePart = substring(lastLine, i);

this.text = concat(firstPart, printablePart);

}

}

}

}

}

if (result)

{

}

return result;

}

 

/**

* Checks for the presence of a t or rt directive on the same line. Returns

* true if the right trim directive was present.

*/

private boolean deliberateRightTrim()

{

boolean result = false;

for (TemplateElement elem = this.prevTerminalNode(); elem != null

&& elem.endLine == this.beginLine; elem = elem

.prevTerminalNode())

{

if (elem instanceof TrimInstruction)

{

TrimInstruction ti = (TrimInstruction) elem;

if (!ti.left && !ti.right)

{

result = true;

}

if (ti.right)

{

result = true;

int firstLineIndex = firstNewLineIndex() + 1;

if (firstLineIndex == 0)

{

return false;

}

if (text.length > firstLineIndex

&& text[firstLineIndex - 1] == '\r'

&& text[firstLineIndex] == '\n')

{

firstLineIndex++;

}

char[] trailingPart = substring(text, firstLineIndex);

char[] openingPart = substring(text, 0, firstLineIndex);

if (trim(openingPart).length == 0)

{

this.text = trailingPart;

this.beginLine++;

this.beginColumn = 1;

} else

{

int lastNonWS = openingPart.length - 1;

while (Character.isWhitespace(text[lastNonWS]))

{

lastNonWS--;

}

char[] printablePart = substring(text, 0, lastNonWS + 1);

if (trim(trailingPart).length == 0)

{

// THIS BLOCK IS HEINOUS! THERE MUST BE ABETTER WAY!

// REVISIT (JR)

boolean trimTrailingPart = true;

for (TemplateElement te = this.nextTerminalNode(); te != null

&& te.beginLine == this.endLine; te = te

.nextTerminalNode())

{

if (te.heedsOpeningWhitespace())

{

trimTrailingPart = false;

}

if (te instanceof TrimInstruction

&& ((TrimInstruction) te).left)

{

trimTrailingPart = true;

break;

}

}

if (trimTrailingPart)

trailingPart = EMPTY_CHAR_ARRAY;

}

this.text = concat(printablePart, trailingPart);

}

}

}

}

return result;

}

 

/*

* private String leftTrim(String s) { int i =0; while (i

* (!Character.isWhitespace(s.charAt(i))) break; ++i; } return

* s.substring(i); }

*/

private int firstNewLineIndex()

{

String content = new String(text);

int newlineIndex1 = content.indexOf('\n');

int newlineIndex2 = content.indexOf('\r');

int result = newlineIndex1 >= 0 ? newlineIndex1 : newlineIndex2;

if (newlineIndex1 >= 0 && newlineIndex2 >= 0)

{

result = Math.min(newlineIndex1, newlineIndex2);

}

return result;

}

 

private int lastNewLineIndex()

{

String content = new String(text);

return Math.max(content.lastIndexOf('\r'), content.lastIndexOf('\n'));

}

 

/**

* figures out how many opening whitespace characters to strip in the

* post-parse cleanup phase.

*/

private int openingCharsToStrip()

{

int newlineIndex = firstNewLineIndex();

if (newlineIndex == -1 && beginColumn != 1)

{

return 0;

}

++newlineIndex;

if (text.length > newlineIndex)

{

if (newlineIndex > 0 && text[newlineIndex - 1] == '\r'

&& text[newlineIndex] == '\n')

{

++newlineIndex;

}

}

if (new String(text).substring(0, newlineIndex).trim().length() > 0)

{

return 0;

}

// We look at the preceding elements on the line to see if we should

// strip the opening newline and any whitespace preceding it.

for (TemplateElement elem = this.prevTerminalNode(); elem != null

&& elem.endLine == this.beginLine; elem = elem

.prevTerminalNode())

{

if (elem.heedsOpeningWhitespace())

{

return 0;

}

}

return newlineIndex;

}

 

/**

* figures out how many trailing whitespace characters to strip in the

* post-parse cleanup phase.

*/

private int trailingCharsToStrip()

{

String content = new String(text);

int lastNewlineIndex = lastNewLineIndex();

if (lastNewlineIndex == -1 && beginColumn != 1)

{

return 0;

}

String substring = content.substring(lastNewlineIndex + 1);

if (substring.trim().length() > 0)

{

return 0;

}

// We look at the elements afterward on the same line to see if we

// should

// strip any whitespace after the last newline

for (TemplateElement elem = this.nextTerminalNode(); elem != null

&& elem.beginLine == this.endLine; elem = elem

.nextTerminalNode())

{

if (elem.heedsTrailingWhitespace())

{

return 0;

}

}

return substring.length();

}

 

boolean heedsTrailingWhitespace()

{

if (isIgnorable())

{

return false;

}

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

{

char c = text[i];

if (c == '\n' || c == '\r')

{

return false;

}

if (!Character.isWhitespace(c))

{

return true;

}

}

return true;

}

 

boolean heedsOpeningWhitespace()

{

if (isIgnorable())

{

return false;

}

for (int i = text.length - 1; i >= 0; i--)

{

char c = text[i];

if (c == '\n' || c == '\r')

{

return false;

}

if (!Character.isWhitespace(c))

{

return true;

}

}

return true;

}

 

boolean isIgnorable()

{

if (text == null || text.length == 0)

{

return true;

}

if (!isWhitespace())

{

return false;

}

// do the trick

boolean atTopLevel = true;

TemplateElement prevSibling = previousSibling();

TemplateElement nextSibling = nextSibling();

return ((prevSibling == null && atTopLevel) || nonOutputtingType(prevSibling))

&& ((nextSibling == null && atTopLevel) || nonOutputtingType(nextSibling));

}

 

private boolean nonOutputtingType(TemplateElement element)

{

return (element instanceof Macro || element instanceof Assignment

|| element instanceof AssignmentInstruction

|| element instanceof PropertySetting

|| element instanceof LibraryLoad || element instanceof Comment);

}

 

private static char[] substring(char[] c, int from, int to)

{

char[] c2 = new char[to - from];

System.arraycopy(c, from, c2, 0, c2.length);

return c2;

}

 

private static char[] substring(char[] c, int from)

{

return substring(c, from, c.length);

}

 

private static char[] trim(char[] c)

{

if (c.length == 0)

{

return c;

}

return new String(c).trim().toCharArray();

}

 

private static char[] concat(char[] c1, char[] c2)

{

char[] c = new char[c1.length + c2.length];

System.arraycopy(c1, 0, c, 0, c1.length);

System.arraycopy(c2, 0, c, c1.length, c2.length);

return c;

}

 

boolean isWhitespace()

{

return text == null || trim(text).length == 0;

}

}

 

原文地址:

http://groups.google.com/group/google-appengine-java/browse_thread/thread/dd84e44f604498c4

http://groups.google.com/group/google-appengine-java/msg/9ccb2a0cf91f57b3?pli=1

相关阅读:

本文网址:http://www.romotc.com/?p=7004

]]>
None 2009-10-27T15:55:03Z