随笔 - 175  文章 - 202  trackbacks - 0
<2006年3月>
2627281234
567891011
12131415161718
19202122232425
2627282930311
2345678

第一个Blog,记录哈哈的生活

常用链接

留言簿(16)

随笔分类

随笔档案

文章分类

文章档案

收藏夹

Java links

搜索

  •  

最新评论

阅读排行榜

评论排行榜

@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

二进海底,龙宫那边新多出一个海螺,进去就是龙宫密道,里面有DOMO组员杨志豪,把他弄走,就在原地来回跑,会定期出现一大鱼一大虾,殴之,每次法宝加40点。我在这里练蓝格怪衣,这个每用一次也加5点。
posted @ 2014-05-10 21:21 哈哈的日子 阅读(458) | 评论 (0)编辑 收藏
等到符鬼很饿(能喂2个东西的时候),找到两个相同的喂食物,比如2个狮子精【有一个“狮子吼”技能】,设此时的符鬼有一个技能是“强音波”,点击“狮子吼”两次,符鬼的那个技能就变成了“无” !@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

为了成功,保存好,多来几次!
posted @ 2014-05-05 21:43 哈哈的日子 阅读(412) | 评论 (0)编辑 收藏
@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css); 在月河村的客栈,一直向右,到不能再右,向下一步,然后再点宝物就可以了。
posted @ 2014-05-05 21:34 哈哈的日子 阅读(457) | 评论 (0)编辑 收藏
人成熟与不成熟跟年龄没有关系。人成熟不成熟,就是你能不能站在对方的角度去看待事物,就是能不能把我的世界变成你的世界。这个社会有很多的成年人,还没有脱离幼稚的行为。一点小事情就跟别人争来争去。
      人不成熟的第一个特征:就是立即要回报。
      他不懂得只有春天播种,秋天才会收获。很多人在做任何事情的时候,刚刚付出一点点,马上就要得到回报。(学钢琴,学英语等等,刚开始就觉得难,发现不行,立即就要放弃。)很多人做生意,开始没有什么成绩,就想着要放弃,有的人一个月放弃,有的人三个月放弃,有的人半年放弃,有的人一年放弃,我不明白人们为什么轻易放弃,但是我知道,放弃是一种习惯,一种典型失败者的习惯。所以说你要有眼光,要看得更远一些,眼光是用来看未来的!
      对在生活中有放弃习惯的人,有一句话一定要送给你:"成功者永不放弃,放弃者永不成功"。那为什么很多的人做事容易放弃呢?美国著名成功学大师拿破仑希尔说过:
穷人有两个非常典型的心态:
1、永远对机会说:"不";
2、总想"一夜暴富"。
      今天你把什么机会都放到他的面前,他都会说"不"。就是今天你开饭店很成功,你把你开饭店的成功经验,发自内心的告诉你的亲朋好友,让他们也去开饭店,你能保证他们每个人都会开饭店吗?是不是照样有人不干。
      所以这是穷人一个非常典型的心态,他会说:"你行,我可不行!"。一夜暴富的表现在于,你跟他说任何的生意,他的第一个问题就是"挣不挣钱",你说"挣钱",他马上就问第二个问题"容易不容易",你说"容易",这时他跟着就问第三个问题"快不快",你说"快"!这时他就说"好,我做!"呵呵,你看,他就这么的幼稚!
      大家想一想,在这个世界上有没有一种:"又挣钱,又容易,又快的",没有的,即使有也轮不到我们啊,所以说在生活中,我们一定要懂得付出。那为什么你要付出呢?因为你是为了追求你的梦想而付出的,人就是为了希望和梦想活着的,如果一个人没有梦想,没有追求的话,那一辈子也就没有什么意义了!
      在生活中你想获得什么,你就得先付出什么。你想获得时间,你就得先付出时间,你想获得金钱,你得先付出金钱。你想得到爱好,你得先牺牲爱好。你想和家人有更多的时间在一起,你先得和家人少在一起。
但是,有一点是明确的,你在这个项目中的付出,将会得到加倍的回报。就象一粒种子,你把它种下去以后,然后浇水,施肥,锄草,杀虫。最后你收获的是不是几十倍,上百倍的回报。
      在生活中,你一定要懂得付出,你不要那么急功近利,马上想得到回报,天下没有白吃的午餐,你轻轻松松是不可能成功的。
一定要懂得先付出!
人不成熟的第二个特征:就是不自律。
不自律的主要表现在哪里呢?
一、不愿改变自己:
      你要改变自己的思考方式和行为模式。你要改变你的坏习惯。其实,人与人之间能力是没有多大区别,区别在于思考方式的不同。一件事情的发生,你去问成功者和失败者,他们的回答是不一样的,甚至是相违背的。
      我们今天的不成功是因为我们的思考方式不成功。一个好的公式是:当你种植一个思考的种子,你就会有行动的收获,当你把行动种植下去,你会有习惯的收获,当你再把习惯种植下去,你就会有个性的收获,当你再把个性种植下去,就会决定你的命运。
      但是如果你种植的是一个失败的种子,你得到的一定是失败,如果你种植的是一个成功的种子,那么你就一定会成功。
很多人有很多的坏习惯,如:看电视,打麻将,喝酒,泡舞厅,他们也知道这样的习惯不好,但是他们为什么不愿意改变呢?因为很多人宁愿忍受那些不好的生活方式,也不愿意忍受改变带来的痛苦
二、愿意背后议论别人:
      如果在生活中,你喜欢议论别人的话,有一天一定会传回去,中国有一句古话,论人是非者,定是是非人
三、消极,抱怨:
      你在生活中喜欢那些人呢?是那些整天愁眉苦脸,整天抱怨这个抱怨哪个的人,还是喜欢那些整天开开心心的人。如果你在生活中是那些抱怨的,消极的人的话,你一定要改变你性格中的缺陷。如果你不改变的话,你是很难适应这个社会的。你也是很难和别人合作的。
      生活当中你要知道,你怎样对待生活,生活也会怎样对待你,你怎样对待别人,别人也会怎样对待你。所以你不要消极,抱怨。你要积极,永远的积极下去,就是那句话:成功者永不抱怨,抱怨者永不成功
人不成熟的第三个特征:经常被情绪所左右。
一个人成功与否,取决于五个因素:
学会控制情绪
健康的身体
良好的人际关系
时间管理
财务管理
      如果你想成功,一定要学会管理好这五个因素,为什么把情绪放在第一位呢?把健康放在第二位呢?是因为如果你再强的身体,如果你情绪不好,就会影响到你的身体,现在一个人要成功20%靠的是智商,80%靠的是情商,所以你要控制好你的情绪,情绪对人的影响是非常大的。人与人之间,不要为了一点点小事情,就暴跳如雷,这样是不好的。
所以在生活中,你要养成什么样的心态呢?你要养成"三不","三多":

不批评、不抱怨、不指责;

多鼓励、多表扬、多赞美。

      你就会成为一个受社会大众欢迎的人。如果你想让你的伙伴更加的优秀,很简单,永远的激励和赞美他们。
      即使他们的确有毛病,那应该怎么办呢?这时是不是应该给他们建议,在生活中你会发现有这样一个现象,有人给别人建议的时候,别人能够接受,但是有建议的时候别人就会生气。其实建议的方式是最重要的,就是"三明治"赞美,建议,再赞美!
想一想,你一天赞美了几个人,有的人可能以为赞美就是吹捧,就是拍马屁。赞美和吹捧是有区别的,赞美有四个特点:
1、是真诚的
2、是发自内心的
3、被大众所接受的
4、无私的
      如果你带有很强的目的性去赞美,那就是拍马屁。当你赞美别人时候,你要大声的说出来,当你想批评别人的时候,一定要咬住你的舌头!
      人不成熟的第四个特征:不愿学习,自以为是,没有归零心态。
      其实人和动物之间有很多的相似之处,动物的自我保护意识比人更强(婴儿与小猪)但是,人和动物最大的区别在于,人会学习,人会思考。人是要不断学习的,你千万不要把你的天赋潜能给埋没了,一定要学习,一定要有一个空杯的心态。我们象谁去学习呢?就是直接向成功人士学习!
      你要永远学习积极正面的东西,不看,不听那些消极,负面的东西。一旦你吸收了那些有毒的思想,它会腐蚀你的心灵和人生    的。在这个知识经济的时代里,学习是你通向未来的唯一护照。在这样一个速度,变化,危机的时代,你只有不断的学习你才不会被这个时代所抛弃,一定要有学习,归零的心态。去看每一个人的优点,"三人行,必有我师也"!
人不成熟的第五个特征:做事情不靠信念,靠人言。
      我们说相信是起点,坚持是终点。很多人做事不靠信念,喜欢听别人怎么说。对自己所做的事业,没有100%的信心,相信和信念是两个不同的概念,相信是看得见的,信念是看不见的。
      信念是人类的一种态度,但是很多的人他们做事,不靠信念的,而是要听别人怎么说,你要登上山峰,要问那些爬到山顶的人,千万不能问没有爬过山的人。
      这里不是说别人的建议不要去听,你可以去参考,但是你要记住,你来做这个生意是为了实现你的梦想,实现你自己的价值。其他的人是不会关心你的梦想的,只有你自己关心你自己的梦想,只有你自己关心你自己能否真正的成功。这才是最重要的!
只要你的选择是正确的,永远不要在乎别人怎么说,以上的人不成熟的五个特征,你们自己去对照,那一个特征是你有的,你一定要在最短的时间里改正,只要你相信你自己能够战胜自己的不成熟,你就会逐渐的成长,成熟起来,你就会得到你想要的那种生活。你就会实现你时间自由、财务自由、精神自由的人生梦想! 
posted @ 2013-11-20 16:17 哈哈的日子 阅读(222) | 评论 (0)编辑 收藏

设置了 scanPeriod 之后,过了好长时间,都不生效,后来 debug 代码。发现了下面这段。

  private volatile long mask = 0xF;
@Override
public FilterReply decide(Marker marker, Logger logger, Level level,
String format, Object[] params, Throwable t) {
if (!isStarted()) {
return FilterReply.NEUTRAL;
}
// for performance reasons, skip change detection (MASK-1) times out of MASK.
// Only once every MASK calls is change detection code executed
// Note that MASK is a variable itself.
if (((invocationCounter++) & mask) != mask) {
return FilterReply.NEUTRAL;
}
long now = System.currentTimeMillis();
synchronized (configurationWatchList) {
updateMaskIfNecessary(now);
if (changeDetected(now)) {
// Even though reconfiguration involves resetting the loggerContext,
// which clears the list of turbo filters including this instance, it is
// still possible for this instance to be subsequently invoked by another
// thread if it was already executing when the context was reset.
disableSubsequentReconfiguration();
detachReconfigurationToNewThread();
}
}
return FilterReply.NEUTRAL;
}

这行 if (((invocationCounter++) & mask) != mask) { mask = 0xf,其实要每循环 0xf 次,也就是 15 次,才会去 check 一次是否要更新,也就是说,不管过了多久,如果没到这 15 次,也不会去检查是否更新配置。
也就是说,我多打几次 log,配置文件就生效了。

@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
posted @ 2013-11-12 14:25 哈哈的日子 阅读(1579) | 评论 (0)编辑 收藏

spring security(下简写为 ss)控制的安全主要有两方面,Web 和 Method Call,这两个方面的权限控制有比较多的相通的设计,也有一些特别的功能。比如 Method Call 可以做 After Invocation 控制,而 Web 可以做 Ip 地址控制。

这里面有两个最基本的概念:authentication manager 和 access decision manager,前者控制认证,后都控制鉴权。
1. 在 ss 的认证系统中,默认的实现帮助我们提供了三个概念,用户(user),角色(authority,一般存 role)和组(group),三者的关系是,组、角色与用户都是多对多关系,组和角色间没关系,默认是不启用组的。后续,在 Acl 权限管理中,可以看到角色之间,是可以有包含(树形?)关系的。
2. 在 ss 的鉴权系统中,明显会比认证复杂得多。有 AccessDecisionManager, AccessDecisionVoter(前置), AfterInvocationProvider(后置), RoleHierarchy, SidRetrievalStrategy, LookupStrategy, PermissionGrantingStrategy, SecurityExpressionHandler, AclService, MutableAclService, AclCache 概念过多了,要一个一个解释
a) 中心是 AccessDecisionManager,主要负责 AccessDecisionVoter 的管理,默认提供了3种实现:1. AffirmativeBased 如果有任何一个投票器允许访问,请求将被立刻允许,而不管之前可能有的拒绝决定。2. ConsensusBased 多数票(允许或拒绝)决定了结果,平局的投票 和空票(全是弃权的)的结果是可配置的。3. UnanimousBased 所有的投票器必须全是允许的,否则访问将 被拒绝。
AccessDecisionManager 在用于 Web 和 Method Call 两种情况下,可能是不一致的,因为功能也不一致。
b) Method Call 除了使用 AccessDecisionManager 进行权限判断外,还可以增加 AfterInvocationProvider 来进行出口数据的判断,默认提供了 3 种。
1) PostInvocationAdviceProvider: 需要提供一个 PostInvocationAuthorizationAdvice,默认实现只有一个,就是 ExpressionBasedPostInvocationAdvice,可以通过 spel 来进行权限判断。注意 ExpressionBasedPostInvocationAdvice 中需要提供一个 MethodSecurityExpressionHandler,能够创建出一个 MethodSecurityExpressionOperations,放到 spel context 中,供 spel function 调用,这样的方式,在后续很常见。
2) AclEntryAfterInvocationProvider 和 AclEntryAfterInvocationCollectionFilteringProvider : 这两种都差不多,主要依赖 AclService, ObjectIdentityRetrievalStrategy, SidRetrievalStrategy 来配合,检查返回值的权限。Collection 版本的,可以把无权限的数据去掉,只留下有权限的数据。
c) RoleHierarchy 提供了角色之间的关系,提供了两个实现,一个是没关系的,直接把 user 的 role 返回,另外一个是有继承关系的。继承关系实现挺有意思的,能够处理多级的 include 关系,比较好用。
RoleHierarchy 的使用比较复杂,会被 AccessDecisionVoter, SidRetrievalStrategy, SecurityExpressionHandler 用到,SecurityExpressionHandler 又会被 AccessDecisionVoter 用到,所以还是有点儿混乱。
具体的说 SecurityExpressionHandler 会用到 PermissionEvaluator 和 RoleHierarchy,PermissionEvaluator 的一个实现 AclPermissionEvaluator 会用到 SidRetrievalStrategy。
d) SidRetrievalStrategy 和 RoleHierarchy 的功能比较接近,比 RoleHierarchy 高一个抽象层次,功能上也有所区别,是从一个 authentication 拿到所有相关的 Sid(包括 Role(GrantedAuthoritySid) 和 User(PrincipalSid)),而 RoleHierarchy 只包括了 Role(GrantedAuthoritySid)的继承关系。
e) LookupStrategy 通过 ObjectIdentity 和 Sid 把相关的 Acl 查询出来。可以在 LookupStrategy 扩展 Acl 和 Ace 的功能,比如在 Ace 上面加上时间的条件限制,就需要自己定义 LookupStrategy,把时间条件从数据库查询出来,并放到自定义的 Ace 当中。
但这件事情非常麻烦,因为默认实现的 BasicLookupStrategy 是个 Final 的类,所以只能自己直接实现接口,无法使用现有的功能。
LookupStrategy 会生成 Acl,而最终的权限验证是由 Acl 完成的,如果想验证带时间条件的 Ace,需要给 Acl 设置自定义的带有检查时间功能的 PermissionGrantingStrategy,实际上,这个 PermissionGrantingStrategy 会首先设置给 LookupStrategy,LookupStrategy 在创建 Acl 的时候,再放到 Acl 中去。
f) SecurityExpressionHandler 能够执行 spel,得到是否可以访问的结果,它的子类都是继承自 AbstractSecurityExpressionHandler 的,有一个非常重要的方法是 SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, T invocation),创建一个 SecurityExpressionOperations 放到 EvaluationContext 中去,提供 spel 中执行的方法实现。比如 SecurityExpressionOperations 的一个抽象实现 SecurityExpressionRoot 中,就包含了大量的权限验证方法,如 hasRole, hasPermission 等常用的功能。
g) AclService, MutableAclService, AclCache 概念比较简单,AclService 是通过 LookupStrategy 查询 Acl,自已可以查询 ObjectIdentity 的父子关联关系,MutableAclService 提供了修改的能力,AclCache 为 AclService 提供缓存,默认的实现了一个 EhCacheBasedAclCache。
3. ss 的鉴权模型 Sid, ObjectIdentity, Acl, Ace, Permission
a) Sid: 是中心,所有的授权会关联在 Sid 上面,Sid 和之前的 Role Base Permission 会有些相同的地方,但也明显不同,Sid 默认实现情况下,分为 GrantedAuthoritySid 和 PrincipalSid,其实就是 Role 和 User,通过 SidRetrievalStrategy 拿到一个 Authentication 的 Sid。
b) ObjectIdentity: 可以理解成 Resource,就是可访问的目标资源,有 id 和 type 两个字段,默认实现的 ObjectIdentityImpl 会直接调用目标 domainObject 的 getClass 和 getId 方法拿到两个参数。在 PermissionEvaluator, AfterInvocationProvider 中,会用到 ObjectIdentityRetrievalStrategy 和 ObjectIdentityGenerator,ObjectIdentityRetrievalStrategy 会根据 domainObject 拿到 ObjectIdentity,然后使用 Acl 进行鉴权,ObjectIdentityGenerator 会在系统提供的不是 domainObject,而是 type, id 的时候,拿到 ObjectIdentity,然后进行 Acl 鉴权,这两个接口有一个共同的实现 ObjectIdentityRetrievalStrategyImpl,如果需要在 ObjectIdentity 进行新的抽象,需要用新的实现,到得不同的 ObjectIdentity,比如将业务对象分类鉴权这样的需求。
c) Acl, 每个 ObjectIdentity 最多对应一条 Acl,Acl 中包含了很多,包括 parental,说明 Acl 是有继承关系的?其实不是,呵呵,是 ObjectIdentity 有继承关系而已。有一个 ObjectIdentity,有很多 Sid,还有一个叫做 Owner 的 Sid,有从 LookupStrategy 传过来的 PermissionGrantingStrategy,进行实际的鉴权,还有 AclAuthorizationStrategy 检查有没有权限进行 Acl security check。实现时间条件检查,就扩展 PermissionGrantingStrategy。
为什么没有 RoleHierarchy 或是 SidRetrievalStrategy 存在呢?是因为调用 Acl 进行权限检查之前,已经把相关的 Sid 得到了,再给 Acl 的。
d) Ace, Permission: Ace 存储 Sid, Permission,提供给 Acl 鉴权用。增加时间条件的话,最基本的,就是要在 Ace 中,增加时间条件字段。Permission 是用二进制存储的,但默认实现的数据库存储并不是,是一个一条,存在数据库里面的。

好吧,概念还是非常多的,不过鉴于权限控制本身就是个复杂的话题,ss 这些设计的我觉得已经非常好,也基本够用了。

@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
posted @ 2013-11-12 14:25 哈哈的日子 阅读(640) | 评论 (0)编辑 收藏
Security.setProperty("ssl.SocketFactory.provider", "com.datayes.cloud.util.TrustAllSSLSocketFactory");
package com.datayes.cloud.util;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class TrustAllSSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public TrustAllSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        sslContext.init(nullnew TrustManager[]{tm}, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }


    @Override
    public Socket createSocket(String host, int port) throws IOException {
        return sslContext.getSocketFactory().createSocket(host, port);
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
        return sslContext.getSocketFactory().createSocket(host, port, localHost, localPort);
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return sslContext.getSocketFactory().createSocket(host, port);
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return sslContext.getSocketFactory().createSocket(address, port, localAddress, localPort);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return new String[0];
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return new String[0];
    }
}
posted @ 2013-09-10 12:30 哈哈的日子 阅读(1568) | 评论 (0)编辑 收藏
主要是遇到的一些问题吧,顺便感谢一下帮助了我的人。安装之前,听说安装正式环境的 OpenStack 挺麻烦的,所以,出发点就是安装一个能测试使用的 Dev 环境就可以了,不求全,时间紧张,能用就行。所以,定位到 devstack(http://devstack.org),一键安装 OpenStack

问题
1. 想用 CentOS 来着,没原因,习惯了,后来发现,devstack 默认支持 ubuntu,为了简单,改用 ubuntu
2. 安装过程中,需要大量的网络下载,网速如果不快,挺急人的。
3. 安装到 stack.sh 的 191 行,会报错 [ERROR] ./stack.sh:191 g-api did not start,这个问题折腾了我好久,最后按照 https://answers.launchpad.net/glance/+question/231020 办法解决了,非常感谢 Marc PINHEDE (pinhede-marc) ,但在 https://bugs.launchpad.net/devstack/+bug/1119428 里,有人说只要修改 /etc/default/locale LANG="POSIX",就可以了,其实我两个都改了,也不知道是哪个产生了作用。但,第一种方法,需要安装到一半,失败了,才会有提到的 /opt/stack/glance/glance/notifier/notify_kombu.py 文件,但第二种方法,刚开始就可以尝试,所以我如果下次安装的话,会先把第二种配置修改好,如果安装失败了,再使用第一种方法继续。


posted @ 2013-08-06 10:19 哈哈的日子 阅读(602) | 评论 (0)编辑 收藏
在 compile hadoop-common 的时候,提示 protobuf 出错,查了一下,需要安装 protobuf(是一个非 Java 的组件)
先到 homebrew 上找到安装 homebrew 的方法 ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
然后不能直接 brew install protobuf,因为会安装 1.5.0,也没办法编译过的,我试了。
需要先 brew versions protobuf,然后 cd `brew --prefix`(我默认的是 cd /usr/local),直接招待刚才 brew versions 出来的那个 git clone 方法。
然后再次 brew install protobuf ,就安装  1.4.1 了,继续 maven 就没有问题了。
posted @ 2013-07-24 13:24 哈哈的日子 阅读(359) | 评论 (0)编辑 收藏
在 .bash_profile 中增加一行 export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 就可以了。


posted @ 2013-07-24 13:20 哈哈的日子 阅读(371) | 评论 (0)编辑 收藏
一直以来,总有人说 IDEA 这个 IDE 要比 Eclipse 好。中间也做过几次尝试,均告放弃。原因虽然各种各样,但归结起来,就是没时间,毕竟熟悉一个 IDE 是要时间的,项目中很少会有这么轻松的时候,又不愿意过多使用业余时间,就这样放下了。

最近有了一些时间,又把这东西拾起来看了看。不得不说,有些地方,做得还是很好的,当然,也有比 Eclipse 差的地方,我估计已经有无数人对比过了,我也不再比了,focus 在我的关注点上:“快捷键”

IDEA 因为使用的是原生的 Java 而不是 swt,对于平台集成方面,不如 Eclipse。
比如在 Eclipse 中,可以设置 Option + B 这样的快捷键,而 IDEA 不行,因为 Option + B 在 Mac 下是有输出字符的。

为了解决这个问题,我到 KeyRemap4MacBook 中,把 Option + B 改成 Option + Left,同理,把 Option + F 改成 Option + Right
这时,在 IDEA 中比较常用的快捷键 Command + Option + B 就变成了 Command + Option + Left,成了后退了。
还需要在 KeyRemap4MacBook 中把 Command + Option + B 恢复成他自己,而且一定要放在 Option + B 前面,否则就没用了。

最终,我得到了这样的 private.xml


<?xml version="1.0"?>
<root>
  <item>
    <name>haha</name>
    <identifier>private.haha</identifier>
    <autogen>--KeyToKey-- KeyCode::P,VK_CONTROL, KeyCode::CURSOR_UP</autogen>
    <autogen>--KeyToKey-- KeyCode::N,VK_CONTROL, KeyCode::CURSOR_DOWN</autogen>
    <autogen>__KeyToKey__ KeyCode::F,VK_OPTION, KeyCode::CURSOR_RIGHT,VK_OPTION</autogen>
    <autogen>__KeyToKey__ KeyCode::B,VK_OPTION,VK_COMMAND, KeyCode::B,VK_OPTION,VK_COMMAND</autogen>
    <autogen>__KeyToKey__ KeyCode::B,VK_OPTION, KeyCode::CURSOR_LEFT,VK_OPTION</autogen>
    <autogen>__KeyToKey__ KeyCode::D,VK_OPTION, KeyCode::FORWARD_DELETE,VK_OPTION</autogen>
  </item>
</root>
posted @ 2013-07-22 13:22 哈哈的日子 阅读(315) | 评论 (0)编辑 收藏
$(window).scroll(function() {
   if($(window).scrollTop() + $(window).height() == $(document).height()) {
       // load next
   }
});
posted @ 2012-12-19 18:10 哈哈的日子 阅读(420) | 评论 (0)编辑 收藏
把这个文件放到 WEB-INF/classes 下面,随便申请一个临时 License 就可以了,会变成 Enterprice 的,其它信息保留。
stash_2_crack.zip 
posted @ 2012-12-14 17:23 哈哈的日子 阅读(543) | 评论 (0)编辑 收藏
今天想在 log 里加上当前机器的 ip,找了一些文档,logback 支持 MDC(Mapped Diagnostic Contexts),可以很容易的把 ip 放到 log 中。

方法: 
1. 先在代码中加上一行 MDC.put("ip", InetAddress.getLocalHost().getHostAddress())
2. 然后在 logback 的 pattern 中加上 %X{ip} 即可

posted @ 2012-12-14 14:58 哈哈的日子 阅读(5123) | 评论 (0)编辑 收藏
vi /etc/yum.conf 将exclude=kernel* 去掉
posted @ 2012-12-14 13:45 哈哈的日子 阅读(350) | 评论 (0)编辑 收藏
1. 建立 winexe 环境,build winexe 并不麻烦,只不过官方文档比较少,下载到 source 之后,也不知道要如何 build。后来找到一个文档,介绍了过程
cd winexe-1.00/source4
./autogen.sh
./configure
make
./bin/winexe -U “<user>%<password>” //<windows system> cmd.exe

2. 如何远程执行,命令比较很简单,但又是环境问题,我们在 windows 下面建立了一个 administrators 组的用户,但无法执行,后来打开了 administrator 这个用户,终于命令可以执行了。
我们的脚本有两个步骤,1. 杀掉旧进程,2. 启动新的进程,如下:
    winexe -U "administrator%admin" //172.16.107.243 "taskkill /F /T /im java.exe"
    cat < /dev/null | winexe -U "administrator%admin" //172.16.107.243 "java -jar c:\agent\job-agent.jar" >> /home/glodon/logs/agent243.log 2>&1 &
启动新进程的时候,遇到了非常麻烦的事情,只能前台执行,nohup , & 这些完全不灵,如果 nohup,就会报错,后来得到了一个方法,cat < /dev/null | winexe 解决了这个问题。

3. jenkins 执行,jenkins 使用 Post Shell Plugin 来调用这个脚本,调用的时候一定要 nohup start.sh > /dev/null &,否则在执行完之后,会发个 sign,会把进程结束掉。
注意,还必须要 > /dev/null,否则就会出错,实在搞不明白原因。

弄好了这个,以后就方便了,心情也挺好。

posted @ 2012-12-14 13:25 哈哈的日子 阅读(427) | 评论 (0)编辑 收藏
呵呵,有图有真相。
用 ipad 发的 imessage,挺有意思的,不知不觉,孩子已经这么大了。

@import url(/css/cuteeditor.css);
posted @ 2012-11-21 16:24 哈哈的日子 阅读(633) | 评论 (0)编辑 收藏

主要完成了下面4个工作

1. 创建一个本地的目录结构,以存放 rpm 包
2. 启动一个 apache,使这些文件能够远程访问
3. 写一个 spec,并且用 rpmbuild 做成一个安装包,用来在机器上安装新的 repository 位置
4. 使用 yum downloadonly plugin 将需要的 rpm 包放到本地目录下,然后使用 createrepo 命令创建 metadata

本来是希望能有一个类似于 nexus 这样的 proxy host server 将远程的 package cache 下来,找来找去,也找到了一个 nexus yum plugin,但这个 plugin 只支持手工的 deploy rpm package 到 nexus 上面,不能做 proxy 方式的。

写写步骤和遇到的问题吧。

准备工作

  • 安装 createrepo, yum install createrepo
  • 安装 yum download only plugin, yum -y install yum-downloadonly
  • 安装 rpmbuild, yum -y install rpm-build
  • 确认已经安装了 apache nginx 之类的 http server

服务器步骤

  • 首先是创建目录结构,比如 mkdir -p /data/yum/centos/6/x86_64
  • 先增加 chef 的源,rpm -Uvh http://rbel.frameos.org/rbel6
  • 然后是通过 yum -y install rubygem-chef-server –downloadonly –downloaddir=/data/yum/centos/6/x86_64
  • 这时,已经可以去掉 chef 的公共源了,rpm -e rbel6-release
  • 创建本地库的 metadata,createrepo /data/yum/centos/6/x86_64,还有一些参数可用,比如 -p, pretty xml, -d create sqlite database files
  • 配置 apache,修改 /etc/httpd/conf/httpd.conf,修改 DocumentRoot 和 Directory 位置,改为 /data,并启动 httpd -k start,也可以使用 chkconfig –level 3 https on,每次开机启动

客户端步骤

  • 首先要制作安装 repository 位置的 rpm 包
  • 创建文件 haha.repo,放到 /root/rpmbuild/SOURCES 目录下,这个是将来 copy 到客户端的 /etc/yum.repos.d/ 目录下的配置文件,内容为
    [haha]
        name=haha
        baseurl=http://192.168.157.131/yum/centos/$releasever/$basearch/
        enabled=1
        gpgcheck=0
  • 再创建文件 build spec 文件,放到 /root/rpmbuild/SOURCES 目录下,是为了创建 rpm 包用的,haha.spec
    Summary:       haha
        Name:          haha
        Version:       0.1
        Release:       1
        Source0:       haha
        Group:         Applications/Internet
        License:       GPLv2+
        URL:           http://192.168.157.131/yum/
        #BuildRoot:     %{_tmppath}/%{name}-%{version}-root
        BuildArch:     noarch
    %description The haha yum repo #%prep #%setup -q %install mkdir -p $RPM_BUILD_ROOT/etc/yum.repos.d install -m 0644 -p %{SOURCE0} $RPM_BUILD_ROOT/etc/yum.repos.d
    %clean rm -rf ${RPM_BUILD_ROOT} %files /etc/yum.repos.d/haha.repo
  • 使用 rpmbuild -ba haha.spec,做出一个 rpm 包,位置在 /root/rpmbuild/RPMS/noarch 下面
  • 制作一次 rpm 后,就可以一直使用了,rpm -ivh xxx.rpm 就可以了

参考了
1. 自建yum源与制作RPM安装包yum源
2. yum只下载rpm包不自动安装方法
3. Installing Chef Server 0.10 in RHEL 6

posted @ 2012-11-07 21:39 哈哈的日子 阅读(306) | 评论 (0)编辑 收藏
最近很少用鼠标了,触摸板还是没有鼠标灵活的,所以,很大希望都寄托在键盘上面了,快捷键就变成了优先级最高的关注点。
Sublime Text 的快捷键总是零零散散记了一些的,今天才发现,原来在 Preferences -> Key Bindings - Default 里面有全部的快捷键定义,以后不知道什么的时候,来看一眼就好了。

posted @ 2012-10-26 15:47 哈哈的日子 阅读(264) | 评论 (0)编辑 收藏
想了好久好久了,终于买到了。老婆送的生日礼物,老婆大人实在是太体贴了!
之前给朋友买了一个红轴的机械键盘,只玩了几把 dota 就给人了,也没感觉到什么,反正我玩 dota 的水平提升了 10%,呵呵。
先说说拿到 hhkb 的感觉吧。

1. 个头,比想象的还要小,60 键的小键盘实在是太小了,喜欢!
2. 键盘包,我还顺便买了一个放 hhkb 的包,也是从日本带回来的(最近因为某人钓鱼的问题,搞得我怪紧张的),拿回来了才发现,made in china,nnd,这东西国内居然还买不到!实在是无语
3. 键位,刚开始的时候,对 Delete 的位置很不习惯,大概用了一个小时左右,大概习惯了。Ctrl 的位置是之前一直在用的,所以非常舒服。比较纠结的是方向键,我之前还以为左边会有一个 fn 键给我组合,没想到 pro 没有,只有 lite 才有,pro 只有右边有一个 fn,只好在需要方向键的时候,手离开主键盘区了。
4. 手感,手感实在是无与伦比了,用了这个打字之后,就不太愿意回到 mac 的巧克力键盘上了,差别的确有些大。
5. 声音,这玩意声音还有点儿大啊,比我之前想得还要大一些,在办公室的环境下,应该是不会影响到什么的,之前还是有点儿心虚,怕影响到别的,后来渐渐习惯了,发现别人根本就听不到,也就慢慢的放心了。呵呵

工作中遇到问题吧
因为主要是 Java 开发,所以 IDE 主要用的是 Eclipse,Eclipse 里面用 hhkb 有两个比较麻烦的地方:
1. 经常要用到方向键,比如语法提示之后,需要用上下来选择你要的那个,这个我用 keyremap4mac 把 Ctrl + N 和 Ctrl + P 直接改成上下了,可以用了。
2. Eclipse 经常要用到 Fx 键,这个相当麻烦,比如,切换 Editor 要 Cmd + F6,换 View 要 Cmd + F7,换视图要 Cmd + F8,执行最后执行的程序要 Cmd + Shift + F11,这时候,我就会发现,我已经有点儿搞不定了,没办法,我估计我要去修改 Eclipse 的快捷键了,因为那个 Cmd + F11 实在是太常用了。

遇到开心的事儿
在 Terminal 下面,用起来非常舒服的,这个键盘本来就是为了 vi , emacs 之类的东西存在的,在 Termial 标准的 Emacs 快捷键下,用起来非常好,基本不用想什么,就一切都很顺利了。
在 OS X 系统下,大部分时候 Emacs 的快捷键 Ctrl + fbnpaek 这些快捷键都是好用的,也是比较舒服的原因之一,但 Option + fbd 这类的快捷键经常不能用,比较郁闷。

无论如何,这个键盘还是带给了我不少的快乐,首先达到了 Happy 的效果,以后慢慢的来体会 Hacking 的感觉吧。
加油!
posted @ 2012-10-13 09:33 哈哈的日子 阅读(1697) | 评论 (1)编辑 收藏
http://dev.mysql.com/doc/refman/5.5/en/connector-j-reference-implementation-notes.html @import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);


ResultSet

By default, ResultSets are completely retrieved and stored in memory. In most cases this is the most efficient way to operate, and due to the design of the MySQL network protocol is easier to implement. If you are working with ResultSets that have a large number of rows or large values, and cannot allocate heap space in your JVM for the memory required, you can tell the driver to stream the results back one row at a time.

To enable this functionality, create a Statement instance in the following manner:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);

The combination of a forward-only, read-only result set, with a fetch size of Integer.MIN_VALUE serves as a signal to the driver to stream result sets row-by-row. After this, any result sets created with the statement will be retrieved row-by-row.

There are some caveats with this approach. You must read all of the rows in the result set (or close it) before you can issue any other queries on the connection, or an exception will be thrown.

The earliest the locks these statements hold can be released (whether they be MyISAM table-level locks or row-level locks in some other storage engine such as InnoDB) is when the statement completes.

If the statement is within scope of a transaction, then locks are released when the transaction completes (which implies that the statement needs to complete first). As with most other databases, statements are not complete until all the results pending on the statement are read or the active result set for the statement is closed.

Therefore, if using streaming results, process them as quickly as possible if you want to maintain concurrent access to the tables referenced by the statement producing the result set.

posted @ 2012-06-29 13:15 哈哈的日子 阅读(465) | 评论 (0)编辑 收藏
在 Mac 上配置 Apache 和 SVN 极其方便。

序:
    之前在 Windows 上,因为心里美的原因,配置过 Apache 和 SVN 集成,使用 http 协议来访问 SVN。配置过程有些麻烦,也容易出错。
    后来,一直使用 svnserve -d,在 windows 上一般还会用 sc 命令做成 service,因为简单方便。

后来因为试验的目的,在 Mac 上配置了 Apache 和 SVN,我的 OS X 是 10.7 Lion
居然极其简单,只要在“系统偏好设置” -> “共享” 中,把 Web 共享打开,然后把个人网站点开(仅仅是不想修改全局配置文件)
然后修改文件 /private/etc/apache2/users/你的用户名.conf ,里面加上
# svn module
LoadModule dav_svn_module libexec/apache2/mod_dav_svn.so
LoadModule authz_svn_module libexec/apache2/mod_authz_svn.so

<Location /svn>
     DAV svn
     SVNListParentPath on
     SVNParentPath "/repository/svn/path"
</Location>

就可以了,
两个 svn 相关的 module 已经放好了,只要 load 一下就行。
配置方面还可以增加认证等等。为了权限管理得更细致,也可以使用 SVNPath 而不是 SVNParentPath。
唉,真是方便,Mac 用来开发,不错!

posted @ 2012-05-10 14:43 哈哈的日子 阅读(226) | 评论 (0)编辑 收藏
ssh 免密码登录,需要使用公私钥来认证@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

首先通过 ssh-keygen 生成一对公私钥,默认在 ~/.ssh/id_rsa.pub 和 ~/.ssh/id_rsa,前面的是公钥。
认证就是要把这个文件加到远程用户目录 ~/.ssh/authorized_keys 文件中,而且这个文件的权限不能被其它人访问。

下面的脚本能够自动把这个文件放到远程,方法是 ./addpk ip username password

#!//usr/bin/expect
set host [lrange $argv 0 0]
set user [lrange $argv 1 1]
set passwd [lrange $argv 2 2]
proc ssh {cmd} {
    global user host passwd
    spawn ssh $user@$host "$cmd"
    expect {
        "*conne*" {
            send "yes\n"
            expect "*password*"
            send "$passwd\n"
            expect eof
        }
        "*password*" {
            send "$passwd\n"
            expect eof
    }
    }
}
proc scp {src dest} {
    global user host passwd
    spawn scp $src $user@$host:$dest
    expect {
        "*conne*" {
            send "yes\n"
            expect "*password*"
            send "$passwd\n"
            expect eof
        }
        "*password*" {
            send "$passwd\n"
            expect eof
        }
    }
}
ssh "mkdir -p ~/.ssh"
scp "/home/user1/.ssh/id_rsa.pub" "~/.ssh/id_rsa.pub"
ssh "cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys"
ssh "uniq ~/.ssh/authorized_keys > ~/.ssh/authorized_keys.tmp"
ssh "mv ~/.ssh/authorized_keys.tmp ~/.ssh/authorized_keys"
ssh "chmod 700 ~/.ssh"
ssh "chmod 600 ~/.ssh/*"

posted @ 2012-05-08 09:38 哈哈的日子 阅读(728) | 评论 (0)编辑 收藏

在 Eclipse 中执行下面代码。



        byte[] bytes = new byte[]{-16, -97, -116, -70};

        String s = new String(bytes, "UTF-8");

        System.out.println(s);


结果打印出了一朵花,呵呵,实在是太有意思了。

@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
posted @ 2012-04-17 15:25 哈哈的日子 阅读(164) | 评论 (0)编辑 收藏
Picasa 像册真的很给力,2048 像素以下(包含)的照片不计算空间,据说 15 分钟以内的也不算空间,除了这些,有1G的空间可以使用。
我现在用的 Aperture 或者是 iPhoto 都有 Picasa Plugin,上传照片非常方便,除了需要fanqiang外,没什么其它问题了。
虽然 Aperture 和 Facebook, Flickr 好像集成的更好,可实际上,Facebook 像素低,还不能选,Flickr 空间有要求。
 
posted @ 2012-02-27 10:54 哈哈的日子 阅读(250) | 评论 (0)编辑 收藏
这个文件已经在 /Library/Java/JavaVirtualMachines/1.6.0_29-b11-402.jdk/Contents/Classes/classes.jar
这里了,我在混淆代码的时候会用到,只要做个 link 就好了,如下:
sudo ln -s /Library/Java/JavaVirtualMachines/1.6.0_29-b11-402.jdk/Contents/Classes/classes.jar /Library/Java/JavaVirtualMachines/1.6.0_29-b11-402.jdk/Contents/Home/lib/rt.jar

@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
posted @ 2012-02-10 10:48 哈哈的日子 阅读(2334) | 评论 (0)编辑 收藏
目前有一个 10 台机器的小网,只有其中一台机器能够通过外网访问,其它机器需要先 ssh 到外网机器,然后再 ssh 一下,才能访问到,很麻烦,一些 scp 之类的软件也没法使用。之前,我一直是用 secure crt 端口转发来做的,也算方便,缺点就是一直要开一个 secure crt 窗口,还不能断,否则就全断开了。

后来同事告诉了我一个办法,叫 iptables,利用这台外网机器自己来进行转发,试了一下,的确要更方便一些。

iptables 本身是用来做 linux 防火墙的,还有一些转发功能。

配置起来比较方便。iptables 的配置文件是放在 /etc/sysconfig/iptables 下面的,缺省是没有这个文件的,需要先执行

外网机器:
外网 ip: 202.118.1.125
内网 ip: 111.111.111.111
端口: 8112

内网机器:
ip: 111.111.111.112

命令:

iptables -t nat -A PREROUTING -d 202.118.1.125 -p tcp --dport 8112 -j DNAT --to-destination 111.111.111.112:22
iptables -t nat -A POSTROUTING -d 111.111.111.112 -p tcp --dport 22 -j SNAT --to 111.111.111.111
iptables -A FORWARD -o eth0 -d 111.111.111.112 -p tcp --dport 22 -j ACCEPT
iptables -A FORWARD -i eth0 -s 111.111.111.112 -p tcp --sport 22 -j ACCEPT

然后再 iptables-save 这个文件就出来了。

通过 service iptables restart 就可以启动 iptables 服务。
奇怪的是 111.111.111.111 这台机器并没有 listen 8112 的端口,但你只要 ssh 202.118.1.125 8112,就真的能够连到 111.111.111.112 这台机器上,算是留下一个疑问吧。

@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
posted @ 2012-01-29 16:04 哈哈的日子 阅读(1404) | 评论 (0)编辑 收藏
L-Larry_Lau@163.com#24777-1i8da63tvtyl2#1119
L-Larry_Lau@163.com#61624-1dvrt8wj18v1#6260
L-Larry_Lau@163.com#50028-se4zkrr1m6t1#10246
L-Larry_Lau@163.com#15600-189y158nwwvuk#339
L-Larry_Lau@163.com#30640-1lklqdbcjmhxs#4016
L-Larry_Lau@163.com#57474-53b2wr1311gnz#10228
L-Larry_Lau@163.com#19667-11r2awc10nqelb#4016
L-Larry_Lau@163.com#60353-pphob7wraf0y#515
L-Larry_Lau@163.com#65157-1ae6ytp7ygj8m#0012
L-Larry_Lau@163.com#16226-1n5h5951019s7s#7343
posted @ 2011-12-27 21:04 哈哈的日子 阅读(1510) | 评论 (1)编辑 收藏
@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css); 问题:
    1. centos 5.5 通过 yum 安装 mysql,启动,一切正常。但是,修改 my.cnf 中的 datadir 到自定义目录,并初始化好数据库,使用原来的 mysql 文件就无法启动了。
    2. 通过 heartbeat 启动 mysql 遇到同样的问题。

解决:
    修改 /etc/selinux/config 文件中的  SELINUX=disabled,就可以运行了。

过程:
    定位问题的过程中,发现,只要 copy 出来的 mysql 脚本,就可以执行,原来的依然不可以。或者 mysql 数据库文件放到 /var/lib/mysql 下,就可以,其它位置,就不行。
    猜测,文件属性有什么不一样的?通过 ls -l 看权限,和 lsattr 看属性,都一模一样。
    但,知道原因后,使用 ls -Z 可以看到 selinux 相关的属性,这些文件是不一样的。
    
原因:
    不太清楚原因,但肯定的是,selinux 相关属性影响的,有空仔细看看相关文档。

下面这篇写得不错:

http://www.linux.gov.cn/netweb/selinux.htm

SELinux简介

SELinux全称是Security Enhanced Linux,由美国国家安全部(National Security Agency)领导开发的GPL项目,它拥有一个灵活而强制性的访问控制结构,旨在提高Linux系统的安全性,提供强健的安全保证,可防御未知攻击,据称相当于B1级的军事安全性能。比MS NT所谓的C2等高得多。

应用SELinux后,可以减轻恶意攻击或恶意软件带来的灾难,并提供对机密性和完整性有很高要求的信息很高的安全保障。 SELinux vs Linux 普通Linux安全和传统Unix系统一样,基于自主存取控制方法,即DAC,只要符合规定的权限,如规定的所有者和文件属性等,就可存取资源。在传统的安全机制下,一些通过setuid/setgid的程序就产生了严重安全隐患,甚至一些错误的配置就可引发巨大的漏洞,被轻易攻击。

而SELinux则基于强制存取控制方法,即MAC,透过强制性的安全策略,应用程序或用户必须同时符合DAC及对应SELinux的MAC才能进行正常操作,否则都将遭到拒绝或失败,而这些问题将不会影响其他正常运作的程序和应用,并保持它们的安全系统结构。

SELinux的相关配置文件

SELinux的配置相关文件都在/etc/selinux下,其中/etc/selinux/targeted目录里就包含了策略的详细配置和context定义,以下是主要文件及功用:

/etc/selinux/targeted/contexts/*_context 默认的context设置 
/etc/selinux/targeted/contexts/files/* 精确的context类型划分 
/etc/selinux/targeted/policy/* 策略文件

Apache under SELinux

Apache under SELinux - 让Apache跑得顺起来!
对于刚使用Redhat Enterprise Linux 4 或Fedora Core 2以上/CentOS 4的用户,一定会为Apache经常无法正常运转,报以"Permission denied"等错误而大为不解,甚至大为恼火。
其实这是因为这些系统里激活了SELinux,而用户的apache配置与SELinux的配置策略有抵触产生的,只有通过适当调整,使apache的配置和访问符合策略才能正常使用。
现在下面来分析一下SELinux中有关httpd(apache)的context定义(略有删节)

/home/[^/]+/((www)|(web)|(public_html))(/.+)? system_u:object_r:httpd_user_content_t
/var/www(/.*)? system_u:object_r:httpd_sys_content_t
/var/www/cgi-bin(/.*)? system_u:object_r:httpd_sys_script_exec_t
/usr/lib/cgi-bin(/.*)? system_u:object_r:httpd_sys_script_exec_t
/var/www/perl(/.*)? system_u:object_r:httpd_sys_script_exec_t
/var/www/icons(/.*)? system_u:object_r:httpd_sys_content_t
/var/cache/httpd(/.*)? system_u:object_r:httpd_cache_t
/etc/vhosts -- system_u:object_r:httpd_config_t
/usr/sbin/httpd -- system_u:object_r:httpd_exec_t
/usr/sbin/apache(2)? -- system_u:object_r:httpd_exec_t
/usr/sbin/suexec -- system_u:object_r:httpd_suexec_exec_t
/var/log/httpd(/.*)? system_u:object_r:httpd_log_t
/var/log/apache(2)?(/.*)? system_u:object_r:httpd_log_t
/var/log/cgiwrap\.log.* -- system_u:object_r:httpd_log_t
/var/cache/ssl.*\.sem -- system_u:object_r:httpd_cache_t
/var/cache/mod_ssl(/.*)? system_u:object_r:httpd_cache_t
/var/run/apache(2)?\.pid.* -- system_u:object_r:httpd_var_run_t
/var/lib/httpd(/.*)? system_u:object_r:httpd_var_lib_t
/var/lib/php/session(/.*)? system_u:object_r:httpd_var_run_t
/etc/apache-ssl(2)?(/.*)? system_u:object_r:httpd_config_t
/usr/lib/apache-ssl(/.*)? -- system_u:object_r:httpd_exec_t
/usr/sbin/apache-ssl(2)? -- system_u:object_r:httpd_exec_t
/var/log/apache-ssl(2)?(/.*)? system_u:object_r:httpd_log_t
/var/run/apache-ssl(2)?\.pid.* -- system_u:object_r:httpd_var_run_t
/var/run/gcache_port -s system_u:object_r:httpd_var_run_t
/var/lib/squirrelmail/prefs(/.*)? system_u:object_r:httpd_squirrelmail_t
/usr/bin/htsslpass -- system_u:object_r:httpd_helper_exec_t
/usr/share/htdig(/.*)? system_u:object_r:httpd_sys_content_t
/var/lib/htdig(/.*)? system_u:object_r:httpd_sys_content_t

针对上述的内容,可以对如下的几个常见问题进行简单处理:

1.phpmyadmin在非默认/var/www/html目录下无法运转

通常类似的情况都是在配置了虚拟主机时,访问/phpmyadmin等提示403访问拒绝,日志里也提示Permission denied,这是因为phpmyadmin防止的目录及文件本身属性不符合context要求。
假设phpmyadmin放在/web目录下,那么执行:
chcon -R -t httpd_user_content_t /web
则会令/web及其下所有子目录/文件,包括phpmyadmin文件都获得了httpd_user_content_t的属性,如果其传统的Unix属性对httpd来说是可读的话,再重新访问一下就应该可以了。

2./home目录下的虚拟主机无法运转

与问题1也是类似的,不过根据上文中context的定义,/home目录下必须是用户的$HOME/www或public_html或web目录才是 httpd_user_content_t类型,因此建议将要作为web页面的内容放置在用户的$HOME/www或web或public_html里,并确保其属性是httpd_user_content_t,使用如下命令查看:
ls -Z /home/abc/
drwxr-xr-x abc abc user_u:object_r:user_home_dir_t tmp
drwxrwxr-x abc abc user_u:object_r:httpd_user_content www
如不是,则可通过chcon来逐级目录及文件更改,直至最后能访问:
chcon -R -t httpd_user_content_t /home/abc/web
chcon -t user_home_dir_t /home/abc

3.CGI程序无法运行

如果cgi程序放在/var/www/cgi-bin/里也无法执行,遇到403或500错误的话,可以检查cgi程序的属性,按SELinux contexts文件里定义的,/var/www/cgi-bin/里必须是httpd_sys_script_exec_t 属性。通过ls -Z查看,如果不是则通过如下命令更改:
chcon -t httpd_sys_script_exec_t /var/www/cgi-bin/*.cgi
如果是虚拟主机里的cgi,则参考问题2使之能正常使用普通的功能后,再通过chcon设置cgi文件的context为httpd_sys_script_exec_t即可。

4.Setuid/gid 程序无法运行

例如早期的SqWebMail及qmailadmin等,需要setuid/gid的支持,但在SELinux下这将受到严格限制。第一种方法是比较彻底的办法,能保留系统的安全性,通过:
audit2allow -l -i /var/log/messages
将SELinux拒绝的信息转换为相应的policy allow指令,将这些指令添加到SELinux policy 的src里相应的配置文件,重新生成policy并加载。但这样做相对比较麻烦。
另一个方法最简单,但将使apache得不到保护。首先确定SELinux 类型是targeted的:
cat /etc/selinux/config|grep SELINUXTYPE
然后,使apache脱离SELinux保护:
setsebool -P httpd_disable_trans 1
然后重启动apache:
/etc/init.d/httpd restart
这样所有apache强制的检查都失效,需要setuid/gid的程序可以正常使用。但这样带来了增加漏洞的危险,对于迫切需要运行而又很急的情况,本方法是一个最大限度减少系统安全缺失的最后办法。对于取消SELinux 未必是一个好方法。

SElinux的几个相关命令

一.

ps -Z
ls -Z
id -Z

例:
[root@ljj cgi-bin]# ls -Z
-rwxrwxrwx root root root:object_r:httpd_sys_script_exec_t a.cgi
-rw-r--r-- root root root:object_r:httpd_sys_script_exec_t a.txt

二. chcon

修改文件的属性 fild1:fild2:fild3

chcon -u fild1 file
chcon -l fild2 file
chcon -t fild3 file

例:
chcon -u root file1

三.getsebool

获取se相关的bool值
例:
[root@ljj cgi-bin]# getsebool -a | grep httpd
httpd_builtin_scripting --> inactive
httpd_disable_trans --> active
httpd_enable_cgi --> active
httpd_enable_homedirs --> active
httpd_ssi_exec --> active
httpd_tty_comm --> inactive
httpd_unified --> inactive

得到了一些与httpd相关的bool值,配置httpd.conf中的user_dir时,要保证这里的httpd_enable_homedirs是 active的,还要保证:

chcon -R -t httpd_sys_content_t ~user/public_html;

  • httpd与selinux之间的关系更多详见:man httpd_selinux

四. togglesebool

给se的相关bool值取反
例:
togglesebool httpd_enable_homedirs


posted @ 2011-12-22 18:41 哈哈的日子 阅读(586) | 评论 (0)编辑 收藏

本次操作环境:

Ubuntu Server 10.10  

SCSI Harddisk:/dev/sda       500GB

U盘:/dev/sdb    8GB(模拟成USB Harddisk,安装OS)

 

介绍2种分区表:
MBR分区表:(MBR含义:主引导记录)
所支持的最大卷:2T (T; terabytes,1TB=1024GB)
对分区的设限:最多4个主分区或3个主分区加一个扩展分区。

GPT分区表:(GPT含义:GUID分区表)
支持最大卷:18EB,(E:exabytes,1EB=1024TB)
每个磁盘最多支持128个分区

 

所以如果要大于2TB的卷或分区就必须得用GPT分区表。

 

Linux下fdisk工具不支持GPT,得使用另一个GNU发布的强大分区工具parted。

fdisk工具用的话,会有下面的警告信息:

WARNING: GPT (GUID Partition Table) detected on '/dev/sda'! The util fdisk doesn't support GPT. Use GNU Parted.

下面是用parted工具对/dev/sda做GPT分区的过程:

root@node01:/mnt# parted /dev/sda
GNU Parted 2.3
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.

 

(parted) mklabel gpt                                                      
Warning: The existing disk label on /dev/sda will be destroyed and all data on this disk
will be lost. Do you want to continue?
Yes/No? yes         

   

(parted) print                                                            
Model: DELL PERC 6/i Adapter (scsi)
Disk /dev/sda: 500GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start  End  Size  File system  Name  Flags

 

(parted)mkpart primary 0KB 500GB
Warning: You requested a partition from 0.00B to 500GB.                   
The closest location we can manage is 17.4kB to 500GB.
Is this still acceptable to you?
Yes/No? yes                                                               
Warning: The resulting partition is not properly aligned for best performance.
Ignore/Cancel? Ignore                          

 

(parted) print                                                            
Model: DELL PERC 6/i Adapter (scsi)
Disk /dev/sda: 500GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End    Size   File system  Name     Flags
 1      17.4kB  500GB  500GB               primary

 

(parted)quit                                                             
Information: You may need to update /etc/fstab.                           

root@node01:/#fdisk -l

WARNING: GPT (GUID Partition Table) detected on '/dev/sda'! The util fdisk doesn't support GPT. Use GNU Parted.


Disk /dev/sda: 499.6 GB, 499558383616 bytes
255 heads, 63 sectors/track, 60734 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1               1       60735   487849983+  ee  GPT

root@node01:/#mkfs.ext4 /dev/sda1
mke2fs 1.41.12 (17-May-2010)
文件系统标签=
操作系统:Linux
块大小=4096 (log=2)
分块大小=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
30490624 inodes, 121962487 blocks
6098124 blocks (5.00%) reserved for the super user
第一个数据块=0
Maximum filesystem blocks=4294967296
3722 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
        4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 
        102400000

正在写入inode表: 完成                            
Creating journal (32768 blocks): 完成
Writing superblocks and filesystem accounting information: 完成

This filesystem will be automatically checked every 24 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

 

root@node01:/#mount /dev/sda1 /export/glusterfs01/


root@node01:/# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/node01-root
                      6.8G  987M  5.5G  16% /
none                  7.9G  208K  7.9G   1% /dev
none                  7.9G     0  7.9G   0% /dev/shm
none                  7.9G   32K  7.9G   1% /var/run
none                  7.9G     0  7.9G   0% /var/lock
/dev/sdb1             228M   21M  196M  10% /boot
/dev/sda1             458G  198M  435G   1% /export/glusterfs01

 

root@node01:/#vi /etc/fstab

# /etc/fstab: static file system information.
#
# Use 'blkid -o value -s UUID' to print the universally unique identifier
# for a device; this may be used with UUID= as a more robust way to name
# devices that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
proc            /proc           proc    nodev,noexec,nosuid 0       0
/dev/mapper/node01-root /               ext4    errors=remount-ro 0       1
# /boot was on /dev/sdb1 during installation
UUID=c21707ff-ba0f-43ee-819a-8e72fa0f8500 /boot           ext2    defaults        0       2
/dev/mapper/node01-swap_1 none            swap    sw              0       0
/dev/sda1       /export/glusterfs01     ext4    defaults        0       2

 

重启就可以自动挂载了!至此完成。

@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
posted @ 2011-12-21 15:56 哈哈的日子 阅读(16418) | 评论 (0)编辑 收藏
1. cross join 就是笛卡尔积
那看起来好象和 inner join 是一样的,在 SQL 标准中定义的是 cross join 就是没有条件的 inner join。在 mysql 中,不区分,这两个等价。

2. natural (left) join 是把两个表名字一样的列,做相等条件处理,比如:

t1
id1 name

t2
id2 name

那么 select t1.id1, t2.id1, t1.name from t1 natural join t2 就等价

select t1.id1, t2.id1, t1.name from t1 join t2 on (t1.name = t2.name)

自动把一样名称的列(name)做了个相待条件处理,多列也会同时处理。

所以,这两种 join 没人用是有原因的。

cross join 没意义,一般用逗号就可以了。

natural 降低了可读性,不建议使用。
posted @ 2011-10-13 18:06 哈哈的日子 阅读(597) | 评论 (0)编辑 收藏
                一个好软件,会让人觉得赏心悦目
                 会让人心旷神怡
                 会开心
                 会……

H2DB 就是这样的一个好软件,就一个感觉----舒服!


比如:group by sort 的实现


    private void queryGroupSorted(int columnCount, ResultTarget result) {

        int rowNumber = 0;

        setCurrentRowNumber(0);

        Value[] previousKeyValues = null;

        while (topTableFilter.next()) {

            setCurrentRowNumber(rowNumber + 1);

            if (condition == null || Boolean.TRUE.equals(condition.getBooleanValue(session))) {

                rowNumber++;

                Value[] keyValues = new Value[groupIndex.length];

                // update group

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

                    int idx = groupIndex[i];

                    Expression expr = expressions.get(idx);

                    keyValues[i] = expr.getValue(session);

                }


                if (previousKeyValues == null) {

                    previousKeyValues = keyValues;

                    currentGroup = New.hashMap();

                } else if (!Arrays.equals(previousKeyValues, keyValues)) {

                    addGroupSortedRow(previousKeyValues, columnCount, result);

                    previousKeyValues = keyValues;

                    currentGroup = New.hashMap();

                }

                currentGroupRowId++;


                for (int i = 0; i < columnCount; i++) {

                    if (groupByExpression == null || !groupByExpression[i]) {

                        Expression expr = expressions.get(i);

                        expr.updateAggregate(session);

                    }

                }

            }

        }

        if (previousKeyValues != null) {

            addGroupSortedRow(previousKeyValues, columnCount, result);

        }

    }



看着太舒服了。

posted @ 2011-10-12 13:52 哈哈的日子 阅读(246) | 评论 (0)编辑 收藏
http://ivansmirnov.wordpress.com/2011/03/19/java-util-concurrent-locks-thread-dump/

The Sun JVM setting “-XX:+PrintConcurrentLocks” adds the lock owner information to the thread dump.
posted @ 2011-08-16 16:18 哈哈的日子 阅读(178) | 评论 (0)编辑 收藏
@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

http://en.wikipedia.org/wiki/Category:Unix_signals

1.SIGHUP信号

UNIX中进程组织结构为 session (会话)包含一个前台进程组及一个或多个后台进程组,一个进程组包含多个进程。一个session可能会有一个session首进程,而一个session首进程可能会有一个控制终端。一个进程组可能会有一个进程组首进程。进程组首进程的进程ID与该进程组ID相等。这儿是可能会有,在一定情况之下是没有的。与终端交互的进程是前台进程,否则便是后台进程。
SIGHUP会在以下3种情况下被发送给相应的进程:
1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进程)
2、session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程
3、若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。
统对SIGHUP信号的默认处理是止收到信号的程。所以若程序中没有捕捉信号,当收到信号程就会退出。
下面观察几种因终端关闭导致进程退出的情况,在这儿进程退出是因为收到了SIGHUP信号。login shell是session首进程。
首先写一个测试程序,代码如下:
#include <stdio.h>
#include 
<signal.h>
char **args;
void exithandle(int
 sig)
{
        printf(
"%s : sighup received ",args[1
]);
}

int main(int argc,char **argv)
{
        args 
=
 argv;
        signal(SIGHUP,exithandle);
        pause();
       
return 0
;
}
程序中捕捉SIGHUP信号后打印一条信息,pause()使程序暂停。
编译后的执行文件为sigtest。
1、命 令:sigtest front > tt.txt
   操 作:关闭终端
   结 果:tt.txt文件的内容为front : sighup received
   原 因: sigtest是前台进程,终端关闭后,根据上面提到的第1种情况,login shell作为session首进程,会收到SIGHUP信号然后退出。根据第2种情况,sigtest作为前台进程,会收到login shell发出的SIGHUP信号。
2、命 令:sigtest back > tt.txt &
     操 作:关闭终端
      结 果:tt.txt文件的内容为 back : sighup received
      原 因: sigtest是提交的job,根据上面提到的第1种情况,sigtest会收到SIGHUP信号。
3、命 令:写一个shell,内容为[sigtest &],然后执行该shell
      操 作:关闭终端
      结 果:ps -ef | grep sigtest 会看到该进程还在,tt文件为空
      原 因: 执行该shell时,sigtest作为job提交,然后该shell退出,致使sigtest变成了孤儿进程,不再是当前session的job了,因此sigtest即不是session首进程也不是job,不会收到SIGHUP。同时孤儿进程属于后台进程,因此login shell退出后不会发送SIGHUP给sigtest,因为它只将该信号发送给前台进程。第3条说过若进程组变成孤儿进程组的时候,若有进程处于停止状态,也会收到SIGHUP信号,但sigtest没有处于停止状态,所以不会收到SIGHUP信号。
4、命 令:nohup sigtest > tt
      操 作:关闭终端
      结 果:tt文件为空
      原 因: nohup可以防止进程收到SIGHUP信号
至此,我们就清楚了何种情况下终端关闭后进程会退出,何种情况下不会退出。


要想终端关闭后进程不退出有以下几种方法,均为通过shell的方式:
1、编写shell,内容如下
       trap "" SIGHUP #该句的作用是屏蔽SIGHUP信号,trap可以屏蔽很多信号
      sigtest
2、nohup sigtest 可以直接在命令行执行,
       若想做完该操作后继续别的操作,可以 nohup sigtest &
3、编写shell,内容如下
       sigtest &
       其实任何将进程变为孤儿进程的方式都可以,包括fork后父进程马上退出。

2.SIGCHLD信号

       子进程死后,会发送SIGCHLD信号给父进程。

        一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程 是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。

2.SIGTERM信号

kill() 可以发 SIGTERM 过去;kill 命令默认也使用 SIGTERM 信号。

SIGTERM 信号的处理函数,常见的是用来清理、退出;或者程序可以忽略这个信号,以防误杀。
        SIGTERM is the default signal sent to a process by the kill or killall commands. It causes the termination of a process, but unlike the SIGKILLsignal, it can be caught and interpreted (or ignored) by the process. Therefore, SIGTERM is more akin to asking a process to terminate nicely, allowing cleanup and closure of files. For this reason, on many Unix systems during shutdown, init issues SIGTERM to all processes that are not essential to powering off, waits a few seconds, and then issues SIGKILL to forcibly terminate other processes to allow the computer to halt.




linux kill信号列表
2009-04-13 17:00
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1
36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5
40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9
44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13
52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9
56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5
60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1
64) SIGRTMAX

列表中,编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。

下面我们对编号小于SIGRTMIN的信号进行讨论。

1) SIGHUP
本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联。

登录Linux时,系统会分配给登录用户一个终端(Session)。在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都属于这个 Session。当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进 程组和后台有终端输出的进程就会中止。不过可以捕获这个信号,比如wget能捕获SIGHUP信号,并忽略它,这样就算退出了Linux登录,wget也 能继续下载。

此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。

2) SIGINT
程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。

3) SIGQUIT
和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。

4) SIGILL
执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号。

5) SIGTRAP
由断点指令或其它trap指令产生. 由debugger使用。

6) SIGABRT
调用abort函数生成的信号。

7) SIGBUS
非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数, 但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。

8) SIGFPE
在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。

9) SIGKILL
用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。

10) SIGUSR1
留给用户使用

11) SIGSEGV
试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.

12) SIGUSR2
留给用户使用

13) SIGPIPE
管道破裂。这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止。

14) SIGALRM
时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号.

15) SIGTERM
程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。

17) SIGCHLD
子进程结束时, 父进程会收到这个信号。

如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程。这种情 况我们应该避免(父进程或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子进程,或者父进程先终止,这时子进程的终止自动由init进程来接管)。

18) SIGCONT
让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符...

19) SIGSTOP
停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.

20) SIGTSTP
停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号

21) SIGTTIN
当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行.

22) SIGTTOU
类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.

23) SIGURG
有"紧急"数据或out-of-band数据到达socket时产生.

24) SIGXCPU
超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变。

25) SIGXFSZ
当进程企图扩大文件以至于超过文件大小资源限制。

26) SIGVTALRM
虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.

27) SIGPROF
类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间.

28) SIGWINCH
窗口大小改变时发出.

29) SIGIO
文件描述符准备就绪, 可以开始进行输入/输出操作.

30) SIGPWR
Power failure

31) SIGSYS
非法的系统调用。

在以上列出的信号中,程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP
不能恢复至默认动作的信号有:SIGILL,SIGTRAP
默认会导致进程流产的信号有:SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ
默认会导致进程退出的信号有:SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM
默认会导致进程停止的信号有:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
默认进程忽略的信号有:SIGCHLD,SIGPWR,SIGURG,SIGWINCH

此外,SIGIO在SVR4是退出,在4.3BSD中是忽略;SIGCONT在进程挂起时是继续,否则是忽略,不能被阻塞。

posted @ 2011-08-16 11:55 哈哈的日子 阅读(766) | 评论 (0)编辑 收藏
会报错
sudo: sorry, you must have a tty to run sudo @import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

只要用 ssh -t 就可以了。

或者修改 /etc/suoders
将 requirestty 注释掉
posted @ 2011-08-15 12:05 哈哈的日子 阅读(1464) | 评论 (0)编辑 收藏
@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
1. 使用默认隔离级别 repeatable read
2. 开始,使用 select @@tx_isolation 确认当前 session 的隔离级别,并且创建个表 create table tt (id int, name varchar(300)) engine=innodb
3. 启动 transaction 1(t1),使用 start transaction
4. 启动 transaction 2(t2), 再开个 mysql,使用 start transaction
5. 在 t2 执行 select * from tt
6. 在 t1 执行 insert into tt  values(1, 'haha')
7. 在 t2 再次执行 select * from tt,是看不到数据的。
8. 在 t2 执行 update tt set name='hehe' where id=1
9. 在 t2 再再次执行 select * from tt,居然看到 id=1 那条 hehe 了!
10. 我们幻读了......

参考自:
http://blog.bitfly.cn/post/mysql-innodb-phantom-read/

原作者写得非常好


posted @ 2011-08-02 17:59 哈哈的日子 阅读(1448) | 评论 (4)编辑 收藏
     摘要: 转自:http://blog.csdn.net/wang382758656/article/details/5771332 @import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteed...  阅读全文
posted @ 2011-07-28 12:03 哈哈的日子 阅读(1324) | 评论 (2)编辑 收藏
@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
因为连接数的问题,我不得不在一台机器上多启 mysql instance

1. 建立两个 mysql 数据库实例
mysql_install_db --datadir=xxx
2. 配置 /etc/my.cnf

[client]
#password = your_password
#port = 3306
#socket = /var/lib/mysql/mysql.sock

# Here follows entries for some specific programs
[mysqld_multi] 
mysqld = /usr/bin/mysqld_safe 
mysqladmin = /usr/bin/mysqladmin 
user = mysql
password = mysql

[mysqld1]
datadir = /home/intple/mysql/data1
max_connections = 800

long_query_time = 0.1
#log-queries-not-using-indexes
slow_query_log = 1
slow_query_log_file = /var/log/mysql-slow.log

port = 3306
socket = /home/intple/mysql/data1/mysql.sock
skip-locking
key_buffer_size = 384M
max_allowed_packet = 1M
table_open_cache = 512
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 64M
thread_cache_size = 32
query_cache_size = 512M
# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 32

log-bin=mysql-bin

server-id = 1

binlog_format=mixed

innodb_buffer_pool_size = 20G
innodb_additional_mem_pool_size = 32M
innodb_thread_concurrency = 32
# Set .._log_file_size to 25 % of buffer pool size
innodb_log_file_size = 256M
innodb_log_buffer_size = 32M
innodb_flush_log_at_trx_commit = 1
innodb_autoextend_increment = 64M
innodb_lock_wait_timeout = 200

[mysqld2]
datadir = /home/intple/mysql/data2
max_connections = 800

long_query_time = 0.1
#log-queries-not-using-indexes
slow_query_log = 1
slow_query_log_file = /var/log/mysql2-slow.log

port = 3307
socket = /home/intple/mysql/data2/mysql2.sock
skip-locking
key_buffer_size = 384M
max_allowed_packet = 1M
table_open_cache = 512
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 64M
thread_cache_size = 32
query_cache_size = 512M
# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 32

log-bin=mysql-bin

server-id = 1

binlog_format=mixed

innodb_buffer_pool_size = 20G
innodb_additional_mem_pool_size = 32M
innodb_thread_concurrency = 32
# Set .._log_file_size to 25 % of buffer pool size
innodb_log_file_size = 256M
innodb_log_buffer_size = 32M
innodb_flush_log_at_trx_commit = 1
innodb_autoextend_increment = 64M
innodb_lock_wait_timeout = 200

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates

[myisamchk]
key_buffer_size = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout

3. 启动
mysqld_multi start 1 &
mysqld_multi start 2 &
posted @ 2011-07-12 15:59 哈哈的日子 阅读(552) | 评论 (0)编辑 收藏
应该是因为 ipv6 的原因,我 lsof -i -P | grep xxx , xxx 是那个 udp multicast 的 ip,是可以看到这个端口被使用了的,但还是一直报错。 Can't assign requested address
后来查了一下,在启动 java 参数上加上 -Djava.net.preferIPv4Stack=true 就解决了。
posted @ 2011-07-01 10:23 哈哈的日子 阅读(326) | 评论 (0)编辑 收藏

转自:http://xok.la/2010/01/mysqlslap_test.html

mysqlslap是官方提供的压力测试工具之一,官方介绍如下:

mysqlslap is a diagnostic program designed to emulate client load for a MySQL server and to report
the timing of each stage. It works as if multiple clients are accessing the server. mysqlslap is
available as of MySQL 5.1.4.

下面介绍一些常见参数:

--auto-generate-sql-write-number
每个线程中产生多少个insert
--auto-generate-sql-guid-primary
自动产生guid格式的主键
--number-of-queries=50000
每个连接客户端总共发起的查询次数
--concurrency=10,50,100
并发连接线程数,分别是10、50、100个并发
-i, --iterations
重复执行测试的次数
--number-char-cols=10
创建测试表的 char 型字段数量
--number-int-cols=10
创建测试表的 int 型字段数量

下面是一个完整的例子:

mysqlslap -hlocalhost -uroot --engine=innodb --auto-generate-sql-write-number=100000 \
--auto-generate-sql-guid-primary --concurrency=10,50,100 --number-of-queries=50000 \
--iterations=2 --number-char-cols=10 --number-int-cols=10 --auto-generate-sql \
--create-schema=sbtest --auto-generate-sql-load-type=mixed

具体的慢慢看手册吧,mysqlslap在mysql的目录的bin目录内。   

@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
posted @ 2011-06-28 16:58 哈哈的日子 阅读(176) | 评论 (0)编辑 收藏
按照如下步骤安装到 DBD::mysql 时,出错,提示找不到 mysql_config

perl -MCPAN -eshell
CPAN> install Time::HiRes
CPAN> install Term::ReadKey
CPAN> install DBI
CPAN> install DBD::mysql

需要到 mysql 网站下载

MySQL-devel-community-5.1.57-1.rhel5.x86_64.rpm

安装,才可以。
我找了半天。
posted @ 2011-06-22 13:39 哈哈的日子 阅读(166) | 评论 (0)编辑 收藏
转自:http://dolphin-ygj.iteye.com/blog/366314
vi替换命令用法详解
: ranges /pat1/pat2/g
其中
: 这是Vi的命令执行界面。
range 是命令执行范围的指定: 百分号(%)表示所有行
点(.)表示当前行
美元($)表示最末行

例如:
10,20表示第10到20行,
.,$表示当前行到最后一行,.
+2,$-5表示当前行后两行直到全文的倒数第五行

s 表示其后是一个替换命令。
pat1 这是要查找的一个正则表达式
pat2 这是希望把匹配串变成的模式的正则表达式

g 可选标志,带这个标志表示替换将针对行中每个匹配的串进行,否则则只替换行中第一个匹配串。


:/string #向下查找
:?stirng   # 向上查找


1

vi编辑命令责任编辑:黑色联想   更新日期:2006-9-7重复执行命令
数字N+命令     重复执行命令N次,如删除15行,就在命令状态下输入15dd
.              重复执行上一条命令
vi命令使用的一些选项及含义
-c sub-command 在对指定的文件编辑前,先执行指定的命令 sub-command .
-r filename 恢复指定的文件filename .
-R 将指定的文件以只读的方式放入编辑器中,这样不会保存对文件的任何修 改。
-y number 将编辑窗口的大小设为number行。
光标移动
命令模式下,在同一行上移动的子命令:
h   将光标左移一格
l   将光标右移一格
j   将光标下移一格
k   将光标上移一格
w   将光标移到下一个小字的前面
W  将光标移到下一个大字的前面
b   将光标移到前一个小字的前面
B   将光标移到前一个大字的前面
e   将光标移到下一个小字的后面
E   将光标移到前一个大字的后面
fc  把光标移到同一行的下一个c字符处
Fc  把光标移到同一行的前一个c字符处
tc  把光标移到同一行的下一个字符c的前一格
Tc  把光标移到同一行的前一个字符c的后一格
number|把光标移到递number列上
命令模式下在行间移动的子命令:     
+或Enter   把光标移至下一行第一个非空白字符
-   把光标移至上一行第一个非空白字符 
0   把光标移到当前行的第一个字符处
$   把光标移到当前行的最后一个字符处
H   把光标移到屏幕最顶端一行
L   把光标移到屏幕最底端一行
M  把光标移到屏幕中间
:number 光标移动到第number行
:$  光标移动到最后以行
屏幕翻滚类命令
Ctrl+u   向文件首翻半屏
Ctrl+d   向文件尾翻半屏
Ctrl+f   向文件尾翻一屏
Ctrl+b  向文件首翻一屏
nz     将第n行滚至屏幕顶部,不指定n时将当前行滚至屏幕顶部
插入文本
I   在光标前
I   在当前行首
a   光标后
A   在当前行尾
o   在当前行之下新开一行
O  在当前行之上新开一行
r   替换当前字符
R   替换当前字符及其后的字符,直至按ESC键
s   从当前光标位置处开始,以输入的文本替代指定数目的字符
S   删除指定数目的行,并以所输入文本代替之
ncw或nCW  修改n个单词
nCC修改指定数目的行
删除
x       删除光标所指的一个字母
X      删除光标左边的一个字母
dd     删除光标所在的一行文字,同时本行文字会放到缓存中
d0     删至行首
d$     删至行尾
D      删除本行光标右边的所有文字,包括光标位置的字母
d$     删除本行光标右边的所有文字,包括光标位置的字母
dw     删除光标右边的一个单词
ndw    删除n个单词
d1G       删除光标所在行以上的所有行
dG     删除光标所在行及光标以下所有行
复制
yy          复制本行文字到缓存中
number yy   复制number行到缓存中
粘贴
p      把缓存中的行粘贴到光标所在的下一行,
P      把缓存中的行粘贴到光标所在的上一行
替换
:s/pattern1/pattern2/g    把光标当前行的pattern1替换为pattern2
:%s/pattern1/pattern2/g   把所有行的pattern1替换为pattern2
:g/parttern1/s//parttern2  把所有行的pattern1替换为pattern2
:num1,num2 s/pattern1/pattern2/g     把num1到num2的partten1替换为partten2
被替换的文字用^表示行首,$表示行尾,如:%s/^/111/g就表示在每一行的行首插入111
文件
:r filename   把文件filename的内容粘贴在光标以下行
:w         保存当前编辑的文件名
:w filename  当filename不存在时,把修改后的文件存为文件filename ,当文件filename
存在时,报错。
!w filename  如果文件filename存在时,把修改后的文件保存为文件filename
:q         退出vi ,若文件被修改,系统不会让用户使用q命令退出
q!         不保存退出
x          保存退出
wq         保存退出
在多个文件之间切换
:n开始编辑vi激活的文件列表中的下一个文件
:n filenames 指定将被编辑的新的文件列表
在当前文件和另外一个文件间切换:
:e filename  使用filename激活vi(在vi中装入另一个文件filename)
e!         重新装入当前文件,若当前文件有改动,则丢弃以前的改动
:e+filename  使用filename激活vi ,并从文件尾部开始编辑
:e+number filename  使用filename激活vi ,并在第number行开始编辑
:e#        开始编辑另外一个文件
查找
/pattern     向后寻找指定的pattern ,若遇到文件尾,则从头再开始。
?pattern   向前寻找指定的pattern ,若遇到文件头,则从尾再开始。
n          在上次指定的方向上,再次执行上次定义的查找。
N         在上次指定的方向的相反方向上,再次执行上次定义的查找。
/pattern/+number    将光标停在包含pattern的行后面第number行上。
/pattern/-number     将光标停在包含pattern的行前面第number行上。
%                移到匹配的"()"或"{}"上。
选项设置
all         列出所有选项设置情况
term        设置终端类型
ignorance   在搜索中忽略大小写
list         显示制表位(Ctrl+I)和行尾标志($)
number    显示行号
report       显示由面向行的命令修改过的数目
terse       显示简短的警告信息
warn        在转到别的文件时若没保存当前文件则显示NO write信息
nomagic     允许在搜索模式中,使用前面不带“\”的特殊字符
nowrapscan 禁止vi在搜索到达文件两端时,又从另一端开始
mesg       允许vi显示其他用户用write写到自己终端上的信息
、在vi中使用的查找替换方法
利用 :s 命令可以实现字符串的替换。具体的用法包括:
:s/str1/str2/ 用字符串 str2 替换行中首次出现的字符串str1
:s/str1/str2/g 用字符串 str2 替换行中所有出现的字符串str1
:.,$ s/str1/str2/g 用字符串 str2 替换正文当前行到末尾所有出现的字符串str1
:1,$ s/str1/str2/g 用字符串 str2 替换正文中所有出现的字符串str1
:g/str1/s//str2/g 功能同上从上述替换命令可以看到:g 放在命令末尾,表示对搜索字符串的每次出现进行替换;不加 g,表示只对搜索字符串的首次出现进行替换;g 放在命令开头,表示对正文中所有包含搜索字符串的行进行替换操作。

2、在shell中使用find结合grep进行文件的替换
# find ./ -exec grep str1 ‘{}’ \; -exec sed -i.bak s/str1/str2/g ‘{}’ \;
上面命令可以在当前目录下(包括子目录)查找包含str1的文件,自动替换成str2,并且生成源文件的bak文件。

 
posted @ 2011-06-17 15:39 哈哈的日子 阅读(171) | 评论 (0)编辑 收藏
准备写一个说不清楚的问题,我表示鸭梨很大。

背景:
    1. 业务分区,多用户,用户间无交叉
    2. 水平切分,一张表存到两个库里去
Bug:
    用户1引用了用户2的数据(这不算什么,后面一句才重要),平时看不出来
问题:
    第一场
    用户1来了,建了一大堆东西。
    用户2来了,关联了用户1的东西,因为都分库到 s1, s2,所以,相安无事。
    第二场
    用户1来了,又建了一大堆东西。
    用户2来了,又想关联用户1的数据。但是,却分库到 s2, s1,注意顺序不一样,然后,没关联到,出错了。

我另外发现了一个问题,我真无聊。
posted @ 2011-06-07 17:18 哈哈的日子 阅读(127) | 评论 (0)编辑 收藏
目前项目有个需要,就是在所有查询的参数中,增加一个属性。
自然想到使用 interceptor 将每个 parameter wraper 一下,加上这个属性
我就使用 cglib 生成了一个 wrapper class,然后再 proxy 到原来的 parameter 上。

后来,出了错误,找了好长时间,发现
ibatis sql 中写着 isPrimary,可其实在 java 里是这样的

private boolean isPrimary;
public boolean isPrimary() {
    return isPrimary;
}

其实属性名字是 primary 啊,为什么在 wrapper 之前就不出错呢。

找了一下,ibatis 是通过他自己的 probe 来获得属性值的,这个 probe 不仅会通过方法取值,还会通过 field name 取值,没访问权限的,还会加上权限。

就是 ClassInfo 的下面方法


  private void addFields(Class clazz) {

    Field[] fields = clazz.getDeclaredFields();

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

      Field field = fields[i];

      if (canAccessPrivateMethods()) {

        try {

          field.setAccessible(true);

        } catch (Exception e) {

          // Ignored. This is only a final precaution, nothing we can do.

        }

      }

      if (field.isAccessible()) {

        if (!setMethods.containsKey(field.getName())) {

          addSetField(field);

        }

        if (!getMethods.containsKey(field.getName())) {

          addGetField(field);

        }

      }

    }

    if (clazz.getSuperclass() != null) {

      addFields(clazz.getSuperclass());

    }

  }


解决办法,将 isPrimary 改成 primary

posted @ 2011-06-01 15:58 哈哈的日子 阅读(170) | 评论 (0)编辑 收藏
也一直使用 quartz,但没仔细看过,看了一个非常详细的文章,转发一下。另外,官方文档链接也附在下面:
http://www.quartz-scheduler.org/docs/tutorials/crontrigger.html

转自:http://wangrui.iteye.com/blog/150947

 一个Cron表达式是由7个子表达式组成的字符串,这些子表达式用空格分隔,其中最后一个子表达式是可选的,其他都是必须的。每个子表达式都描述了一个单独的日程细节。每一个子表达式的含义如下: 

子表达式名称(取值范围)(允许的特殊字符) 
1.Seconds秒 (0-59) (, - * /) 
2.Minutes分钟 (0-59) (, - * /) 
3.Hours小时 (0-23) (, - * /) 
4.Day-of-Month月中的天 (1-31) (, - * ? / L W) 
5.Month月 (1-12或JAN-DEC) (, - * /) 
6.Day-of-Week周中的天 (1-7或SUN-SAT) (, - * ? / L #) 
7.Year(optional)年(可选) (空或1970-2099) (, - * /) 

    一个cron表达式的例子字符串为"0 0 12 ? * WED",这表示“每周三的中午12:00”。 
    
    单个子表达式可以包含范围或者列表。例如:前面例子中的周中的天这个域(这里是"WED")可以被替换为"MON-FRI", "MON, WED, FRI"或者甚至"MON-WED,SAT"。 
    
    所有的域中的值都有特定的合法范围,这些值的合法范围相当明显,例如:秒和分域的合法值为0到59,小时的合法范围是0到23,Day-of-Month中值得合法凡范围是0到31,但是需要注意不同的月份中的天数不同。月份的合法值是0到11。或者用字符串JAN,FEB MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 及DEC来表示。Days-of-Week可以用1到7来表示(1=星期日)或者用字符串SUN, MON, TUE, WED, THU, FRI 和SAT来表示.  
    
    通配符('*')可以被用来表示域中“每个”可能的值。因此在"Month"域中的*表示每个月,而在Day-Of-Week域中的*则表示“周中的每一天”。 
    
    '?'字符可以用在day-of-month及day-of-week域中,它用来表示“没有指定值”。这对于需要指定一个或者两个域的值而不需要对其他域进行设置来说相当有用。 

    '/'字符用来表示值的增量,例如, 如果分钟域中放入'0/15',它表示“每隔15分钟,从0开始”,如果在份中域中使用'3/20',则表示“小时中每隔20分钟,从第3分钟开始”或者另外相同的形式就是'3,23,43'。 

    'L'字符可以在day-of-month及day-of-week中使用,这个字符是"last"的简写,但是在两个域中的意义不同。例如,在day-of-month域中的"L"表示这个月的最后一天,即,一月的31日,非闰年的二月的28日。如果它用在day-of-week中,则表示"7"或者"SAT"。但是如果在day-of-week域中,这个字符跟在别的值后面,则表示"当月的最后的周XXX"。例如:"6L" 或者 "FRIL"都表示本月的最后一个周五。当使用'L'选项时,最重要的是不要指定列表或者值范围,否则会导致混乱。 

    'W' 字符用来指定距离给定日最接近的周几(在day-of-week域中指定)。例如:如果你为day-of-month域指定为"15W",则表示“距离月中15号最近的周几”。 

    '#'表示表示月中的第几个周几。例如:day-of-week域中的"6#3" 或者 "FRI#3"表示“月中第三个周五”。 
posted @ 2011-05-30 10:23 哈哈的日子 阅读(234) | 评论 (0)编辑 收藏
1. 在之前的2.x版本下,我一般编译程序到机子的做法是修改xproject去掉iPhone Developer的方法,(参考http://www.cocoachina.com/bbs/read.php?tid-1822-fpage-4.html )
如果以前这样修改过xproject文件的,要先恢复到原始状态,把iPhone Developer那句话加回去(随意找个2.x时期的官方sample就有)
2. 制作自己的证书,制作方法参考http://www.weiphone.com/thread-222380-1-1.html ,说明的是,最后的存放位置据说应该是登录(login)而不是系统,反正我现在用的就是登录.
3. 打开终端,执行如下代码,这个是XCode的补丁,因为在3.13的xcode修补了3.12的免签名漏洞,打这个补丁才行
#!/bin/bash
cd /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneOS\ Build\ System\ Support.xcplugin/Contents/MacOS/
dd if=iPhoneOS\ Build\ System\ Support of=working bs=500 count=255
printf "\x8f\x2a\x00\x00" >> working
dd if=iPhoneOS\ Build\ System\ Support of=working bs=1 skip=127504 seek=127504
/bin/mv -n iPhoneOS\ Build\ System\ Support iPhoneOS\ Build\ System\ Support.original
/bin/mv working iPhoneOS\ Build\ System\ Support
chmod a+x iPhoneOS\ Build\ System\ Support
 
或者你懒的去执行,也可以下载这个文件(要解压下)    patch.sh.zip (1 K) 下载次数:103 放在用户根目录,执行
sudo sh ./patch.sh

4. 在终端执行如下命令

mkdir /Developer/iphoneentitlements30
cd /Developer/iphoneentitlements30
curl -O http://www.alexwhittemore.com/iphone/gen_entitlements.txt 
mv gen_entitlements.txt gen_entitlements.py
chmod 777 gen_entitlements.py

5. XCode中打开你的project,在菜单project->New Build Phase > New Run Script Build Phase,那个script空白框,拷贝如下代码进去

export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate
if [ "${PLATFORM_NAME}" == "iphoneos" ]; then
/Developer/iphoneentitlements30/gen_entitlements.py "my.company.${PROJECT_NAME}" "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${PROJECT_NAME}.xcent";
codesign -f -s "iPhone Developer" --resource-rules "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/ResourceRules.plist" \
--entitlements "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${PROJECT_NAME}.xcent"  "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/"
fi
 

6. 修改"/Developer/Platforms/iPhoneOS.platform/Info.plist"文件,默认是用Property List Editor打开,然后添加:
PROVISIONING_PROFILE_ALLOWED = NO
PROVISIONING_PROFILE_REQUIRED = NO

7. 在你的project的info.list里面增加一行,也就是你之前步骤2建的自定义的证书名字啦.
SignerIdentity=iPhone Developer 

8. 把你的iphone连接到电脑,提示连接成功,后 xcode菜单,window->Organizer里面,把iphone设为调试设备.
对了,我忘记了我做的一个步骤,不知道是不是必须的,这里补上
9. iphone要安装MobileInstallation Patch ,安装步骤:打开cydia,进入manage->sources->edit->Add,在网址输入框里面输入www.iphone.org.hk/adp/ 
完成后,进入sources 可以看到www.iphone.org.hk 这个网站,然后进去,可以找到MobileInstallation Patch,点击安装即可.
安装完成重启手机.
posted @ 2011-05-17 00:29 哈哈的日子 阅读(232) | 评论 (0)编辑 收藏

转自:http://blog.csdn.net/cafecheng/archive/2009/07/17/4357248.aspx



H2, HSQLDB, DERBY, POSTGRESQL, MYSQL

openSourceDatabaseComparison

posted @ 2011-05-06 16:58 哈哈的日子 阅读(1083) | 评论 (0)编辑 收藏
     摘要: 转自:http://www.001pp.com/chengxuyouhua/mysql%20xingnengyouhua2183.html 网上有不少mysql 性能优化方案,不过,mysql的优化同sql server相比,更为麻烦与负责,同样的设置,在不同的环境下 ,由于内存,访问量,读写频率,数据差异等等情况,可能会出现不同的结果,因此简单地根据某个给出方案来配置mysql是行不通的,...  阅读全文
posted @ 2011-05-04 15:50 哈哈的日子 阅读(169) | 评论 (0)编辑 收藏

转自 http://imysql.cn/node/609

作/译者:吴炳锡,来源:http://imysql.cn & http://imysql.cn/blog/3208 转载请注明作/译者和出处,并且不能用于商业用途,违者必究。

 

介绍:
InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句提供一个Oracle风格一致的非锁定读。这些特色增加了多用户部署和性能。没有在InnoDB中扩大锁定的需要,因为在InnoDB中行级锁定适合非常小的空间。InnoDB也支持FOREIGN KEY强制。在SQL查询中,你可以自由地将InnoDB类型的表与其它MySQL的表的类型混合起来,甚至在同一个查询中也可以混合。
Innodb 的创始人:Heikki Tuuri
Heikki Tuuri在Innodb的Bug社区里也是很活跃的,如果遇到Bug也可以直接提到社区,得到作者的解答。

为什么要学习Innodb的调优:
目前来说:InnoDB是为Mysql处理巨大数据量时的最大性能设计。它的CPU效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的。在数据量大的网站或是应用中Innodb是倍受青睐的。
另一方面,在数据库的复制操作中Innodb也是能保证master和slave数据一致有一定的作用。

参数调优内容:
  1. 内存利用方面
2. 日值控制方面
3. 文件IO分配,空间占用方面
4. 其它相关参数

1.内存利用方面:
首先介绍一个Innodb最重要的参数:
innodb_buffer_pool_size
这个参数和MyISAM的key_buffer_size有相似之处,但也是有差别的。这个参数主要缓存innodb表的索引,数据,插入数据时的缓冲。为Innodb加速优化首要参数。
该参数分配内存的原则:这个参数默认分配只有8M,可以说是非常小的一个值。如果是一个专用DB服务器,那么他可以占到内存的70%-80%。这个参数不能动态更改,所以分配需多考虑。分配过大,会使Swap占用过多,致使Mysql的查询特慢。如果你的数据比较小,那么可分配是你的数据大小+10%左右做为这个参数的值。例如:数据大小为50M,那么给这个值分配innodb_buffer_pool_size=64M
设置方法:
innodb_buffer_pool_size=4G
这个参数分配值的使用情况可以根据show innodb status\G;中的
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 4668764894;
 
去确认使用情况。


第二个:
innodb_additional_mem_pool:
作用:用来存放Innodb的内部目录
这个值不用分配太大,系统可以自动调。不用设置太高。通常比较大数据设置16M够用了,如果表比较多,可以适当的增大。如果这个值自动增加,会在error log有中显示的。
分配原则:
show innodb status\G;去查看运行中的DB是什么状态(参考BUFFER POOL AND MEMORY段中),然后可以调整到适当的值。
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 4668764894; in additional pool allocated 16777216
参考:in additional pool allocated 16777216
根据你的参数情况,可以适当的调整。
设置方法:
innodb_additional_mem_pool=16M


2.关于日值方面:
innodb_log_file_size
作用:指定日值的大小
分配原则:几个日值成员大小加起来差不多和你的innodb_buffer_pool_size相等。上限为每个日值上限大小为4G.一般控制在几个LOG文件相加大小在2G以内为佳。具体情况还需要看你的事务大小,数据大小为依据。
说明:这个值分配的大小和数据库的写入速度,事务大小,异常重启后的恢复有很大的关系。
设置方法:
innodb_log_file_size=256M


innodb_log_files_in_group
作用:指定你有几个日值组。
分配原则: 一般我们可以用2-3个日值组。默认为两个。
设置方法:
innodb_log_files_in_group=3


innodb_log_buffer_size:
作用:事务在内存中的缓冲。
分配原则:控制在2-8M.这个值不用太多的。他里面的内存一般一秒钟写到磁盘一次。具体写入方式和你的事务提交方式有关。在Oracle等数据库了解这个,一般最大指定为3M比较合适。
参考:Innodb_os_log_written(show global status 可以拿到)
如果这个值增长过快,可以适当的增加innodb_log_buffer_size
另外如果你需要处理大理的TEXT,或是BLOB字段,可以考虑增加这个参数的值。
设置方法:
innodb_log_buffer_size=3M

innodb_flush_logs_at_trx_commit
作用:控制事务的提交方式
分配原则:这个参数只有3个值,0,1,2请确认一下自已能接受的级别。默认为1,主库请不要更改了。
性能更高的可以设置为0或是2,但会丢失一秒钟的事务。
说明:
这个参数的设置对Innodb的性能有很大的影响,所以在这里给多说明一下。
当这个值为1时:innodb 的事务LOG在每次提交后写入日值文件,并对日值做刷新到磁盘。这个可以做到不丢任何一个事务。
当这个值为2时:在每个提交,日志缓冲被写到文件,但不对日志文件做到磁盘操作的刷新,在对日志文件的刷新在值为2的情况也每秒发生一次。但需要注意的是,由于进程调用方面的问题,并不能保证每秒100%的发生。从而在性能上是最快的。但操作系统崩溃或掉电才会删除最后一秒的事务。
当这个值为0时:日志缓冲每秒一次地被写到日志文件,并且对日志文件做到磁盘操作的刷新,但是在一个事务提交不做任何操作。mysqld进程的崩溃会删除崩溃前最后一秒的事务。

从以上分析,当这个值不为1时,可以取得较好的性能,但遇到异常会有损失,所以需要根据自已的情况去衡量。


设置方法:
innodb_flush_logs_at_trx_commit=1

3. 文件IO分配,空间占用方面
innodb_file_per_table
作用:使每个Innodb的表,有自已独立的表空间。如删除文件后可以回收那部分空间。
分配原则:只有使用不使用。但DB还需要有一个公共的表空间。
设置方法:
innodb_file_per_table=1

innodb_file_io_threads
作用:文件读写IO数,这个参数只在Windows上起作用。在LINUX上只会等于4
设置方法:
innodb_file_io_threads=4

innodb_open_files
作用:限制Innodb能打开的表的数据。
分配原则:如果库里的表特别多的情况,请增加这个。这个值默认是300。
设置方法:
innodb_open_files=800 
请适当的增加table_cache


4. 其它相关参数
这里说明一个比较重要的参数:
innodb_flush_method
作用:Innodb和系统打交道的一个IO模型
分配原则:Windows不用设置。
Unix可以设置:fsync() or O_SYNC/O_DSYNC
如果系统可以禁止系统的Cache那就把他禁了。
Linux可以选择:O_DIRECT 
直接写入磁盘,禁止系统Cache了
设置方法:
innodb_flush_method=O_DIRECT

innodb_max_dirty_pages_pct 
作用:控制Innodb的脏页在缓冲中在那个百分比之下,值在范围1-100,默认为90.
这个参数的另一个用处:当Innodb的内存分配过大,致使Swap占用严重时,可以适当的减小调整这个值,使达到Swap空间释放出来。建义:这个值最大在90%,最小在15%。太大,缓存中每次更新需要致换数据页太多,太小,放的数据页太小,更新操作太慢。
设置方法:
innodb_max_dirty_pages_pct=90
动态更改需要有Super权限:
set global innodb_max_dirty_pages_pct=50;

总结:
这里只算是列出了Innodb部分的重要参数,不能认为是对Mysql的整体调优。Mysql的参数一般分为:全局参数,具体引擎的参数。全局参数方面请参考http://imysql.cn/2007_12_08_optimize_mysql_under_linux yejr的那个Mysql调优的PPT。

posted @ 2011-05-04 15:37 哈哈的日子 阅读(199) | 评论 (0)编辑 收藏
手动创建目录 .ssh 的时候,权限可能不对,默认应该是 775,这样不行,需要改成 755 或者 700 之类的,才可以。
authorized_keys 文件权限也要改成 600

顺便把步骤写一下:

1. ssh-keygen 生成 key pair,默认是 rsa 的
2. 把 public key 放到服务器上,然后执行 cat xxx >> ~/.ssh/authorized_keys,xxx 是 public key 文件名

posted @ 2011-05-04 10:04 哈哈的日子 阅读(185) | 评论 (0)编辑 收藏
     摘要: 转自:http://blogold.chinaunix.net/u3/102731/showart_2270571.html http://book.51cto.com/art/200803/68118.htm 摘要:《深 入浅出MySQL——数据库开发、优化与管理维护》从数据库的基础、开发、优化、管理4方面对MySQL进行了详细的介绍,其中每一部分都独立成篇,每一 篇又包括多个章节。本书...  阅读全文
posted @ 2011-04-26 11:29 哈哈的日子 阅读(583) | 评论 (0)编辑 收藏
转自:http://5iwww.blog.51cto.com/856039/340985


shell> mysqlbinlog log-file
使用mysqldumpslow命令获得日志中显示的查询摘要来处理慢查询日志, 例如:
[zzx@bj37 data]$ mysqldumpslow bj37-slow.log

一.1 获 取锁等待情况
可以通过检查 table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定争夺:
mysql> show status like 'Table%';
+----------------------------+----------+
| Variable_name | Value |
+----------------------------+----------+
| Table_locks_immediate | 105 |
| Table_locks_waited | 3 |
+----------------------------+----------+
2 rows in set (0.00 sec)
可以通过检查 Innodb_row_lock状态变量来分析系统上的行锁的争夺情况:
mysql> show status like 'innodb_row_lock%';
+----------------------------------------+----------+
| Variable_name | Value |
+----------------------------------------+----------+
| Innodb_row_lock_current_waits | 0 |
| Innodb_row_lock_time | 2001 |
| Innodb_row_lock_time_avg | 667 |
| Innodb_row_lock_time_max | 845 |
| Innodb_row_lock_waits | 3 |
+----------------------------------------+----------+
5 rows in set (0.00 sec)
另外,针对Innodb类型的表,如果 需要察看当前的锁等待情况,可以设置InnoDB Monitors,然后通过Show innodb status察看,设置的方式是:
CREATE TABLE innodb_monitor(a INT) ENGINE=INNODB;
监视器可以通过发出下列语句来被停止:
DROP TABLE innodb_monitor;
设置监视器后,在show innodb status的显示内容中,会有详细的当前锁等待的信息,包括表名、锁类型、锁定记录的情况等等,便于进行进一步的分析和问题的确定。打开监视器以后,默 认情况下每15秒会向日志中记录监控的内容,如果长时间打开会导致.err文件变得非常的巨大,所以我们在确认问题原因之后,要记得删除监控表以关闭监视 器。或者通过使用--console选项来启动服务器以关闭写日志文件。


如果是root帐号,你能看到所有用户的当前连接。如果是其它普通帐号,只能看到自己占用的连接。 
show processlist;只 列出前100条,如果想全列出请使用show full processlist; 
mysql> show processlist;(非常管用哦)
posted @ 2011-04-26 10:17 哈哈的日子 阅读(2853) | 评论 (0)编辑 收藏
转自51cto:http://g.51cto.com/mike/67136

动innodb_monitor的方法
 
在使用Innodb做为存储引擎的数据库系统中,可以使用innodb_monitor 来监控数据库的性能,启动innodb_monitor的方法为 Create table innodb_monitor (i int) engine=innodb 通过建立这个表就启动了innodb_monitor,监控的结果并不会记录到这个表中,而是记录到了mysql的err日志中,如果我们想监控更我的关于innodb的锁信息还可更进一步的建立表create table innodb_lock_monitor (i int) engine=innodb 这样在日志中会加入更多的锁信息,如果要关闭监控只要简单的删除这两个表就可以了.Drop table innodb_monitor; drop table innodb_lock_monitor;
 
用InnoDB monitor 可以监控死锁的情况等用InnoDB monitor 可以监控死锁的情况等
 
InnoDB引擎提供了一个monitor,可以通过monitor一窥其内部的一些统计信息,也可以说是了解InnoDB引擎的一个很好的窗口。
我们最熟悉的,应当就是show innodb status命令,可以直接在客户端输出很多的信息。其实InnoDB monitor一共有四种模式,show innodb status只是其一种模式的直接展现,并且只能交互式开启,无法自动循环捕获信息。另外还有一种适合四种模式的开启方式,则是通过创建一张特殊的innodb表来开启,开启后会按照固定的时间间隔循环,输出信息到log-error参数指定的错误日志文件中,通过drop对应的表,可以停止monitor。
四种monitor分别是:
  • innodb_monitor:create table innodb_monitor(x int) engine=innodb;
  • innodb_lock_monitor:create table innodb_lock_monitor(x int) engine=innodb;
  • innodb_table_monitor:create table innodb_table_monitor(x int) engine=innodb;
  • innodb_tablespace_monitor:create table innodb_tablespace_monitor(x int) engine=innodb;
根据我在5.1.36版本中实际观察到的结果,innodb_monitor/innodb_lock_monitor开启后的执行周期是16s参考手册上说是15s),而innodb_table_monitor/innodb_tablespace_monitor的执行周期是64s。开启monitor后因为是持续周期性的运行的,在不需要的时候一定要记得drop相关表来停止monitor。如果在开启monitor的中间服务器有重启,monitor不会自动重启,并且在下次启动monitor之前,必须先执行停止操作。
其中innodb_monitor/innodb_lock_monitor两种监视器的输出结果基本类似,后者会有更多关于锁的信息,而前一个实际上就是show innodb status。innodb_table_monitor则会将系统中所有innodb的表的一些结构和内部信息输出,而innodb_tablespace_monitor则输出的是tablespace的信息,注意该monitor输出的只是共享表空间的信息,如果使用innodb_file_per_table为每个表使用独立的表空间,则这些表空间的信息是不会包含在输出中的。
以下是一些简单的示例:
innodb_monitor/innodb_lock_monitor:
=====================================
090805 22:24:48 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 19 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 312921, signal count 308229
Mutex spin waits 0, rounds 18209349, OS waits 111906
RW-shared spins 287775, OS waits 142204; RW-excl spins 175036, OS waits 19318
------------
TRANSACTIONS
------------
Trx id counter 0 121675664
Purge done for trx's n:o < 0 121675662 undo n:o < 0 0
History list length 10
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 121462143, not started, process no 8452, OS thread id 1160767840
mysql tables in use 1, locked 1
MySQL thread id 8056144, query id 78206864 localhost root
---TRANSACTION 0 137229, not started, process no 8452, OS thread id 1158199648
MySQL thread id 50, query id 377 Has read all relay log; waiting for the slave I/O thread to update it
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
34 OS file reads, 80820900 OS file writes, 1263117 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 1.16 writes/s, 0.63 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2,
0 inserts, 0 merged recs, 0 merges
Hash table size 8850487, node heap has 233 buffer(s)
0.11 hash searches/s, 0.42 non-hash searches/s
---
LOG
---
Log sequence number 4 3697502095
Log flushed up to   4 3697502095
Last checkpoint at  4 3697502095
0 pending log writes, 0 pending chkp writes
79595438 log i/o's done, 0.47 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 4851752298; in additional pool allocated 13195520
Dictionary memory allocated 145784
Buffer pool size   262144
Free buffers       193334
Database pages     68577
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 70, created 120513, written 2829967
0.00 reads/s, 0.21 creates/s, 0.84 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
1 read views open inside InnoDB
Main thread process no. 8452, id 1157658976, state: waiting for server activity
Number of rows inserted 12233742, updated 57497659, deleted 1, read 69720050
0.05 inserts/s, 0.05 updates/s, 0.00 deletes/s, 0.05 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================
innodb_table_monitor:
===========================================
090805 22:26:56 INNODB TABLE MONITOR OUTPUT
===========================================
--------------------------------------
TABLE: name SYS_FOREIGN, id 0 11, columns 7, indexes 3, appr.rows 0
COLUMNS: ID: DATA_VARCHAR prtype 1835012 len 0; FOR_NAME: DATA_VARCHAR prtype 1835012 len 0;
REF_NAME: DATA_VARCHAR prtype 1835012 len 0; N_COLS: DATA_INT len 4;
DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR:
DATA_SYS prtype 258 len 7;   INDEX: name ID_IND, id 0 11, fields 1/6, uniq 1, type 3
root page 46, appr.key vals 0, leaf pages 1, size pages 1
FIELDS:  ID DB_TRX_ID DB_ROLL_PTR FOR_NAME REF_NAME N_COLS
INDEX: name FOR_IND, id 0 12, fields 1/2, uniq 2, type 0
root page 47, appr.key vals 0, leaf pages 1, size pages 1
FIELDS:  FOR_NAME ID
INDEX: name REF_IND, id 0 13, fields 1/2, uniq 2, type 0
root page 48, appr.key vals 0, leaf pages 1, size pages 1
FIELDS:  REF_NAME ID
...省略若干输出
--------------------------------------
TABLE: name test/test, id 0 81, columns 4, indexes 1, appr.rows 3
COLUMNS: i: DATA_INT DATA_BINARY_TYPE len 4; DB_ROW_ID: DATA_SYS prtype 256 len 6;
DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7;
INDEX: name GEN_CLUST_INDEX, id 0 23, fields 0/4, uniq 1, type 1
root page 3, appr.key vals 3, leaf pages 1, size pages 1
FIELDS:  DB_ROW_ID DB_TRX_ID DB_ROLL_PTR i
-----------------------------------
END OF INNODB TABLE MONITOR OUTPUT
==================================
innodb_tablespace_monitor:
================================================
090805 22:28:16 INNODB TABLESPACE MONITOR OUTPUT
================================================
FILE SPACE INFO: id 0
size 65536, free limit 6208, free extents 89
not full frag extents 6: used pages 69, full frag extents 0
first seg id not used 0 1067667
SEGMENT id 0 1067666 space 0; page 903; res 1 used 1; full ext 0
fragm pages 1; free extents 0; not full extents 0: pages 0
...省略若干输出
SEGMENT id 0 144216 space 0; page 1307; res 1 used 1; full ext 0
fragm pages 1; free extents 0; not full extents 0: pages 0
NUMBER of file segments: 37
Validating tablespace
Validation ok
---------------------------------------
END OF INNODB TABLESPACE MONITOR OUTPUT
=======================================
posted @ 2011-04-26 09:53 哈哈的日子 阅读(285) | 评论 (0)编辑 收藏

转自MySQL 中文网:http://imysql.cn/2008_05_22_walk_through_show_innodb_status
感谢两个作者,呵呵

原文作者: Peter Zaitsev
原文来源: http://www.mysqlperformanceblog.com/2006/07/17/show-innodb-status-walk-through/
译者:叶金荣(Email:),转载请注明译者和出处,并且不能用于商业用途,违者必究。

 

很多人让我来阐述一下 SHOW INNODB STATUS 的输出信息, 了解 SHOW INNODB STATUS 都输出了些什么信息,并且我们能从这些信息中获取什么资讯,得以提高 MySQL 性能。

首先,让我们来了解一下 SHOW INNODB STATUS 输出的基础,它打印了很多关于 InnoDB 内部性能相关的计数器、统计、事务处理信息等。在 MySQL 5 中,InnoDB 的性能统计结果也在 SHOW STATUS 结果中显示了。大部分和 SHOW INNODB STATUS 的其他信息相同,在旧版本中还没有这个功能。

SHOW INNODB STATUS 中的很多统计值都是每秒更新一次的,如果你打算利用这些统计值的话,那么最好统计一段时间内的结果。InnoDB 首先输出以下信息:

1.=====================================
2.060717  3:07:56 INNODB MONITOR OUTPUT
3.=====================================
4.Per second averages calculated from the last 44 seconds

首先要确认这是至少统计了 20-30 秒的样本数据。如果平均统计间隔是0或1秒,那么结果就没什么意义了。
说实在的我不喜欢InnoDB提供的平均值,因为很难取得合理的平均间隔统计值,如果你是写脚本来取得 SHOW INNODB STATUS 结果的话,那么最好取得全局的统计结果,然后取得平均值。当然了,直接查看输出的结果信息也是很有用的。

下一部分显示了信号(Semaphores)相关信息:

1.----------
2.SEMAPHORES
3.----------
4.OS WAIT ARRAY INFO: reservation count 13569, signal count 11421
5.--Thread 1152170336 has waited at ./../include/buf0buf.ic line 630 for 0.00 seconds the semaphore:
6.Mutex at 0x2a957858b8 created file buf0buf.c line 517, lock var 0
7.waiters flag 0
8.wait is ending
9.--Thread 1147709792 has waited at ./../include/buf0buf.ic line 630 for 0.00 seconds the semaphore:
10.Mutex at 0x2a957858b8 created file buf0buf.c line 517, lock var 0
11.waiters flag 0
12.wait is ending
13.Mutex spin waits 5672442, rounds 3899888, OS waits 4719
14.RW-shared spins 5920, OS waits 2918; RW-excl spins 3463, OS waits 3163

这段可以分成2个部分。一部分是当前的等待,这部分只是包含了在高并发环境下的全部记录,因此 InnoDB 会频繁回退到系统等待。如果等待是通过自旋锁来解决的话,那么这些信息就就不会显示了。

通过这部分信息,你就会知道系统负载的热点在哪了。不过这需要了解一下源码相关的知识 - 从上面的信息中就可以看出来是哪个源码文件中的哪行(不同的版本结果可能不同),只是从这里却看不出来任何信息。尽管如此,还是可以从文件名中猜到一些东西 - 比如本例中,文件名 "buf0buf.ic" 预示着和一些缓冲池争夺有关系。如果想了解更多,就去看源码吧。

还有一些关于等待的更多细节。"lock var" 表示当前的 mutex 对象的值(被锁住 = 1 / 释放 = 0) 值,"waiters flag" 表示当前的等待个数。另外,本例中还可以看到等待状态信息 "wait is ending",这表示 mutex 已经释放,但是系统调度线程还正在处理。

第二块是事件统计 - "reservation count" 和 "signal count" 显示了 innodb 使用内部同步阵列的活跃程度 - 时间片(slot)分配以及线程信号使用同步阵列的频繁程度。这些统计信息可以用于表示 innodb 回退到系统等待的频率。还有关于系统等待的直接相关信息,可以看到"OS Waits"的互斥信号灯(mutexes),以及读写锁。这些信息中显示了互斥锁和共享锁。系统等待和 "保留(reservation)" 不完全一样,在回退到用 sync_array 的复杂等待模式前,innodb 会尝试 "输出(yield)" 到系统,希望下一次调度时间对象里命名线程已经释放了。系统等待相对较慢,如果每秒发生了上万次系统等待,则可能会有问题。另一个观察方法是查看系统状态中的上下文(context)交换频率。

另一块重要的信息是 "spin waits" 和 "spin rounds" 的数量。相较于系统等待,自旋锁是低成本的等待;不过它是一个活跃的等待,会浪费一些cpu资源。因此如果看到大量的自旋等待和自旋轮转,则很显然它浪费了很多cpu资源。浪费cpu时间和无谓的上下文切换之间可以用 innodb_sync_spin_loops 来平衡。

接下来的这段显示死锁状况:

1.------------------------
2.LATEST DETECTED DEADLOCK
3.------------------------
4.060717  4:16:48
5.*** (1) TRANSACTION:
6.TRANSACTION 0 42313619, ACTIVE 49 sec, process no 10099, OS thread id 3771312 starting index read
7.mysql tables in use 1, locked 1
8.LOCK WAIT 3 lock struct(s), heap size 320
9.MySQL thread id 30898, query id 100626 localhost root Updating
10.update iz set pad='a' where i=2
11.*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
12.RECORD LOCKS space id 0 page no 16403 n bits 72 index `PRIMARY` of table `test/iz` trx id 0 42313619 lock_mode X locks rec but not gap waiting
13.Record lock, heap no 5 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
14. 0: len 4; hex 80000002; asc     ;; 1: len 6; hex 00000285a78f; asc       ;; 2: len 7; hex 00000040150110; asc    @   ;; 3: len 10; hex 61202020202020202020; asc a         ;;
15.
16.*** (2) TRANSACTION:
17.TRANSACTION 0 42313620, ACTIVE 24 sec, process no 10099, OS thread id 4078512 starting index read, thread declared inside InnoDB 500
18.mysql tables in use 1, locked 1
19.3 lock struct(s), heap size 320
20.MySQL thread id 30899, query id 100627 localhost root Updating
21.update iz set pad='a' where i=1
22.*** (2) HOLDS THE LOCK(S):
23.RECORD LOCKS space id 0 page no 16403 n bits 72 index `PRIMARY` of table `test/iz` trx id 0 42313620 lock_mode X locks rec but not gap
24.Record lock, heap no 5 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
25. 0: len 4; hex 80000002; asc     ;; 1: len 6; hex 00000285a78f; asc       ;; 2: len 7; hex 00000040150110; asc    @   ;; 3: len 10; hex 61202020202020202020; asc a         ;;
26.
27.*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
28.RECORD LOCKS space id 0 page no 16403 n bits 72 index `PRIMARY` of table `test/iz` trx id 0 42313620 lock_mode X locks rec but not gap waiting
29.Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
30. 0: len 4; hex 80000001; asc     ;; 1: len 6; hex 00000285a78e; asc       ;; 2: len 7; hex 000000003411d9; asc     4  ;; 3: len 10; hex 61202020202020202020; asc a         ;;
31.
32.*** WE ROLL BACK TRANSACTION (2)

这里显示了 Innodb 最后检测到事务引发的死锁,包括发生死锁时的状态,加了什么锁,在等待什么锁释放,以及 Innodb 决定哪个事务会被回滚。注意,innodb只显示了事务持有锁的相关简单信息。并且只显示了每个事务最后执行的语句,发生死锁的记录就是由于这些语句引起的。查看复杂的死锁信息还需要查看日志文件,才能找到真正引发冲突的语句。大部分情况下,SHOW INNODB STATUS 显示的信息基本足够了。

下面是关于外键约束引发的死锁信息:

1.------------------------
2.LATEST FOREIGN KEY ERROR
3.------------------------
4.060717  4:29:00 Transaction:
5.TRANSACTION 0 336342767, ACTIVE 0 sec, process no 3946, OS thread id 1151088992 inserting, thread declared inside InnoDB 500
6.mysql tables in use 1, locked 1
7.3 lock struct(s), heap size 368, undo log entries 1
8.MySQL thread id 9697561, query id 188161264 localhost root update
9.insert into child values(2,2)
10.Foreign key constraint fails for table `test/child`:
11.,
12.  CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE
13.Trying to add in child table, in index `par_ind` tuple:
14.DATA TUPLE: 2 fields;
15. 0: len 4; hex 80000002; asc     ;; 1: len 6; hex 000000000401; asc       ;;
16.
17.But in parent table `test/parent`, in index `PRIMARY`,
18.the closest match we can find is record:
19.PHYSICAL RECORD: n_fields 3; 1-byte offs TRUE; info bits 0
20. 0: len 4; hex 80000001; asc     ;; 1: len 6; hex 0000140c2d8f; asc     - ;; 2: len 7; hex 80009c40050084; asc    @   ;;

Innodb会显示引发错误的语句。外键约束定义失败,以及定义关系最密切的父表。有很多嵌接信息都是用16进制表示,不过对于问题诊断并不是太重要,它们主要用于给 Innodb 的开发者来查看或者用于调试目的。

接下来是显示 Innodb 当前活跃的事务:

1.------------
2.TRANSACTIONS
3.------------
4.Trx id counter 0 80157601
5.Purge done for trx's n:o <0 80154573 undo n:o <0 0
6.History list length 6
7.Total number of lock structs in row lock hash table 0
8.LIST OF TRANSACTIONS FOR EACH SESSION:
9.---TRANSACTION 0 0, not started, process no 3396, OS thread id 1152440672
10.MySQL thread id 8080, query id 728900 localhost root
11.show innodb status
12.---TRANSACTION 0 80157600, ACTIVE 4 sec, process no 3396, OS thread id 1148250464, thread declared inside InnoDB 442
13.mysql tables in use 1, locked 0
14.MySQL thread id 8079, query id 728899 localhost root Sending data
15.select sql_calc_found_rows  * from b limit 5
16.Trx read view will not see trx with id>= 0 80157601, sees <0 80157597
17.---TRANSACTION 0 80157599, ACTIVE 5 sec, process no 3396, OS thread id 1150142816 fetching rows, thread declared inside InnoDB 166
18.mysql tables in use 1, locked 0
19.MySQL thread id 8078, query id 728898 localhost root Sending data
20.select sql_calc_found_rows  * from b limit 5
21.Trx read view will not see trx with id>= 0 80157600, sees <0 80157596
22.---TRANSACTION 0 80157598, ACTIVE 7 sec, process no 3396, OS thread id 1147980128 fetching rows, thread declared inside InnoDB 114
23.mysql tables in use 1, locked 0
24.MySQL thread id 8077, query id 728897 localhost root Sending data
25.select sql_calc_found_rows  * from b limit 5
26.Trx read view will not see trx with id>= 0 80157599, sees <0 80157595
27.---TRANSACTION 0 80157597, ACTIVE 7 sec, process no 3396, OS thread id 1152305504 fetching rows, thread declared inside InnoDB 400
28.mysql tables in use 1, locked 0
29.MySQL thread id 8076, query id 728896 localhost root Sending data
30.select sql_calc_found_rows  * from b limit 5
31.Trx read view will not see trx with id>= 0 80157598, sees <0 80157594

如果当前连接不是很多,则会显示全部事务列表;如果有大量连接,则 Innodb 只会显示他们的数量,减少输出的列表信息,使得输出结果不会太多。

事务ID是当前事务的标识,事务的id每次都会增加。Purge done for trx's n:o 是指净化(purge)线程已经完成的事务数。Innodb仅清除那些被当前事务认为不再需要的旧版本数据。那些未提交的旧事务可能会阻塞净化线程并且消耗资源。通过查看2次清除事务数之差,就可以知道是否发生了这种情况。少数情况下,净化线程可能难以跟上更新的速度,2次查看值之差可能会越来越大;那么,innodb_max_purge_lag 就派得上用场了。 "undo n:o" 显示了净化线程当前正在处理的回滚日志号,如果当前不处于活跃状态,则它的值是 0。

History list length 6 是指在回滚空间中的未清除事务数。随着事务的提交,它的值会增加;随着清除线程的运行,它的值会减小。

Total number of lock structs in row lock hash table 是指事务分配过的行锁结构总数。它和曾经被锁住过的行总数不一定相等,通常是一个锁结构对应多行记录。

MySQL中,每个连接如果没有活动的事务,则它的状态是 not started,如果有活动的事务,则是 ACTIVE。注意,尽管事务是活动的,但是其连接的状态却可能是 "睡眠(sleep)" - 如果是在一个有多条语句的事务里的话。Innodb 会同时显示系统的线程号以及进程号,这有助于利用gdb来调试或者其他类似用途。另外,事务的状态也会根据当前实际状态来显示,例如 "读取记录(fetching rows)",em>"更新(updating)"等等。"Thread declared inside InnoDB 400" 的意思是 Innodb 内核正在运行该线程,并且还需要400个票。Innodb 会根据 innodb_thread_concurrency 的值来限制同时并发的线程数不超过它。如果线程当前不在 Innodb 的内核中运行,则它的状态可能是 "waiting in InnoDB queue" 或 "sleeping before joining InnoDB queue"。后面这个状态有点意思 - Innodb 为了避免有太多的线程同时抢着要进入运行队列,那么就会尝试让这些线程进入等待状态(如果没有足够的空闲插槽(slot)的话)。这就可能会导致 Innodb 内核中当前活跃的线程数可能比innodb_thread_concurrency 的值还小。某种负载环境下,这可能有助于减小线程进入队列的时间。可以通过调整 innodb_thread_sleep_delay 来实现,它的单位是微妙。

mysql tables in use 1, locked 0 是指事务中已经用过的数据表个数(已经访问过了的),以及被锁的个数。Innodb 一般情况不会锁表,因此锁表数一般是0,除非是ALTER TABLE 或者其他类似 LOCK TABLES 的语句。

除了Innodb相关的特定信息外,一些基本信息可以通过 来查看,例如正在执行什么语句,查询ID号,查询状态等。

下面这部分显示的是跟IO相关的具体信息:

1.--------
2.FILE I/O
3.--------
4.I/O thread 0 state: waiting for i/o request (insert buffer thread)
5.I/O thread 1 state: waiting for i/o request (log thread)
6.I/O thread 2 state: waiting for i/o request (read thread)
7.I/O thread 3 state: waiting for i/o request (write thread)
8.Pending normal aio reads: 0, aio writes: 0,
9. ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
10.Pending flushes (fsync) log: 0; buffer pool: 0
11.17909940 OS file reads, 22088963 OS file writes, 1743764 OS fsyncs
12.0.20 reads/s, 16384 avg bytes/read, 5.00 writes/s, 0.80 fsyncs/s

本部分显示了IO助手线程状态 - 插入缓冲线程,日志线程,读、写线程。它们分别对应插入缓冲合并,异步日志刷新,预读以及刷新脏数据。源自查询的正常读取是由正在运行的查询执行的。在Unix/Linux平台下,总能看见4个线程,在Windows上可以通过 innodb_file_io_threads 来调整。每个线程准备好之后都能看到其状态:waiting for i/o request 或者正在执行特定的操作。

每个线程都会显示正在进行的操作数量 - 同时正要执行或者正在执行的操作数量。另外,正在执行的 fsync 操作数量也会显示出来。有写数据时,Innodb需要确保数据最终被写到磁盘上,只是把它们放在系统缓存里是不够的。通常是调用 fsync() 来完成的。如果它的值一直很高,那意味这Innodb可能是处于IO负载较高状态。注意,由线程执行请求引发的IO请求是不计算在内的,因此尽管系统的IO负载较高,但是它们的值却可能为 0。

接下来显示的是IO操作的平均统计值,它们对于图形显示或者监控很有用。
"16384 avg bytes/read" 是读请求的平均值。随机IO的话,每个页的大小是16K,全表扫描或索引扫描时的预读会导致这个值明显的增加。因此,它体现了预读的效率。

1.-------------------------------------
2.INSERT BUFFER AND ADAPTIVE HASH INDEX
3.-------------------------------------
4.Ibuf for space 0: size 1, free list len 887, seg size 889, is not empty
5.Ibuf for space 0: size 1, free list len 887, seg size 889,
6.2431891 inserts, 2672643 merged recs, 1059730 merges
7.Hash table size 8850487, used cells 2381348, node heap has 4091 buffer(s)
8.2208.17 hash searches/s, 175.05 non-hash searches/s

本部分显示了插入缓冲以及自适应哈希索引的状态。第一行显示了插入缓冲的状态 - 段的大小以及空闲列表,以及缓冲中有多少记录。接下来显示了缓冲中已经完成了多少次插入,有多少记录已经合并,有多少次合并已经完成。合并次数除以插入次数得到的比率可以反映出插入缓冲的效率如何。

Innodb采用哈希索引建立内存页索引形成自适应哈希索引而不是采 B-tree 索引,得以加速行记录到内存页的检索。这里显示了哈希表的大小,以及自适应哈希索引使用了多少单元和缓冲。可以通过计算利用哈希索引检索的次数以及没利用它检索的次数来了解哈希索引的效率。

当前对自适应哈希索引基本没有什么办法可以调整它,主要还是用于查看。

1.---
2.LOG
3.---
4.Log sequence number 84 3000620880
5.Log flushed up to   84 3000611265
6.Last checkpoint at  84 2939889199
7.0 pending log writes, 0 pending chkp writes
8.14073669 log i/o's done, 10.90 log i/o's/second

接下来显示的是Innodb的日志子系统相关信息。可以看到当前的日志序列号 - 相当于Innodb自从表空间开始创建直到现在已经写入日志文件的总字节数。还可以看到日志已经刷新到哪个点,同样也可以根据最后检查点计算出还有多少日志没有刷新到文件中去。Innodb采用模糊检查点,因此这行显示的是已经从缓冲池中刷新到文件的日志序列号。由于更高的日志序列号可能不会被立刻刷新到日志文件中去,因此日志序列号不能被覆盖掉。通过监控刷新到哪个日志的日志序列,可以判定innodb_log_buffer_size 的设置是否合理,如果看到超过 30% 的日志还没有刷新到日志文件中,则需要考虑增加它的值了。

另外,还能看到日志写入以及检查点的数目。根据日志 I/O 操作的数目可以区分开表空间相关的IO请求和日志IO请求数量,进而可以确定到底需要几个日志文件。注意,innodb_flush_log_at_trx_commit 的值可以影响到日志写操作的代价高或低。如果 innodb_flush_logs_at_trx_commit=2,则日志是写到系统缓存,然后再顺序写到日志文件中,因此相对会快很多。

1.----------------------
2.BUFFER POOL AND MEMORY
3.----------------------
4.Total memory allocated 4648979546; in additional pool allocated 16773888
5.Buffer pool size   262144
6.Free buffers       0
7.Database pages     258053
8.Modified db pages  37491
9.Pending reads 0
10.Pending writes: LRU 0, flush list 0, single page 0
11.Pages read 57973114, created 251137, written 10761167
12.9.79 reads/s, 0.31 creates/s, 6.00 writes/s
13.Buffer pool hit rate 999 / 1000

这部分显示了缓冲池和内存的利用率相关信息。可以看到Innodb分配的所有内存(有些时候可能比你设置的还要多点),以及额外的内存池分配情况(可以检查它的大小是否正好),缓冲池总共有多少个内存页,有多少空闲内存页,数据库分配了多少个内存页以及有多少个脏内存页。从这些信息中,就可以判断内存缓冲池是否设定合理,如果总是有大量空闲内存页,则不需要设置那么多内存,可以适当减小一点。如果空闲内存页为 0,这种情况下数据库内存页就不一定会和缓冲池的总数一致,因为缓冲池还需要保存锁信息,自适应哈希索引以及其他系统结构等信息。

等待中的读写是指内存缓冲池级别的请求。Innodb可能会把多个文件级别的请求合并到一个上,因此各不相同。我们还可以看到Innodb提交的各种不同类型的IO,LRU内存页中需要刷新的页 - 脏内存页,它们不会被长时间存取;刷新列表 -
检查点进程处理完之后需要刷新的旧内存页;独立内存页 - 独立的写内存页。

我们还可以看到内存页总共读写了多少次。已经创建的内存页是当前一个内存页中的内容没有读取到内存缓冲池中时,专门为新数据创建的空内存页。

最后我们可以看到缓冲池的命中率,它预示着缓冲池的效率。1000/1000 相当于 100% 的命中率。不过这样也很难说明缓冲池的命中率就足够高了,这要需要根据不同的负载环境而定。通常情况下,950/1000 就够了,有些时候在IO负载较高的环境下,命中率可能为 995/1000。

1.--------------
2.ROW OPERATIONS
3.--------------
4.0 queries inside InnoDB, 0 queries in queue
5.1 read views open inside InnoDB
6.Main thread process no. 10099, id 88021936, state: waiting for server activity
7.Number of rows inserted 143, updated 3000041, deleted 0, read 24865563
8.0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s

最后一部分,显示了数据行操作以及一些系统信息相关情况。

一开始显示了Innodb线程队列状态 - 有多少线程处于等待或活跃的。Innodb内部打开了多少读视图 -
这是在事务开始后,但是当前还没有活跃语句的情况,Innodb主线程的状态控制了系统操作调度的数量 - 刷新脏内存页、检查点、净化线程、刷新日志、合并插入缓冲等。 "state" 的值则表示了主线程当前的状态。

接下来可以看到自从系统启动以来,所有的数据行操作数量及其平均值。它们可以很方便地用于监控以及画出系统状态图,数据行操作次数可以很好的衡量Innodb的负载。不是所有的数据行操作带来的负载都是一样的,存取10字节的行比10Mb的行相比会小了很多,不过相对于查询的总次数来说这个信息可是有用的多了,差别也很大。

还有一点需要注意的是,SHOW INNODB STATUS 不是一成不变的,有些时间点上可能会不相符。SHOW INNODB STATUS结果中,不同时间可能会显示不同结果,因此有些时候可能会看到冲突的信息。这是由于设计时需要由全局锁提供一致性信息,导致了大量的开销。

posted @ 2011-04-26 09:51 哈哈的日子 阅读(526) | 评论 (0)编辑 收藏
很长一段时间使用 mac os x 目前是 snow leopard,最让我恼火的就是他的快捷键。
我是大部分操作靠键盘的人,但切换到 mac 后,曾经和同事说,基本上是“武功全废”。

直到今天,给老婆买了新 mbp 后,才发现,原来。。。。是我土了!!!
原来,在设置->键盘->键盘快捷键,里面,有一项叫“全键盘控制”,可以切换,快捷键是 control + F7。

生活,原来可以更美一点儿的,真的!
posted @ 2011-04-21 22:45 哈哈的日子 阅读(153) | 评论 (0)编辑 收藏
我的 m2eclipse 下载 source 功能老是不好用,只好用命令行了。

mvn eclipse:eclipse -DdownloadSources=true
or
mvn eclipse:eclipse -DdownloadJavadocs=true
posted @ 2011-04-16 17:23 哈哈的日子 阅读(601) | 评论 (0)编辑 收藏
sudo lsof -i -P | grep 2144 | awk '$2 != 2144 {print $2}' | xargs ps -fp | awk 'NR > 1 {print $3}' | xargs kill -15
posted @ 2011-03-13 17:45 哈哈的日子 阅读(319) | 评论 (0)编辑 收藏
目标:
copy 国际化资源文件,*.properties 至 *_en_US.properties,但有一些不是国际化资源的配置文件被误 copy 了,国际化资源的判断标准是同时还有一个 *_zh_CN.properties 文件


                                
<target>
                                    
<pathconvert property="x" pathsep="," targetos="unix">
                                        
<path>
                                            
<fileset dir="src/main/resources" includes="**/*_zh_CN.properties" />
                                        
</path>
                                        
<mapper type="regexp" from=".*?src/main/resources/(.*?)_zh_CN.properties$" to="\1.properties" />
                                    
</pathconvert>
                                    
<copy todir="${project.build.outputDirectory}">
                                        
<fileset dir="src/main/resources" includes="${x}" />
                                        
<mapper type="regexp" from="^(.*?).properties$" to="\1_en_US.properties" />
                                    
</copy>
                                
</target>
posted @ 2011-03-10 19:31 哈哈的日子 阅读(253) | 评论 (0)编辑 收藏
现象:
eclipse subversive plugin 快捷键无效
原因:
据说是 eclipse 高版本的 api 和 subversive 不太匹配,不确定。
解决:
Window -> Customize Perspective -> Command Groups Availability -> 左侧 Available command groups -> 选择 SVN

posted @ 2011-03-09 10:53 哈哈的日子 阅读(1242) | 评论 (0)编辑 收藏
有一位居士,在江边散步,看到一个船夫将沙滩上的渡舟推向江里,准备载客渡江。此时刚好有一位禅师路过,这个居士于是向前作礼请示道:“请问禅师,刚才船夫将舟推入江时,将江滩上的螃蟹、虾、螺等压死不少,请问这是乘客的罪过?还是船夫的罪过?” 禅师没有考虑,就回答道:“既不是乘客的罪过,也不是船夫的罪过!” 居士非常不解,怀疑地问道:“两者都没有罪过,那么是谁的罪过?” 禅师两眼圆睁,大声道:“是你的罪过!”
posted @ 2011-02-20 22:39 哈哈的日子 阅读(117) | 评论 (0)编辑 收藏
@import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css); 步骤如下:
xxx 是当前用户名
1. 下载一个 unzip 的 mysql 的 tar 包。
2. 把这个 tar 解压到 /usr/local/mysql 目录下,
3. 到 /usr/loca/mysql 目录下,执行 chown -R xxx ,增加权限。
4. 然后执行 /usr/local/mysql/scripts/mysql_install_db --user=xxx
5. 然后 /usr/local/mysql/bin/mysqld --console 就启动了

如果要开机启动,就 sudo vi /etc/rc.local,在里面加上 /usr/local/mysql/bin/mysqld 就行了。

posted @ 2011-02-19 09:47 哈哈的日子 阅读(158) | 评论 (0)编辑 收藏
http://coolshell.cn/articles/3609.html

StackExchange.com上有一个贴子在评论着最近20年来被炒作过度的技术,对于出现的结果,大多数赞同,也有一些不赞同。下面我从前15名挑了10个(Java的WORE我去掉了,TDD我也去掉了,因为我觉得他们应该没有炒作过度,而且都不错),按原贴的顺序罗列如下:(后面的一些评论是我加的,欢迎大家讨论)

Top 10 过度炒作的技术和概念

  • Unified Modeling Language (UML) – UML是一个程序员交流想法的不错的工具,但是他离程序员真正需要的设计工具还差得很远,比如:设计是否符合需求、架构设计、数据流等等。只有为数不多的程序员使用这个工具交流想法,而没有用在具体工作中。
  • Sharepoint - 现在N多的公司都在用微软的这个东西做公司内部的Intranet。不过安装和维护起来,代价相当的大。但是其市场做的很成功,不对技术上来说对技术人员来说,相当的蹩脚。Sharepoint的设计没有认真地分析过业务流程,仅仅是一个文档存储地。看上去我们似乎可以做任何的事,但是如果你要用其来管理你的项目和track你的项目问题,你会发现其是无比的难用。
  • eXtensible Mark-up Language (XML) –  XML嘛,以前说过很多了(XML1 XML2)我们用他来做和程序数据封装,用来做配置文件,用来做网络传输格式。我们的程序处理起XML来,又慢,又不经济,没有工具,几乎无法维护XML文件。XML用来做数据封包真是很不经济,Yaml和JSON那个不比它简单?用XML来做程序配置文件不知道是谁想出来的主意,相当的愚蠢,看看Unix/Linux下的配置文件,简单易读,相当容易维护。真是高科技啊。
  • SOAP, XML-RPC, WSDL 的 Web Services – 这个东西前几年炒的很凶。所有人都相信,这是程序员的未来。可惜的,其中的复杂和不一致,相当的令人恶心。SOAP的那个S居然还是Simple!看来,扯上XML的都不会是什么好的东东。不过,个人认为,CORBA比他更恶。

  • CORBA - 作为一个比其更恶的更过度炒作的COM技术的Linux/Unix下的补充技术,这个技术也好不到哪里去。相当的复杂,从理论上开始就是这样了。这是一个没有经过实践就搞出来的一个东西。然后开始炒作。
  • Cloud Computing – 这是一个靠炒作出现的东西。这个东西也就是说,我们可以使用不同的调备,比如电脑,平板电脑,手机,移动设备随时随地做想做的事。Google的Chrome笔记本的广告展示了这项技术,但是,把工作结果放在云端的人会有多少呢。更多的人更喜欢的是去使用那些自己可以控制的电脑或平台。Google在这点上做的明显不如Amazon,像Amazon EC2平台,你可以在世界上任何一个角落随时随地的去启动你那台远程的系统。(更新(2011/1/29)解释一下,关于云计算,在写下这篇文章的时候我本来有点拿不定主意的,后来回顾了一下历史,如COM啊,ActiveX啊,EJB啊,当时感觉都是很强的东西,但是最终也只是被炒作的。云计算,我不知道未来怎么样,从今天来看,这项技术在今天存在炒作的情况——中移动云,阿里云,到处都是云,在云面前,神马都是浮云了。
  • SOA – Service Oriented Architecture – 这是一个没有人真正知道是什么玩意的概念。炒作了很多年,很多人都试图去了解它,但最后的结果是打个哈欠,看别的东西去了。现在没有人提了。中国一些银行在IBM的鼓动下搞了很多所谓的SOA应用,结果是系统很复杂,当然,也再离不开IBM了。
  • Software Industrial Process – 软件开发中有很多所谓的工业界的流程,用这些流程好像可以控制质量。外包公司和中国的本土公司很喜欢这些东西,比如ISO和CMMi,这些流程不能说不好,也有好的地方,尤其是对那些不会思考只要跟从的Worker来说。这些工业界流程中炒作过度的是,那些所谓的使用这些流程可以预测项目周期,质量控制,以前需求开发和管理等东西。其让流程上升到了一种神学的可预言的地步,同样也上升到了政治的地步。因为,这些流程中都必然会有SQA 的Audit的流程,还有统计和报告的流程,这些统统不是软件开发的流程,但是的确是相当的政治。使用这些工业届标准流程的公司,通常都是一些创造性有问题的公司。
  • Agile Software Development – 敏捷开发。首先,我承认其中的很多实践相当有效,在理论上也不错,还有很多不错方法的。不过,还是有炒作的成分(下面的言论,我等着被骂)对我来说,在中国,“敏捷开发”的炒作简直就像是一个电视购物,ThoughtWorks中国各种咨询师们软件开发经验其实并不丰富,准确来说,他们有的是咨询经验,而没有具体项目实施经验(有的咨询师甚至都没有写过一行代码就去学教人怎么编程和开发软件了),和他们沟通起来能够感到他们对敏捷很亢奋,而且是唯敏捷主义,就差打出Once Process,One Agile的口号了,他们信仰敏捷流程的已经接近宗教信仰,他们的精神世界很朝鲜。因为,无论你和他们的咨询师谈什么,他们只说敏捷,从来不会分析一下,项目的特性是什么?开发这个项目的人的风格是什么?客户的特性是什么?有没有关心软件的stakeholder们(如:程序员,测试人员,客户,管理人员)是怎么想的?而XP和SCRUM也就成了Push工程师最强大的工具。流程这个东西,应该是项目组自发出来的东西,而不是被 灌输,被教条使用的东西。不同的团队、不同的项目、不同的人,不同的风格就是不同的流程,只有去使用适合自己的流程才是最好的流程打个比方,足球队中,巴西队玩的是个人艺术足球,德国队玩的是整体和纪律性足球,意大利玩的是防守型足球,但是他们都有夺世界杯冠军的实力,如果你硬要让巴西队去整德国队或是意大利队的风格,那就悲剧了。很显然,ThoughtWorks很像把全中国的软件公司都整成Agile的,这注定了其在中国是杯具的,也只能争取到那些不知所措的公司和项目,没有合适的项目,也只有靠各种炒作(比如整一些大会,搞一些宣传)。他们总是觉得中国的用户和程序员需要去用时间不停地教育,但是,他们从来没有想想自己的原因 — 靠教育和灌输是永远赢不了的。我给他们的个人建议是,不要以为世界就像你所想像的那样,学会尊重程序员和项目还有很多非技术的东西,多听听程序员和客户怎么说,多分析一下项目的特质,从实际情况出发,而不是自己涛涛不绝地向大家灌输自己的理论
  • Object-Oriented Programming (OOP) – 不多说了,以前本站说过了,所有的一切都在面向对象是个骗局一文中。不过有一点我想告诉大家,面向对象的Design Pattern真是被滥用了,Design Pattern教你的是两件事,1)怎么去化繁为简,2)怎么能让对象的耦合性降低。而不是一个公式让你的套,但,更多的程序员则学会了“流行的设计模式编程”。

附:我不认为过度炒作的技术

Write Once Run Anywhere - 这个有点让我不解,不知道为什么会那么靠前。这是Java的口号,我觉得Java在跨平台方面还是成功的,没有过度炒作啊。用虚拟机的确是做到了这一点,对于那些需要有不同的硬件和操作系统平台并不断升级和更换它们的公司来说,这的确是个很不错的解决平台依赖性的方案。我个感觉这个技术并没有炒作过头,至少在Java这边是这样的。与其说这个,还不如说EJB,这才是炒作过度的技术。

Test Driven Design (TDD) – 从测试案例开始写程序这可能是很多程序员都不习惯的方法。其实这是一种比较好的编程方法,保证了代码怎么改动都不会break其它没有改动的代码,代码可以在一种持续集成中保证质量。但是,我们需要知道TDD的一些副作用(在十条不错的编程观点里也提到过TDD的弊端):1)TDD可能会让程序员敷衍了事,以为test case 没有错就正确了。2)TDD可能会让你忽略了软件设计和架构以及程序的扩展性和重用性。TDD只是一种方法,并不是程序的核心。当然,TDD近几年的炒作也有点过头,已经出现了“TDD是一种Design方法”等“神乎其技”的论调,我对此表示质疑中。

posted @ 2011-02-09 14:32 哈哈的日子 阅读(164) | 评论 (0)编辑 收藏
1. 查看 1521 端口上的应用程序
windows: netstat -anp, linux: sudo netstat -anop | grep 1521, os x: sudo lsof -i -P | grep 1521,注意 P 大写
2. 安装 oracle 需要 /usr/bin/make,最方便的方法是安装 xcode,就有了。
3. 安装 oracle 时使用 jdk 1.4.2,需要做一个 link,sudo ln -s /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK /System/Library/Frameworks/JavaVM.framework/Versions/1.4.2,这样 oracle 才可以执行 ./runInstaller -J-d32 安装
4. 安装过程中会报 all_no_orcl ipc_g ihsodbc32 错误,需要修改~/oracle/product/10.2.0/db_1/rdbms/lib/ins_rdbms.mk 文件,把里面 $(HSODBC_LINKLINE) 这行注释掉,即在前面加个 #
5. 安装完成后,需要执行 netca 和 dbca,netca 建立 listener,dbca 建库,但不能直接运行,需要修改 java 文件,$ORACLE_HOME/jdk/bin/java,将...java -Xbootclasspath... 改成 ...java -d32 -Xbootclasspath....,这样才可以运行,然后建立数据库

这样应该总算建好了,太辛苦了。

更完整的参考 http://blog.rayapps.com/2009/09/14/how-to-install-oracle-database-10g-on-mac-os-x-snow-leopard/
这个文档写得太好了,千万不要使用中文版的那个在 snow leopard 下安装 oracle 10g 的文档,中间省略了好多东西,让我走了不少的弯路,呵呵。
posted @ 2011-01-29 22:00 哈哈的日子 阅读(225) | 评论 (0)编辑 收藏
一、用户级别的
在用户目录下建 .bash_profile 文件,即可,每次 login 执行,一般放一些 path,alias,环境变量什么的

二、系统级别的
在 /etc 目录下建 rc.local 文件,里面加一些启动要执行的程序。比如 nexus、jira、confluence 这些。

posted @ 2011-01-24 15:29 哈哈的日子 阅读(137) | 评论 (0)编辑 收藏
弄了两天 Google Calendar 和 GAE,打算做个功能,就是在 GAE 上做个应用,每天在 Google Calendar 里面增加一个 Event,里面记录着今天要背的单词。 
Google 就会到时候短信提醒我,要背的单词了。
这个功能就是个试验的,没有实际作用,肯定不如背单词软件来得实在,好就好在不用装什么软件。

这个功能涉及到了一些功能点:
1. 调用 Google Calendar API,增加 Event 及提醒--这个简单
2. 使用 AuthSub 认证,提醒用户信任我的应用,使应用能够帮助用户订阅背单词的 Calendar--这个参考文档http://code.google.com/intl/zh-CN/apis/calendar/data/2.0/developers_guide_java.html#AuthAuthSub,就可以了
3. 增加 Event 时,有 TimeZone 问题,需要处理。

第三个问题之前没有遇到,现象是
在我本地运行 GAE 的时候,一切正常,可以加一个 10:00-11:00 的提醒到 Calendar 中,但部署至 GAE 服务器上的后,加的提醒就是 18:00-19:00 了,调整了一下 new DateTime 的 TimeZone 至 GMT+8:00,问题依旧。

后来查了一下 JDK 的 API,发现其实 java.util.Date 和 java.util.Calendar 中是有 TimeZone 信息的,这下明白了,在 Calendar.getInstance 的时候,加上 +8 时区的 TimeZone,问题解决,因为目前我只需要在 +8 时区使用这个功能。
posted @ 2011-01-12 10:55 哈哈的日子 阅读(169) | 评论 (0)编辑 收藏
先选上 “系统偏好设置 -> 安全 -> 通用 -> 进入睡眠或开始.....”选项。
然后 control + shift + eject(最右上角的退盘键)
就可以进入屏保了,然后需要密码解锁
posted @ 2011-01-03 17:31 哈哈的日子 阅读(414) | 评论 (0)编辑 收藏
可以为应用定制快捷键,和 windows 下面的 hoekey 有点儿像
软件图标

运行后会在 MenuBar显示一个图标
点击,显示

增加一个快捷方式就可以了
posted @ 2011-01-03 17:13 哈哈的日子 阅读(150) | 评论 (0)编辑 收藏
1. 很有名的 http://www.sinfuliphonerepo.com/
这上面有全套的破解版 lockinfo,还有破解的 MyWi,iFile,相当的多。
2.我最近才知道的 http://theiphonespotrepo.net/apt/
上面有我非常喜欢的 Wi-Fi Sync,可以用 WiFi 与电脑同步,不用接线了。还有非常好的 My3G,支持使用 3G 进行 FaceTime,这个软件在 sinfuliphone 上面也有。
posted @ 2011-01-02 16:42 哈哈的日子 阅读(1304) | 评论 (0)编辑 收藏
按住 command 就可以查看当前可以使用的快捷键了,非常好用!
下载地址
http://www.ergonis.com/downloads/dnld_keycue.html

可用的序列号

SN: KC-MCA-122008-1-182080-408767-1

KC-MCA-122008-46-75994-427759-36

KC-MCA-122008-79-161137-964991-4

KC-MCA-122008-97-87408-790539-10

KC-MCA-122008-73-138209-878696-68

KC-MCA-122008-90-92030-853288-16

KC-MCA-122008-37-86090-647601-4

KC-MCA-122008-90-116413-467930-42 

KC-MCA-122008-65-68077-631067-3

KC-MCA-122008-86-106715-366213-67

posted @ 2010-12-25 21:06 哈哈的日子 阅读(202) | 评论 (0)编辑 收藏
     摘要: http://www.chinamac.com/2009/1012/49609.html
在选择系统语言的时候,你一定注意到了,在你的Home下文件夹会随之变化,
例如在英文时显示Documents,切换到一个使用中文偏好的账户(即便在fast switch)时,显示“文档”,后续介绍mac os x是如何处理的  阅读全文
posted @ 2010-12-22 22:38 哈哈的日子 阅读(966) | 评论 (0)编辑 收藏
     摘要: http://www.levelofindirection.com/journal/2009/10/10/using-a-networked-drive-for-time-machine-backups-on-a-mac.html
You'll find similar information to this around the web, but I find it fiddly enough to piece together reliably, and I need it often enough, that I thought I'd blog about it. That way it at least gives me a single place to look. Maybe it will help others too. Much of the specifcs, especially the hdiutil command line and the ifconfig trick, I sourced from this thread in the Ready  阅读全文
posted @ 2010-12-20 12:56 哈哈的日子 阅读(224) | 评论 (0)编辑 收藏
下面的网址可以浏览,但不是实际下载的地址
http://s3browse.springsource.com/browse/maven.springframework.org/

实际下载的地址是

http://maven.springframework.org/xxxx

就是去掉前面的
http://s3browse.springsource.com/browse/

浏览进去下载一下,看看网址就知道了。

posted @ 2010-12-08 15:50 哈哈的日子 阅读(276) | 评论 (0)编辑 收藏
1424-4118-1138-0912-4001-7222
需要在 hosts 文件中加入
127.0.0.1 activate.adobe.com 
posted @ 2010-12-06 14:18 哈哈的日子 阅读(588) | 评论 (0)编辑 收藏

一、简介

       SQL*LOADERORACLE的数据加载工具,通常用来将操作系统文件迁移到ORACLE数据库中。SQL*LOADER是大型数据仓库选择使用的加载方法,因为它提供了最快速的途径(DIRECTPARALLEL)。使用前提是必须存在目标表。

二、SQL*LOADER使用方法

    Window系统下,SQL Loader的命令为sqlldr,在UNIX下一般为sqlldr/sqlload

有效的关键字:   
userid   --   ORACLE   用户名/口令   
control   --   控制文件名  
log   --   日志文件名 
bad   --   错误文件名,如果有的数据没有被处理,将会出现在这里   
data   --   数据文件名  
discard   --   废弃文件名 
discardmax   --   允许丢弃数据的数目   (全部默认)   
skip   --   要跳过的逻辑记录的数目   (默认0)   
load   --   要加载的逻辑记录的数目   (全部默认)   
errors   --   允许的错误记录数目  (默认50)   
rows   --   常规路径绑定数组中或直接路径保存数据间的行数  (默认:   常规路径   64,   所有直接路径)   
bindsize   --    常规路径绑定数组的大小,以字节计算(默认65536)   
silent   --   运行过程中隐藏的信息   (header,feedback,errors,discards,partitions)   
direct   --   使用直接路径   (默认FALSE)   
parfile   --   参数文件:包含参数说明的文件的名称
parallel   --   执行并行加载   (默认FALSE)   

file -- 要从以下对象中分配区的文件
skip_unusable_indexes -- 不允许/允许使用无用的索引或索引分区  (默认 FALSE)
skip_index_maintenance -- 没有维护索引, 将受到影响的索引标记为无用  (默认 FALSE)

commit_discontinued -- 提交加载中断时已加载的行  (默认 FALSE)
readsize -- 读取缓冲区的大小               (默认 1048576)
external_table -- 使用外部表进行加载; NOT_USED, GENERATE_ONLY, EXECUTE  (默认 NOT_USED)
columnarrayrows -- 直接路径列数组的行数  (默认 5000)
streamsize -- 直接路径流缓冲区的大小 (以字节计)  (默认 256000)
multithreading -- 在直接路径中使用多线程
resumable -- 启用或禁用当前的可恢复会话  (默认 FALSE)
resumable_name -- 有助于标识可恢复语句的文本字符串
resumable_timeout -- RESUMABLE 的等待时间 (以秒计)  (默认 7200)
date_cache -- 日期转换高速缓存的大小 (以条目计)  (默认 1000)

PLEASE NOTE: 命令行参数可以由位置或关键字指定。前者的例子是 'sqlload scott/tiger foo'; 后一种情况的一个示例是 'sqlldr control=foo userid=scott/tiger'.位置指定参数的时间必须早于但不可迟于由关键字指定的参数。例如,允许 'sqlldr scott/tiger control=foo logfile=log', 但是不允许 'sqlldr scott/tiger control=foo log', 即使参数 'log' 的位置正确。

三、SQL*LOADER实例

控制文件脚本实例:

load data    --控制文件表示
infile 'e:\aa.csv'    --有导入的数据文件名
append into table TBL_SYNC_CORE_INSURANCE    --向表TBL_SYNC_CORE_INSURANCE中追加记录
fields terminated by ','  --指定用逗号分隔
OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS  
--表的字段没有对应值时允许为空
*************下面是表的字段
(
  COVERAGE_CODE,
  PRODUCT_NO,
  NAME,
  MAIN_COVERAGE_CODE,
  KIND,
  CREATOR,
  CREATED_DATE,
  MODIFIER,
  MODIFIED_DATE
)

      备注:数据导入的方式上例中用的append,有一下几种:insert,为缺省方式,在数据装载开始时要求表为空;append,在表中追加新记录;replace,删除旧记录,替换成新装载的记录   ;truncate,同replace,会用truncate语句删除现存数据

      在命令行提示符下使用SQL*Loader命令实现数据的输入:

      sqlldr   userid=用户名/口令@服务名   control='e:\control.ctl'   log=e:\log.txt   bad=e:\bad.txt

      如果本地安装了oracle服务端,可以不写服务名;log和bad不写,默认生成在当前目录下。

四、其他导入方法

      利用PLSQL   Developer:

      在单个文件不大的情况下(少于100000行),并且目的表结构已经存在的情况下-----对于excel而言肯定不会超过了,因为excel文件的最大行为65536-----可以全选数据COPY   ,然后用PLSQL   Developer工具。

      1   在PLSQL   Developer的sql   window里输入select   *   from   test   for   update;   
      2   按F8执行;
      3   打开锁,   再按一下加号.   鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后COMMIT提交即可。

五、补充在Linux下使用 sqlldr 的注意事项

在执行 sqlldr 前,需要进行以下步骤

  1. 设置 ORACLE_HOME 环境变量,如 export ORACLE_HOME=/usr/lib/oracle/xe/app/oracle/product/10.2.0/server
  2. 设置ORACLE编码格式,将本地字符集和ORACLE字符集设置为一致,如export NLS_LANG="SIMPLIFIED CHINESE_CHINA.AL32UTF8"
  3. 将csv文件转码成相应的编码

然后再使用 sqlldr 进行数据导入

posted @ 2010-11-07 15:42 哈哈的日子 阅读(4122) | 评论 (0)编辑 收藏
原因:

因为公司搬迁,两天左右,svn服务器不能使用,需要搭建临时的 svn 服务器。

一、备份 svn 服务器:

首先,使正在使用的 svn 无法提交。方法是:

在正在使用的 svn 服务器上,增加一个 pre-commit hook,在不使用 perl, python 等脚本的情况下,windows 就是 pre-commit.bat,linux 就是 pre-commit

使这个 hook 始终 exit 1

然后旧的 svn 服务器就没办法提交了。

文件 copy 一份出来就可以了,放在另外一个服务上,启动,然后让大家 relocate 一下,就可以使用新的 svn 服务器了。

二、恢复 svn 服务器

旧的 svn 依然不能提交,即 pre-commit hook exit 1,将新的 svn 服务器也设置为不能提交。

然后:

在新的 svn 服务器上,使用 svnadmin dump -r xxx:HEAD --incremental > dump 进行增量的版本库 dump

xxx 是我们备份的下一个版本号

将旧的 svn 服务器设置为可以提交,即删除 pre-commit hook 或修改为正常使用的 hook,然后在旧的 svn 服务器上使用 svnadmin load < dump 就可以将新的服务器上提交的内容恢复到旧的服务器上。

让大家 relocate 回到旧的服务器上,就可以了。

完成!
posted @ 2010-10-16 13:09 哈哈的日子 阅读(903) | 评论 (3)编辑 收藏

这种方法SEO不好,需要SEO的,请不要使用。
在ckeditor中,增加分页符,然后可以使用下面的代码进行 js 分页。


$(
function() {
    
var top = "#content";
    
var content = $(top);
    
var all = content.find("*");
    
var pages = [];
    
function hideContent() {
        all.hide();
    }
    
function showArray(arr) {
        $.each(arr, 
function(i) {
            
this.show().parentsUntil(top).show();
        });
    }
    
function initPages(pageBreaks) {
        pageBreaks.each(
function(index) {
            $(
this).attr("id""pageBreak" + index);
        });
        
var current = 0;
        pages[
0= [];
        all.each(
function(i) {
            
var id = $(this).attr("id");
            
if(id == "pageBreak" + current) {
                current
++;
                pages[current] 
= [];
            } 
else {
                pages[current].push($(
this));
            }
        });
    }
    
function showPage(i) {
        hideContent();
        showArray(pages[i]);
    }
    
var pageBreaks = content.find("div[style]").filter(function() {
        
return $(this).css("page-break-after"== "always";
    });
    
if(pageBreaks.size() > 0) {
        initPages(pageBreaks);
        $(
"#pagingBar").pagination(pages.length, {
            callback: 
function(index) {
                showPage(index);
            },
            prev_text: '
<',
            next_text: '
>',
            items_per_page: 
1,
            num_display_entries: 
5,
            num_edge_entries: 
2
        });
        showPage(
0);
    }
    $(
"#content").show();
});
posted @ 2010-06-23 00:58 哈哈的日子 阅读(975) | 评论 (0)编辑 收藏
grant all privileges on *.* to root@'%' identified by '' with grant option;
posted @ 2010-06-11 15:02 哈哈的日子 阅读(199) | 评论 (0)编辑 收藏
产品需要一个邮件服务器,目标定位在 Apache James,原因是 sendmail 不好配,没弄明白。
开工!

1. 下载 James,是个 zip 包或是 tar 包,解压,windows 下不说,linux 下 tar -xf apache-james-2.3.2.tar.gz
2. 到 james-x.x.x/bin 目录下,linux 需要 chmod a+x *.sh,加上执行属性,然后运行 ./phoenix.sh start,然后快点儿 ./phoenix.sh stop,start 是因为会生成一个展开目录的 james,快一些 stop 是因为无数的垃圾邮件服务器在连接你,用你当垃圾邮件发送器
3. 修改 james-x.x.x/apps/james/SAR-INF/config.xml 文件,这步是最重要的。
    a) 修改 <servername>haha.com</servername>,把这个修改为你的域名,注意:要和你的机器 hostname 一致,至于怎么改 hostname,请参考我转的另一篇文章
    b) 把下面这段注释掉
         <mailet match="RemoteAddrNotInNetwork=127.0.0.1" class="ToProcessor">
            <processor> relay-denied </processor>
            <notice>550 - Requested action not taken: relaying denied</notice>
         </mailet>
    c) 把下面这段原来被注释掉的去掉注释
         <authRequired>true</authRequired>
    d) 把下面的被注释掉的,也去掉注释
         <verifyIdentity>true</verifyIdentity>
    e) 修改 root 密码,就是这行 <account login="root" password="new_password"/>
4. 重新执行 ./phoenix.sh start

你已经成功了。
posted @ 2010-05-31 22:32 哈哈的日子 阅读(560) | 评论 (0)编辑 收藏
http://www.onlyit.cn/bbs_html/200603/article_49_1284.htm

域名记录简介 
概述 
成功注册了域名之后,域名的日常管理就是对各种域名记录的配置和管理。下面我对常用的三种域名记录进行一个简单的介绍,这三种域名记录类型分别是 A 记录(地址记录)、 CNAME 记录(别名记录)和 MX 记录(邮件服务器记录)。前面两种主要作用都是将一个域名解释成一个 IP 地址,用于几乎所有的 TCP/IP 通信。后一种是将一个域名解释成一个邮件服务器的域名,只用于 SMTP (互联网的邮件系统)通信过程。 
在开始之前需要简单说明一下 DNS 系统所作的事情不仅仅是将域名解释成 IP 地址。 DNS 实际上作的是名字翻译工作。虽然在 TCP/IP 环境下最后基本上都会牵扯到 IP 地址。但是 DNS 允许通过不同的类型让同一个名称拥有不同的含义。比如同样的 oray.net 这个名称在 Web/FTP 通信过程中对应的是一个地址,在 SMTP 通信中则变成一个邮件服务器。这样就允许我们将 Web 和 SMTP 服务器放在不同的 IP 地址上。 
DNS 服务器进行名字解释的时候依赖的是一个数据文件,每个域名都有一个独立的数据文件,这个文件包括了该域名所有的名称,名称对应的类型和对应的类型数据。 DNS 规定的名称类型有近 20 个,不过常用的除了我们下面介绍的三种外,还有就是 soa 记录和 NS 记录。 
记录生存时间 
所有的名字记录都有一个相同的属性就是生存时间( TTL ),这个属性用来控制其它 DNS 服务器在什么时候删除这个记录的解释结果,是一个非常重要的参数。在前面我们讲过为了提高域名解释的速度。一般的 DNS 服务器都会缓存代理解释的结果。但是如果授权服务器的记录发生改变,曾经代理解释过这个记录的 DNS 服务器不会那么快反应这个变化。因为在记录缓存失效之前,这些服务器会使用缓存中的结果回答收到的查询申请。所以缓存虽然提高了查询效率,但是负面的作用就是变化的反应时间延长。技术上叫收敛过程缓慢,一个记录的缓存时间越长,收敛就越慢。在同一个域名下不同的域名记录的缓存时间是可以单独控制的,对于经常需要变化的域名记录我们一般采用较短的缓存时间。 
为了改善这种慢收敛效应, DNS 规定了记录的代理解释的服务器在使用缓存数据回应的时候,包含在回应数据中的缓存时间是原始缓存时间减去已经缓存的时间。例如一个记录在授权服务器上设置的缓存时间是 1 小时,那么代理解释服务器通过授权服务器得到的结果的原始缓存时间就是 1 小时,缓存了半小时后,代理解释服务器上再次受到解释请求,这是服务器通过缓存解释域名,不过回应的时候告诉客户这股只剩下半小时的缓存时间。如果客户是另一台代理服务器那么这台服务得到的原始缓存时间就只有半小时了。这样的机制保证了一个记录变化之后最坏情况下被缓存的时间最长就是设定的生存时间。 
A 记录(地址记录) 
这种记录是最简单的一种记录类型,其功能就是将域名解释成一个 IP 地址。配置的时候(不同的系统有不同的操作界面,不过基本的原理差不多)输入名称和一个 IP 地址。留意一下生存时间就可以了。 
一个名字可以对多个 IP 地址,这样就需要使用多条 A 记录来实现。在解释的时候 DNS 服务器基本上都会支持一种 “ 轮换 ” ( Round Robin )机制。如果同一个类型的同一个名字有多条记录,虽然每次查询都斛返回所有的记录内容,不过在返回的过程中数据排列的顺序每次都不相同。由于大部分的客户端只选择第一条记录所以通过这种方式可以实现一定程度的负载平衡。 
CNAME (别名记录) 
这种记录的作用是将一个域名解释成另外一个域名,两个域名不一定需要在同一个域下。通常为了方便域名的管理。如果一个 IP 地址对应着多个域名的话,经常使用若干条 CNAME 记录和一条 A 记录来替代多条 A 记录。这样当 IP 地址发生变化的时候只需要改变一条 A 记录就可以了。 
理论上别名记录本身也可以只想另外一个别名记录,不过一般不这么做。应为最后我们需要的是得到一个地址。多极别名会大大降低域名的查询速度,而且一些服务器不会正常解释这种域名记录。 
MX (邮件服务器记录) 
这种记录用来说明负责接受指定域名的邮件的邮件服务器是哪一个。仅用于 SMTP 服务转发邮件的时候。当 SMTP 服务器需要向外转发 name@Domain.com 的邮件的时候。首先会像 DNS 查询类行为 MX ,名称为 Domain.Com 的记录。如果没有 MX 记录则会使用 A 类型再查询一次。所以 MX 记录在一定程度上是可以使用 A 记录替代的。 
MX 记录的结果比上面两个稍微复杂一些,它包含一个邮件服务器的域名和一个邮件服务器的优先级,如果你的域名使用多个 SMTP 服务器接受邮件的话,你可以使用多条 MX 记录指出所有的邮件的服务器,通过优先级参数配置那一台服务作为首选服务器。一般情况下邮件会发给优先级最高的服务器(数值最小的),如果该服务器不能连通,则转到下一个优先级的服务器。想通优先级的服务器的顺序可以由 “ 轮换 ” 机制决定。 
一般情况下,即使你的其他服务器和邮件服务区使用相同的 IP 地址也建议使用 MX 记录来表示邮件服务器。相对于简单的 A 记录来说, MX 记录的优先级可以控制,另外你保持了邮件服务和其他服务的独立性。
posted @ 2010-05-30 00:26 哈哈的日子 阅读(267) | 评论 (0)编辑 收藏
test
test
test
e538-c851-cf5a-930c-1943
posted @ 2010-05-27 09:44 哈哈的日子 阅读(329) | 评论 (0)编辑 收藏
有篇文章讲得太好了,引用在下面:

怎样修改Linux的hostname
http://hi.chinaunix.net/?uid-13066923-action-viewspace-itemid-30947

Linux操作系统的hostname是一个kernel变量,可以通过hostname命令来查看本机的hostname。也可以直接cat /proc/sys/kernel/hostname查看。

#hostname
#cat /proc/sys/kernel/hostname
上面两种输出结果相同。

修改运行时Linux系统的hostname,即不需要重启系统
hostname命令可以设置系统的hostname

#hostname newname
newname即要设置的新的hostname,运行后立即生效,但是在系统重启后会丢失所做的修改,如果要永久更改系统的hostname,就要修改相关的设置文件。

永久更改Linux的hostname

man hostname里有这么一句话,”The host name is usually set once at system startup in /etc/rc.d/rc.inet1 or /etc/init.d/boot (normally by reading the contents of a file which contains the host name, e.g. /etc/hostname).” RedHat里没有这个文件,而是由/etc/rc.d/rc.sysinit这个脚本负责设置系统的hostname,它读取/etc /sysconfig/network这个文本文件,RedHat的hostname就是在这个文件里设置。

所以,如果要永久修改RedHat的hostname,就修改/etc/sysconfig/network文件,将里面的HOSTNAME这一行修改成HOSTNAME=NEWNAME,其中NEWNAME就是你要设置的hostname。

Debian发行版的hostname的配置文件是/etc/hostname。

修该配置文件后,重启系统就会读取配置文件设置新的hostname。

hostname与/etc/hosts的关系

很过人一提到更改hostname首先就想到修改/etc/hosts文件,认为hostname的配置文件就是/etc/hosts。其实不是的。

hosts文件的作用相当如DNS,提供IP地址到hostname的对应。早期的互联网计算机少,单机hosts文件里足够存放所有联网计算机。不过随着互联网的发展,这就远远不够了。于是就出现了分布式的DNS系统。由DNS服务器来提供类似的IP地址到域名的对应。具体可以man hosts。

Linux系统在向DNS服务器发出域名解析请求之前会查询/etc/hosts文件,如果里面有相应的记录,就会使用hosts里面的记录。/etc/hosts文件通常里面包含这一条记录

127.0.0.1    localhost.localdomain   localhost
hosts文件格式是一行一条记录,分别是IP地址 hostname aliases,三者用空白字符分隔,aliases可选。

127.0.0.1到localhost这一条建议不要修改,因为很多应用程序会用到这个,比如sendmail,修改之后这些程序可能就无法正常运行。

修改hostname后,如果想要在本机上用newhostname来访问,就必须在/etc/hosts文件里添加一条newhostname的记录。比如我的eth0的IP是192.168.1.61,我将hosts文件修改如下:

#hostname blog.infernor.net
# cat /etc/hosts
127.0.0.1  localhost.localdomain localhost
192.168.1.61    blog.infernor.net       blog
这样,我就可以通过blog或者blog.infernor.net来访问本机。

从上面这些来看,/etc/hosts于设置hostname是没直接关系的,仅仅当你要在本机上用新的hostname来访问自己的时候才会用到/etc/hosts文件。两者没有必然的联系。

RHEL还有个问题。

我开始在测试的时候,只修改/etc/hosts,里面添加 192.168.1.61 blog.infernor.net blog,而/etc/sysconfig/network维持原状,也就是里面的HOSTNAME=localhost.localdomain。我重启系统后居然发现hostname给修改成了blog.infernor.net。这样看的话,倒真觉得/etc/hosts是hostname的配置文件。后来终于在/etc/rc.d/rc.sysinit这个启动脚本里发现了问题的所在。

rc.sysinit文件里一开始就设置了hostname

if [ -f /etc/sysconfig/network ]; then
. /etc/sysconfig/network
fi
if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then
HOSTNAME=localhost
fi
确实使用了/etc/sysconfig/network里的hostname值。不过后面还有一段关于设置hostname的

ipaddr=
if [ "$HOSTNAME" = "localhost" -o "$HOSTNAME" = "localhost.localdomain" ]
; then
ipaddr=$(ip addr show to 0/0 scope global | awk '/[[:space:]]inet
/ { print gensub("/.*","","g",$2) }')
if [ -n "$ipaddr" ]; then
eval $(ipcalc -h $ipaddr 2>/dev/null)
hostname ${HOSTNAME}
fi
fi
脚本判断hostname是否为localhost或者localhost.localdomain,如果是的话,将会使用接口IP地址对应的 hostname来重新设置系统的hostname。问题就出在这里,我的/etc/sysconfig/network默认的hostname是 localhost.localdomain,eth0的IP是192.168.1.61,而/etc/hosts里有192.168.1.61的记录。于是就用192.168.1.61这条记录来替换了hostname。

估计这也是很多人将/etc/hosts误以为是hostname的配置文件的原因。

hostname带选项查询

hostname的-s -f -i等等选项都用到了/etc/hosts或者DNS系统,跟我们讨论的hostname有点远了,也容易产生误会。具体可以man hostname查看。

posted @ 2010-05-25 20:17 哈哈的日子 阅读(842) | 评论 (0)编辑 收藏
     摘要:   阅读全文
posted @ 2010-04-13 16:55 哈哈的日子 阅读(463) | 评论 (0)编辑 收藏
SET FOREIGN_KEY_CHECKS=0;

方便啊,平时多累啊。
posted @ 2010-04-13 16:27 哈哈的日子 阅读(215) | 评论 (0)编辑 收藏
修改 /etc/my.cnf 文件,在 [mysqld] 中增加

log             = /path/mysql.log
log_slow_queries= /path/mysql_slow.log
long_query_time = 1

即可
posted @ 2010-04-12 13:37 哈哈的日子 阅读(496) | 评论 (0)编辑 收藏
jQuery 1.4.2
  • IE 6.0+
  • FF 2+
  • Safari 3.0+
  • Opera 9.0+
  • Chrome
Dojo 1.4
  • Firefox 2 support dropped. Firefox 3.0 through 3.6 supported.
  • Latest Safari (Safari 4) and latest Chrome (Chrome 3) supported, but not previous versions.
  • IE6, IE7, IE8 all supported.
  • Latest Opera (Opera 10) (Dojo core only).
  • Keyboard now supported in all supported browsers (previously it didn't work on Safari and on Chrome)
Extjs 3.2
  • Internet Explorer 6+
  • FireFox 1.5+ (PC, Mac)
  • Safari 3+
  • Opera 9+ (PC, Mac)
MooTools 1.2.4
  • Safari 2+
  • Internet Explorer 6+
  • Firefox 2+ (and browsers based on gecko)
  • Opera 9+
Prototype 1.6 没找到
 
另外,Google为大部分的js框架提供CDN服务,列表如下:
  • jQuery
  • jQuery UI
  • Prototype
  • script.aculo.us
  • MooTools
  • Dojo
  • SWFObject
  • Yahoo! 用户界面库 (YUI)
  • Ext Core新增!
具体可参考http://code.google.com/intl/zh-CN/apis/ajaxlibs/
posted @ 2010-04-07 09:51 哈哈的日子 阅读(1445) | 评论 (0)编辑 收藏
     摘要: (?:^| )editor(?:$| )

看了半天没明白,后来打开 RegexTester 试了一下,原来(?:^| )是“字符串开始或空格开头”的意思,后面的(?:$| )同理。
sigh,以为自己正则表达式也看过一些了,但看了 perl 和 js 一些库之后,觉得自己的正则表达式水平怎么也忒差了点儿,再学学吧。

另外:
CKEditor 的 config.js 里面的内容是

CKEDITOR.editorConfig = function( config )
{
// Define changes to default configuration here. For example:
//config.language = 'fr';
config.uiColor = '#CCDC6E';
};

我眼花了,还以为是返回一个 Object config 呢,害得我写上了:

config.filebrowserUploadUrl :   阅读全文
posted @ 2010-04-05 11:44 哈哈的日子 阅读(1432) | 评论 (1)编辑 收藏
把 Nexus 加成服务的时候启动不了,发现的这个问题。
同样启动 sonar 也有这个问题。
posted @ 2010-04-02 10:13 哈哈的日子 阅读(150) | 评论 (0)编辑 收藏
如果使用 Nexus 的话,需要配置一个 Proxy Repository,目标指向 http://yoursonar:sonarport/deploy/maven,如果没改过什么的话,应该是 http://localhost:9000/deploy/maven

另外,可以直接访问 http://localhost:9000/deploy/maven/README.txt,有一些说明性的内容。
posted @ 2010-03-30 17:40 哈哈的日子 阅读(482) | 评论 (0)编辑 收藏

我使用的是 163 的邮箱和iphone手机,手机支持pushmail的功能,但163邮件不支持。
以下做法可以让我的163邮箱好象有pushmail的功能,还带有免费的短信通知,前提是用移动的手机。

通过移动手机申请个139的邮箱,并打开短信通知功能。
申请个 gmail,可以在 gmail 里设置使用 163 的邮件地址做为发件人地址。
设置163邮箱自动转发至gmail邮箱中(以前自动转发是收费服务,我今天试了一下,好象不要钱了)
设置 gmail 邮件转发至 139 邮箱中。
当然还要配置手机的 push mail 至 gmail

这样的话,当 163 邮箱收到邮件的时候,手机会收到 push mail(来自gmail)和短信通知(来自139邮箱)


posted @ 2010-03-27 12:08 哈哈的日子 阅读(321) | 评论 (0)编辑 收藏
首先,对一个 array 进行排序,但得到的结果与想象的不一样,是 2010-1-13, 2010-1-22, 2010-1-15
        var sortArray=[
         {title:"aaa", date:"2010-1-22"},
         {title:"trtttt", date:"2010-1-15"},
         {title:"erere", date:"2010-1-13"}
        ];
        sortArray.sort(function(x,y){
         var x1=new Date(x.date.replace("-","/"));
         var y1=new Date(y.date.replace("-","/"));
         //alert("x1=" + (x1.getMonth()+1)+"/"+x1.getDate() + ", y1 = " + (y1.getMonth()+1)+"/"+y1.getDate() + ", x1 > y1 = " + (x1 - y1));
         return x1>y1;
        });
        for(var i=0;i<sortArray.length;i++) {
         var x1=new Date(sortArray[i].date.replace("-","/"));
         alert(x1.getYear() + "-" + (x1.getMonth() + 1) + "-" + x1.getDate() + " , " + sortArray[i].date + " | " + sortArray[i].title);  
        }
要把标红的部分改成
        return x1-y1;
看来,js 排序的时候为了内部优化,排序和 sort 的 function 结果有关。
posted @ 2010-03-22 14:01 哈哈的日子 阅读(610) | 评论 (1)编辑 收藏

转自:http://cupoy.javaeye.com/blog/251796

1. 脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

2. 不可重复读 :是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题。

3. 幻读 : 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材料添加到该文档中。如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。

补充 : 基于元数据的 Spring 声明性事务 :

Isolation 属性一共支持五种事务设置,具体介绍如下:

l          DEFAULT 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别 .

l          READ_UNCOMMITTED 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )

l          READ_COMMITTED  会出现不可重复读、幻读问题(锁定正在读取的行)

l          REPEATABLE_READ 会出幻读(锁定所读取的所有行)

l          SERIALIZABLE 保证所有的情况不会发生(锁表)

不可重复读的重点是修改 :
同样的条件 ,   你读取过的数据 ,   再次读取出来发现值不一样了
幻读的重点在于新增或者删除
同样的条件 ,   第 1 次和第 2 次读出来的记录数不一样

posted @ 2010-03-10 11:09 哈哈的日子 阅读(206) | 评论 (0)编辑 收藏

编译 Trigger 出错,错误的原因是找不到sequence,但是在 sql 里面使用这个sequence非常正常。找了半天原因,另一个同事试了一下给这个sequence授权,就可以编译通过了。
疑惑了很久,为什么sql中可以用,编译trigger就不能用了呢。
查了一些资料,才明白。
是因为 Oracle 在编译Procedu的时候,只检查当前用户的权限,而不管角色。所以,即使这个用户是DBA,也没有用,必须要对这个用户授权。这就是显式授权。
我在CSDN上找到了一个很好的文章,解释了显式授权和隐式授权的区别。
附在下面。






来自CSDN博客,http://blog.csdn.net/pashine/archive/2009/12/21/5050060.aspx


oracle 对象的授权
Oracle授权

 

一、授权语法


GRANT 语法:

1.显式授权(直接将对象授权给用户)
 GRANT privilege [, ...] ON object [, ...]  TO  { Public| Group | Username|role} [WITH GRANT OPTION ] 
  
2.隐式授权(通过将角色授权给用户)
 GRANT role TO  { Public| Group | Username|role}

语法说明:

privilege (权限)
   可能的权限有:
     SELECT--访问声明的表/视图的所有列/字段.
     INSERT--向声明的表中插入所有列字段.
     UPDATE--更新声明的所有列/字段.
     DELETE --从声明的表中删除所有行.
     RULE   在表/视图上定义规则 (参见 CREATE RULE 语句).
     ALL 赋予所有权限.

object 赋予权限的对象名.
    可能的对象是: 
     table (表)
     view (视图)
     sequence (序列)
     index (索引)
Public    代表是所有用户的简写.
Group     将要赋予权限的组GROUP .目前的版本中,组必须是用下面方法显式创建的.
Username  将要赋予权限的用户名.PUBLIC 是代表所有用户的简写.
role      某个角色,(如DBA)
WITH GRANT OPTION 允许向别人赋予同样权限,被授权的用户可以继续授权.


描述
    对象创建后,除了创建者外,除非创建者赋予(GRANT)权限,其他人没有访问对象的权限。
    GRANT 允许对象的创建者给某用户或某组或所有用户(PUBLIC)某些特定的权限。不需要给创建者赋予(GRANT)对象的权限,创建者自动拥有对象的所有权限,包括删除它的权限。

说明

Oracle不允许在过程中使用未经显式授权的对象. 要使用另一用户的对象,必须通过另一用户给自己显示授权。

因为Oracle在编译存储过程时并不检查定义者拥有的角色,只是检查其被显式授予的权限,而DBA也是一种角色,所以即使是DBA,也需要显式授权。

二、授权方式 (显式和隐式)


  对象授权有两种模式,显式和隐式: 
显示授权和隐式授权的区别是:显示授权是直接把对象授权给用户,隐式授权是给用户授予角色的方式来实现授权。

1. 显式授权是直接用GRANT语句进行授权。
 语法:GRANT 某种权限 TO 用户
如:
  CONN  USER1/Password
  GRANT SELECT  ON TABLE1 TO USER2;    --- 将user1的表TABLE1的select 权限显示授权给user2
  GRANT UPDATE  ON TABLE1 TO USER2;    --- 将user1的表TABLE1的update权限显示授权给user2


  注:用system/manager登录是没法授权的,要使USER2用户能在存储过程里面访问USER1用户的表,必须以USER1用户(该用户有dba权限)登录,然后授权就可以了。
  SQL>grant select on USER1.MA_USERINFO to USER2

2.隐式授权则是通过ROLE来授权。
 语法:GRANT 某个角色 TO 用户
如: 
  CONN  USER1 
  GRANT SELECT ON TABLE1 TO ROLE1;     --- 将USER1的表TABLE1的select权限显示授权给Role1
  CONN  SYSTEM 
  GRANT ROLE1 TO USER2;                --- 给USER2授与Role1的权限。


三、收回权限


   语法:
       revoke 权限 from 用户;

   例子:

  revoke select on table1 from User1; 收回查询select表的权限;
  revoke all    on table1 from User1;
    grant  connect to xujin;
  revoke  connect  from xujin

      revoke  ROLE1    from USER2;

End

posted @ 2010-03-05 11:25 哈哈的日子 阅读(1127) | 评论 (0)编辑 收藏

command + L : safari 在地址栏输入网址

command + option + L : safari 显示下载列表

command + shift + [ : safari 选择上一个标签

command + shift + ] : safari 选择下一个标签

command + enter : safari 在新的 tab 页中打开网页,也可以 command + 点击链接

fn + delete : 删除光标后面的字母,相当于 windows 下面的 delete

control + a : 相当于 windows 下的 home

control + e : 相当于 windows 下的 end

command + option + f : safari 中的 google search

command + option + ctrl + ⏏ : 关机

command + option + 拖拽 : 建立快捷方式

option + 点击已经最小化窗口 : 还原全部最小化窗口

posted @ 2010-02-03 20:45 哈哈的日子 阅读(181) | 评论 (0)编辑 收藏
1. 准备mysql,参考jira 4.0.1 war 方式的安装过程,使用mysql第1步,将数据库名由jiradb修改为confluence
2. 准备tomcat,参考jira 4.0.1 war 方式的安装过程,使用mysql第2步,2-b不做
3. 准备confluence
  a)下载confluence-3.1.zip,解压到一个临时目录$confluence_temp
  b)修改$confluence_temp\confluence\WEB-INF\classes\confluence-init.properties,增加一行 confluence.home=D:/atlassian/confluence,红色部分修改为实际的目录,confluence相关的数据会存到这个目录。
  c)下载confluence_crack.rar,将文件解压到$confluence_temp\confluence\WEB-INF\classes目录下
  d)运行$confluence_temp\build.bat
  e)将$confluence_temp\dist\confluence-3.1.war文件放到合适的目录下$confluence_war(或者不移动)
  f)在$catalina_home\conf\Catalina\localhost目录下创建confluence.xml,内容为<Context path="/confluence" docBase="$confluence_war" debug="0" reloadable="true" />,将$confluence_war替换为上一步的文件路径

然后启动tomcat,访问http://localhost:8080/confluence就可以了

license填写如下

Description=Confluence\: COMMERCIAL
NumberOfUsers=500
CreationDate=2010-01-22
ContactName=haha@haha.haha
conf.active=true
ContactEMail=haha@haha.haha
Evaluation=false
conf.LicenseTypeName=COMMERCIAL
MaintenanceExpiryDate=2011-01-21
conf.NumberOfClusterNodes=0
Organisation=haha
ServerID=HAHA-HAHA-HAHA-HAHA
LicenseID=LID
LicenseExpiryDate=2011-01-21
PurchaseDate=2010-01-22
posted @ 2010-01-25 10:59 哈哈的日子 阅读(2249) | 评论 (1)编辑 收藏

接着上一个的jira 4.0.1 war 方式的安装过程,使用mysql,把jira的login加上crowd,为之后增加confluence和svn的sso做准备

第一步先把jira的认证改成使用crowd,接着上次安装完jira的tomcat,继续安装

1. 准备mysql
  a)创建一个库create database crowd character set utf8;
  b)在my.ini中增加一行
  [mysqld]
  transaction-isolation = READ-COMMITTED
2. 准备tomcat
  a)修改$catalina_home\conf\server.xml,增加useBodyEncodingForURI="true",如下:
  <Connector port="8080" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" useBodyEncodingForURI="true"/>
  b)下载javamail api,放到$catalina_home\lib目录下
3. 准备crowd
  a)下载atlassian-crowd-2.0.3-war.zip,并解压到$crowd_home
  b)修改$crowd_home\WEB-INF\classes\crowd-init.properties,增加配置crowd.home=$crowd_home($crowd_home替换成实际目录)
  c)创建crowd.xml,内容为<Context path="/crowd" docBase="$crowd_home" reloadable="false"/>($crowd_home替换成实际目录),将这个文件放到$catalina_home\conf\Catalina\localhost目录下
  d)启动tomcat,进入crowd,如:http://localhost:8080/crowd
  e)到applications中add application,类型选jira,name: jira, password: haha, url: http://localhost:8080/jira, ip最好手工填, directories选一个需要的,Allow all users to authenticate我选上了,成功
  f)import jira users在users里面选import users,import 的时候注意把dbname修改为jiradb就可以了。
4. 准备jira
  a)修改$jira_home\WEB-INF\classes\crowd.properties,如
  application.name                        jira
  application.password                    haha
  application.login.url                   http://hostname/jira/
  crowd.server.url                        http://hostname/crowd/services/
  ...
  其它的不需要修改
  b)修改$jira_home\WEB-INF\classes\osuser.xml,内容如下:

<!-- This is where JIRA's credentials checking can be configured.  For instance, see
http://www.atlassian.com/software/jira/docs/latest/ldap.html 
-->
<opensymphony-user>

    
<authenticator class="com.opensymphony.user.authenticator.SmartAuthenticator" />

<!-- CROWD:START
    You will need to uncomment the Crowd providers below to enable Crowd integration
    and comment out the default providers that are located further down in this file.
-->
    
<provider class="com.atlassian.crowd.integration.osuser.CrowdCredentialsProvider"/>
    
<provider class="com.atlassian.crowd.integration.osuser.CrowdAccessProvider"/>
    
<provider class="com.atlassian.crowd.integration.osuser.DelegatingProfileProvider">
        
<property name="provider-1">com.atlassian.crowd.integration.osuser.CrowdProfileProvider</property>
        
<property name="provider-2">com.atlassian.jira.user.ExternalEntityJiraProfileProvider</property>
        
<property name="provider-2-exclusive-access">true</property>
    
</provider>
<!-- CROWD:END -->

<!-- CROWD:START  - The providers below here will need to be commented out for Crowd integration -->
<!--
    <provider class="com.atlassian.core.ofbiz.osuser.CoreOFBizCredentialsProvider">
        <property name="exclusive-access">true</property>
    </provider>

    <provider class="com.atlassian.jira.user.osuser.JiraOFBizProfileProvider">
        <property name="exclusive-access">true</property>
    </provider>

    <provider class="com.atlassian.jira.user.osuser.JiraOFBizAccessProvider">
        <property name="exclusive-access">true</property>
    </provider>
-->
<!-- CROWD:END -->

</opensymphony-user>

  c)修改$jira_home\WEB-INF\classes\seraph-config.xml,内容如下:

<security-config>
    
<parameters>
        
<init-param>
            
<!--
              The login URL to redirect to when the user tries to access a protected resource (rather than clicking on
              an explicit login link). Most of the time, this will be the same value as 'link.login.url'.
                - if the URL is absolute (contains '://'), then redirect that URL (for SSO applications)
                - else the context path will be prepended to this URL

                If '${originalurl}' is present in the URL, it will be replaced with the URL that the user requested.
                This gives SSO login pages the chance to redirect to the original page
            
-->
            
<param-name>login.url</param-name>
            
<param-value>/login.jsp?os_destination=${originalurl}</param-value>
            
<!--<param-value>http://sso.mycompany.com/login?redirectTo=${originalurl}</param-value>-->
        
</init-param>
        
<init-param>
            
<!--
              the URL to redirect to when the user explicitly clicks on a login link (rather than being redirected after
              trying to access a protected resource). Most of the time, this will be the same value as 'login.url'.
                - same properties as login.url above
            
-->
            
<param-name>link.login.url</param-name>
            
<param-value>/login.jsp?os_destination=${originalurl}</param-value>
            
<!--<param-value>/secure/Dashboard.jspa?os_destination=${originalurl}</param-value>-->
            
<!--<param-value>http://sso.mycompany.com/login?redirectTo=${originalurl}</param-value>-->
        
</init-param>
        
<init-param>
            
<!-- URL for logging out.
                 - If relative, Seraph just redirects to this URL, which is responsible for calling Authenticator.logout().
                 - If absolute (eg. SSO applications), Seraph calls Authenticator.logout() and redirects to the URL
                 
-->
            
<param-name>logout.url</param-name>
            
<param-value>/secure/Logout!default.jspa</param-value>
            
<!--<param-value>http://sso.mycompany.com/logout</param-value>-->
        
</init-param>
        
<!-- The key that the original URL is stored with in the session -->
        
<init-param>
            
<param-name>original.url.key</param-name>
            
<param-value>os_security_originalurl</param-value>
        
</init-param>
        
<init-param>
            
<param-name>login.cookie.key</param-name>
            
<param-value>seraph.os.cookie</param-value>
        
</init-param>
        
<!-- This property controls how your cookie is encrypted.  If you truly want to secure your cookies, you need
            to change this to a secure password 
-->
        
<init-param>
            
<param-name>cookie.encoding</param-name>
            
<param-value>jiracookie</param-value>
        
</init-param>
        
<!-- This property sets the default cookie timeout in seconds.  It is currently set to 1 year -->
        
<init-param>
            
<param-name>autologin.cookie.age</param-name>
            
<param-value>31536000</param-value>
        
</init-param>
        
<!-- Basic Authentication can be enabled by passing the authentication type as a configurable url parameter.
        With this example, you will need to pass http://mycompany.com/anypage?os_authType=basic in the url to enable Basic Authentication 
-->
        
<init-param>
            
<param-name>authentication.type</param-name>
            
<param-value>os_authType</param-value>
        
</init-param>
        
<!--  If this parameter is set to true, the cookie will never be set secure.  This is useful if you're logging
              into JIRA via https, but want to browse JIRA over http.  This flag will ensure that the remember me option
              works correctly.
        <init-param>
            <param-name>insecure.cookie</param-name>
            <param-value>true</param-value>
        </init-param> 
-->
    
</parameters>

    
<rolemapper class="com.atlassian.jira.security.JiraRoleMapper"/>

    
<!-- CROWD:START - If enabling Crowd SSO integration uncomment the following JIRAAuthenticator and comment out the DefaultAuthenticator below -->
    
<authenticator class="com.atlassian.crowd.integration.seraph.JIRAAuthenticator"/>
    
<!-- CROWD:END -->

    
<!-- CROWD:START - The authenticator below here will need to be commented out for Crowd SSO integration -->
    
<!--
    <authenticator class="com.atlassian.jira.security.login.JiraOsUserAuthenticator"/>
    
-->
    
<!-- CROWD:END -->

    
<!-- NB: the URL to redirect to is now specified by login.url above -->
    
<services>
        
<service class="com.atlassian.seraph.service.PathService">
            
<init-param>
                
<param-name>config.file</param-name>
                
<param-value>/seraph-paths.xml</param-value>
            
</init-param>
        
</service>

        
<service class="com.atlassian.seraph.service.WebworkService">
            
<init-param>
                
<param-name>action.extension</param-name>
                
<param-value>jspa</param-value>
            
</init-param>
        
</service>
    
</services>

    
<interceptors>
        
<interceptor class="com.atlassian.jira.portal.PortalPageInterceptor"/>
        
<interceptor class="com.atlassian.jira.user.preferences.UserPreferencesResetInterceptor"/>
    
</interceptors>
</security-config>

  d)重启tomcat

一切搞定,可以使用crowd的用户登录jira了,而且只要在一边登录,两边就都登录了。


另外把遇到的问题写一下
1. 在crowd中import jira users的时候,将connection url改正确了之后,就是把dbname改成jiradb,依然无法连接,后来发现是crowd没有mysql jdbc驱动,停掉crowd,将mysql jdbc驱动放到crowd WEB-INF\lib目录,重试就可以了。
2. 所有的都配置好了之后,到jira里面仍然无法登录,通过查看crowd log,发现有这句话[crowd.service.soap.SOAPService] Client host is invalid: 10.40.155.43 / 10.40.155.43,明白了,因为在crowd里面add application的时候,使用的是自动得到IP,得到的是127.0.0.1。解决这个问题的办法就是在IP里面,把这个10.40.155.43也加上,就可以了。

posted @ 2010-01-22 15:27 哈哈的日子 阅读(6979) | 评论 (2)编辑 收藏

安装方式力求简单,更多优化配置需要进一步配置。

1. 准备mysql
  a)下载mysql-noinstall-5.1.42-win32.zip,解压到$mysql_home
  b)到$mysql_home目录下,将my-medium.ini修改为my.ini
  c)到$mysql_home\bin目录下,运行mysqld --console
  d)到$mysql_home\bin目录下,执行mysql -uroot,然后执行sql:
  create database jiradb character set utf8;
  e)下载mysql-connector-java-5.1.11.zip,备用
2. 准备tomcat
  a)下载apache-tomcat-6.0.20.zip,解压到$catalina_home
  b)下载jira-jars-tomcat6.zip,解压到$catalina_home\lib目录下
  c)把之前下载的mysql-connector-java-5.1.11.zip,解压里面的mysql-connector-java-5.1.11-bin.jar到$catalina_home\lib目录下
  d)修改$catalina_home\conf\server.xml文件,将里面的
  <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
  修改为
  <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" />
  e)修改$catalina_home\bin\startup.bat,在@echo off后面增加一行
set CATALINA_OPTS=%CATALINA_OPTS% -Dorg.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true -Dmail.mime.decodeparameters=true -Xms128m -Xmx512m -XX:MaxPermSize=256m
  f)启动一次,然后停止,为了在$catalina_home\conf目录下生成Catalina\localhost目录

3. 准备jira
  a)下载atlassian-jira-enterprise-4.0.1.zip,解压到一个临时目录$jira_temp
  b)修改$jira_temp\edit-webapp\WEB-INF\classes\entityengine.xml,将
  <datasource name="defaultDS" field-type-name="hsql"
  schema-name="PUBLIC"
  修改为
  <datasource name="defaultDS" field-type-name="mysql"
  注意:删除了一行schema-name="PUBLIC"
  c)修改$jira_temp\edit-webapp\WEB-INF\classes\jira-application.properties,将jira.home的值填好,jira相关的数据会放到这个目录下,比如:
  jira.home = D:/atlassian/jira/data
  d)下载jira_crack.rar,将WEB-INF目录解压到$jira_temp\webapp\目录下,覆盖一个目录,新增加了一个目录
  e)运行$jira_temp\build.bat
  f)修改$jira_temp\dist-tomcat\tomcat-6\jira.xml
  一、修改部分如下
  <Resource name="jdbc/JiraDS" auth="Container" type="javax.sql.DataSource"
            username="root"
            password=""
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost/jiradb?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=UTF8"
             maxActive="20"
            validationQuery="select 1"
/>
  注意,删除了两行
  minEvictableIdleTimeMillis="4000"
  timeBetweenEvictionRunsMillis="5000"
  二、如果移动了atlassian-jira-4.0.1.war
  还需要修改docBase
  g)将jira.xml复制到$catalina_home\conf\Catalina\localhost目录下

一切就绪,启动tomcat,第一次需要等比较久一点儿。
访问http://localhost:8080/jira,如果没问题的话,正确的填写配置后,license可以填写

Description=JIRA\: COMMERCIAL
CreationDate=2010-01-20
ContactName=haha@haha.haha
jira.LicenseEdition=ENTERPRISE
ContactEMail=haha@haha.haha
Evaluation=false
jira.LicenseTypeName=COMMERCIAL
jira.active=true
licenseVersion=2
MaintenanceExpiryDate=2011-01-19
Organisation=haha
jira.NumberOfUsers=-1
ServerID=B6FW-B4KW-J1A3-4DQB
LicenseID=LID
LicenseExpiryDate=2011-01-19
PurchaseDate=2010-01-20

就可以了
posted @ 2010-01-21 17:05 哈哈的日子 阅读(3926) | 评论 (7)编辑 收藏
     摘要: 转自:http://www.douban.com/group/topic/5667071/

第一:不要认为停留在心灵的舒适区域内是可以原谅的。
第二:不要把“好像”;“有人会……”;“大概”;“晚些时候”;“或者”;“说不定”之类放在嘴边。尤其是和上级谈论工作的时候。
第三:不要拖延工作
第四:不要认为理论上可以实施就大功告成了!
第五:不要让别人等你
第六:不要认为细节不重要
第七:不要表现得消极,仅仅因为你所做的事情不是你的兴趣所在。
第八:绝对不要把改善工作能力仅寄托在公司培训上
第九:不要推卸责任
第十:不要对自己说“我是大学生”   阅读全文
posted @ 2010-01-09 21:53 哈哈的日子 阅读(310) | 评论 (0)编辑 收藏

增加 weiphone 的源

http://app.weiphone.com/cydia/dists/stable/main/binary-iphoneos-arm/Packages

照别的源弄的,可以使用。
加了 ipa 破解和wefit

但 repo.beyouriphone.com 的源不怎么怎么加。

posted @ 2010-01-06 19:45 哈哈的日子 阅读(370) | 评论 (0)编辑 收藏
weiphone
http://app.weiphone.com/cydia

我用里面的ipa 破解和wefit

BeYoIp
http://repo.beyouriphone.com

里面有破解的 mQuickDo 挺好用的


默人的源里有 sbsetting 好用
posted @ 2010-01-04 12:45 哈哈的日子 阅读(408) | 评论 (0)编辑 收藏

开始使用 jira 4 + greenhopper 4,为了两个原因:
1. 简单:方便的创建问题,方便的更新状态(可视化拖拽)
2. 清晰:图表燃尽图显示项目状态,任务视图直观查看所有任务状态


一直希望项目组所有人都能够清楚的了解项目的状态。而我也能够跟踪项目中问题的状态,但实际情况确不像想象的那么容易。
之前一直使用 jira 来做项目问题管理,包括任务的管理。但发现实际上想要了解项目状态的时候,却比较困难。其实我发现最好工具的是纸、笔和白板,但办公室没有这个条件。

看不到项目状态有以下几个原因:

1. 项目风格比较宽松。愿意把任务记在上面就记,不愿意记就不记。我想起任务的时候,就会把任务记上,分配给相应的人。但不是每个人都习惯这样做。jira上没有所有的任务,自然无法看到状态。
2. 任务状态不及时更新。主要是懒得更新状态,嫌麻烦。其实和第一个原因比较接近。我一般不喜欢强制让别人做什么,只是想自己做自己喜欢的事情,愿意的事情就好了。虽然我认为 jira 用起来已经相当简单了,但仍然有人认为麻烦,所以,基本就不更新状态,或是记东西什么的。
3. 没有时间估计。这个是项目管理上的问题,我的本意是希望简单,自然,不要给同事们带来麻烦。但发现不估计时间简直就等于自杀,完全看不到项目的状态。

ps:其实评估任务的重要性相当的必要,但上面的问题主要是基于已经确定当前版本范围的情况。所以,也就不用太在意哪个更重要了。

第3个问题没有别的办法,只能进行时间估计。我采用大家一起来估计的方法,我充当产品负责人的角色给大家讲解需求,然后让每个人进行估计,因为目前的项目复杂度不高,所以估计工作量并不难。
我觉得大家一起来估计工作量有两个好处:一、大家有参与感,积极性相对会好一些。二、所有人了解所有的需求,以后有问题也好互相帮助。

前两个问题我希望能通过工具的简单程度解决问题,如果做起来很容易,就会自然去做,而不会觉得麻烦了。

我发现 jira 4 + greenhopper 4 可以方便的创建和修改任务,而且可视化拖拽。这样就能大幅度解决问题,而且燃尽图和任务视图,可以非常直观的给出项目状态,大幅度提高所有人对项目进度的认知。

周末随手破解了一下,暂时先用一用,解压到相应的目录下即可。
jira_crack.rar

换了之后,使用明文注册即可,注册信息可以随便修改,如下:
JIRA 的:

#Sun Oct 25 00:50:34 CDT 2009
Description=JIRA\: COMMERCIAL
CreationDate=2009-10-25
ContactName=haha@haha.haha
jira.LicenseEdition=ENTERPRISE
ContactEMail=haha@haha.haha
Evaluation=false
jira.LicenseTypeName=COMMERCIAL
jira.active=true
licenseVersion=2
MaintenanceExpiryDate=2010-10-24
Organisation=haha
jira.NumberOfUsers=-1
ServerID=B6FW-B4KW-J1A3-4DQB
LicenseID=LID
LicenseExpiryDate=2010-10-24
PurchaseDate=2009-10-25


GreenHopper 的:

#Sat Oct 24 19:09:35 CDT 2009
Description=GreenHopper for JIRA 4\: COMMERCIAL
CreationDate=2009-10-25
ContactName=haha@haha.haha
greenhopper.NumberOfUsers=-1
greenhopper.LicenseTypeName=COMMERCIAL
ContactEMail=haha@haha.haha
Evaluation=false
greenhopper.LicenseEdition=ENTERPRISE
licenseVersion=2
MaintenanceExpiryDate=2010-10-24
Organisation=haha
greenhopper.active=true
LicenseID=LID
LicenseExpiryDate=2010-10-24
PurchaseDate=2009-10-25

ps:本来想写个注册机,但 jira 从 4.0 开始更新了注册的公钥存放位置,原来是文件的,一般叫 leaf.key,现在直接写在程序里了,没办法,只能替换 class,这样写注册机就没什么意义了,所以就硬破解了一下。

posted @ 2009-11-01 21:52 哈哈的日子 阅读(8982) | 评论 (19)编辑 收藏

xsl 里增加

   function valueOf(context, elem) {
    return tools.valueOf(context, elem);
   }
代码里增加


 public String valueOf(XSLProcessorContext context, ElemExtensionCall elem) {
  String value = elem.getAttribute("select");
  String maxStr = elem.getAttribute("max");
  try {
   value = executeExpression(context, elem, value);
  } catch (TransformerException e) {
  }
  if (isNotBlank(maxStr)) {
   try {
    int max = Integer.parseInt(maxStr);
    value = shortStr(value, max);
   } finally {
   }
  }
  return value;
 }

 private String executeExpression(XSLProcessorContext context, ElemExtensionCall elem, String value)
   throws TransformerException {
  XPathContext xctxt = context.getTransformer().getXPathContext();
  XPath path = new XPath(value, elem, xctxt.getNamespaceContext(), XPath.SELECT);
  XObject data = path.execute(xctxt, context.getContextNode(), elem);
  if (data != null)
   value = data.xstr().toString();
  return value == null ? "" : value;
 }











参考了下面的文档






[prev in list] [next in list] [prev in thread] [next in thread]
List: xalan-j-users Subject: Re: Extension element with subelements From: John Gentilin <gentijo () eyecatching ! com> Date: 2007-09-07 21:48:37 Message-ID: 46E1C735.2080504 () eyecatching ! com [Download message RAW] Oops... this might be what you are after instead... executeChildTemplatesToXML or ToString or ToXMLString may be what you are after.. /** * A repository for common functions that can be used but the extension * functions and extension elements. * * * Title: Base Functions * Copyright: Copyright (c) 2005 * Company: Eye Catching Solutions Inc. * @version 1.0 * @author John Gentilin */ public class BaseFunctions { private static Category m_Log = Category.getInstance("RapidXSL.Interface"); private static DocumentBuilderFactory m_dfactory = null; private static DocumentBuilder m_docBuilder = null; /** * @param context * @param elem * @throws TransformerException */ protected void executeChildTemplates( XSLProcessorContext context, ElemExtensionCall elem ) throws TransformerException { TransformerImpl transf = context.getTransformer(); transf.executeChildTemplates(elem, context.getContextNode(), context.getMode(), transf.getResultTreeHandler()); } /** * @param context * @param elem * @throws TransformerException */ protected Document executeChildTemplatesToXML(Document doc, XSLProcessorContext context, ElemExtensionCall elem ) throws XMLServerException { DOMBuilder builder = null; TransformerImpl transformer = context.getTransformer(); try { builder = new DOMBuilder(doc); transformer.executeChildTemplates(elem, context.getContextNode(), context.getMode(), builder); } catch (Exception e) { throw new XMLServerException("RXSL_IFACE", "XSL Interface Error - " + e.getLocalizedMessage()); } return doc; } /** * @param context * @param elem * @throws TransformerException */ protected String executeChildTemplatesToString(XSLProcessorContext context, ElemExtensionCall elem ) throws XMLServerException { TransformerImpl transformer = context.getTransformer(); try { TextSerializationHandler handler = new TextSerializationHandler(); transformer.executeChildTemplates(elem, context.getContextNode(), context.getMode(), handler); return handler.toString(); } catch (Exception e) { throw new XMLServerException("RXSL_IFACE", "XSL Interface Error - " + e.getLocalizedMessage()); } } protected String executeChildTemplatestoXMLString(XSLProcessorContext context, ElemExtensionCall elem) throws TransformerException, SAXException { try { TransformerImpl transformer = context.getTransformer(); // This should be worked on so that the output format can be // defined by a first child of the redirect element. OutputProperties format = transformer.getOutputFormat(); Properties prop = format.getProperties(); format.setProperty("indent","no"); format.setProperty("{http://xml.apache.org/xalan}indent-amount","0"); ByteArrayOutputStream ostream = new ByteArrayOutputStream(); SerializationHandler serializer = transformer.createSerializationHandler( new StreamResult(ostream), format); serializer.startDocument(); transformer.executeChildTemplates(elem, context.getContextNode(), context.getMode(), serializer); serializer.flushPending(); serializer.endDocument(); return ostream.toString("ISO-8859-1"); } catch (UnsupportedEncodingException e) { m_Log.fatal("Error Encoding Bytes from XML - " + e.getLocalizedMessage()); return new String(); } } /** * Get the Node Value of a Stylesheet Element. This will be used to collect * the data value when populating a Control..... * * @return */ protected String getNodeValue( ElemExtensionCall elem ) { Node child = elem.getFirstChild(); if (child != null) { return child.getNodeValue(); } return null; } /** * Resolve the Attribute Selection for the fixed attribute "select" * * @return * @throws TransformerException */ protected String getStringValueFromSelectExpr(XSLProcessorContext context, ElemExtensionCall elem ) throws TransformerException { return getStringValueFromAttribute("select", context, elem); } /** * Find the Attribute named "attrib" and convert that to an XPath statement * that can be executed. * * Return null if the Attribute did not exist. * * @param attrib * @return * @throws TransformerException */ protected static XPath getAttributeExpr( String attrib, XSLProcessorContext context, ElemExtensionCall elem ) throws TransformerException { String expr = elem.getAttribute (attrib, context.getContextNode(), context.getTransformer()); if(null != expr) { org.apache.xpath.XPathContext xctxt = context.getTransformer().getXPathContext(); return new XPath( expr, elem, xctxt.getNamespaceContext(), XPath.SELECT); } return null; } /** * * Get the value of an Attribute. It will first try to treat the attribute as an XPath * if that fails then just return the attribute value itself. * * @param attrName * @param context * @param elem * @return */ protected String getStringValueFromAttribute( String attrName, XSLProcessorContext context, ElemExtensionCall elem ) { XPath path; String value = null; try { path = getAttributeExpr(attrName, context, elem); if (path != null) { XObject data = executeXPath(path, context, elem); if (data != null) value = data.xstr().toString(); } } catch (TransformerException e) { value = elem.getAttribute(attrName); } if (value == null) value = ""; return value; } /** * A helper function to execute an XPath Object. * * @param path * @return * @throws TransformerException */ protected static XObject executeXPath( XPath path, XSLProcessorContext context, ElemExtensionCall elem ) throws TransformerException { org.apache.xpath.XPathContext xctxt = context.getTransformer().getXPathContext(); return path.execute(xctxt, context.getContextNode(), elem); } protected Document getEmptyDocument() { initDocFactory(); return m_docBuilder.newDocument(); } protected static void initDocFactory() { if (m_dfactory != null) return; try { m_dfactory = DocumentBuilderFactory.newInstance(); m_docBuilder = m_dfactory.newDocumentBuilder(); } catch (Exception e) { m_Log.fatal("RapidXSL Interface, failure to init XML Subsystem - " + e.getLocalizedMessage()); } } } Cynepnaxa wrote: > Hi, everybody! > I start to write simple extension element, but a problem occurs. I want to > access extension element's subelements in java+xalan. My xsl contains > following block of code: > <my-ext:request> > <body><xsl:value-of select="$body"/></body> > <contentType>text/html</contentType> > <metaData><![CDATA[<?xml version="1.0" encoding="utf-8"?>]]><metaData> > <xsl:value-of select="$metaData"/> > </metaData> > </metaData> > </my-ext:request> > In extension element Java-method i have "XSLProcessorContext context" and > "ElemExtensionCall elem". I can get contentType by calling for example > "elem.getFirstChild().getNextSibling().getFirstChild().getTextContent()", > but i want to access subelements by tag name(for example, by > elem.getElementsByTagName("metadata"), or XPath). I have no idea how to > access in java content of $body variable and xml - encapsulated $metaData. > All google - examples shining no light. Is simple xslt - subelements access > method exist? Big thanx for help. > P.S. Sorry for my English. I hope you understand me. > > [prev in list] [next in list] [prev in thread] [next in thread]


Configure | About | News | Donate | Add a list | Sponsors: 10EastKoreLogicTerra-InternationalChakpak.com
posted @ 2009-10-21 17:19 哈哈的日子 阅读(342) | 评论 (0)编辑 收藏

 要过生日了,看看老婆的准备。


早饭:
长寿面+荷包蛋 用小青菜做汤
 
 
 
 
 
中饭:
菜:
1可乐鸡
2鱼
3锅包肉
4黄瓜炒肉
5皮蛋
6花生
 
汤:蛋花汤
 
水果:榴莲 哈密瓜
 
饮料:可乐 啤酒
 
主食:饺子
 
主要地:生日蛋糕


重要的是生日礼物:
                苹果笔记本电脑还有一个蓝牙的无线苹果鼠标,无比的喜欢!!!
posted @ 2009-09-14 21:17 哈哈的日子 阅读(415) | 评论 (3)编辑 收藏
1. 先到 google code 上下载了 api 的 lib,当然是 java client,还有好多,比如 .net , php 什么的,没看。
2. 去看 google data api 的 getting start,但是,那个 ant 命令执行完,会出一些 captcha 的错误,没细看,估计是需要验证码了,api 没跟上。
3. 直接到 calendar 里面,把 CalendarFeedDemo执行了一下,注意,需要输入用户名和密码,用户名是 aaa@gmail.com 这样的,但发现这个不是我要的,我要的只是增加个 event 而已。
4. 执行 EventFeedDemo,jump这个才是我要的,简化了一下,只要能增加一个定时的 event,并有提醒,就够了。

代码在下面,连包名都没改:
 1 
 2 package sample.calendar;
 3 
 4 import java.io.IOException;
 5 import java.net.URL;
 6 import java.util.Calendar;
 7 import java.util.GregorianCalendar;
 8 import java.util.TimeZone;
 9 
10 import com.google.gdata.client.calendar.CalendarService;
11 import com.google.gdata.data.DateTime;
12 import com.google.gdata.data.PlainTextConstruct;
13 import com.google.gdata.data.calendar.CalendarEventEntry;
14 import com.google.gdata.data.extensions.Reminder;
15 import com.google.gdata.data.extensions.When;
16 import com.google.gdata.data.extensions.Reminder.Method;
17 import com.google.gdata.util.ServiceException;
18 
19 public class HahaCalendar {
20     private static URL eventFeedUrl;
21     private static final String METAFEED_URL_BASE = "http://www.google.com/calendar/feeds/";
22     private static final String EVENT_FEED_URL_SUFFIX = "/private/full";
23 
24     public static void main(String[] args) throws ServiceException, IOException {
25         String username = "username@gmail.com";
26         eventFeedUrl = new URL(METAFEED_URL_BASE + username + EVENT_FEED_URL_SUFFIX);
27         CalendarService myService = new CalendarService("haha calendar");
28         myService.setUserCredentials(username, "password");
29         CalendarEventEntry singleEvent = createSingleEvent(myService, "每天背单词""单词1,单词2");
30         System.out.println("Successfully created event " + singleEvent.getTitle().getPlainText());
31     }
32 
33     private static CalendarEventEntry createSingleEvent(CalendarService service, String eventTitle, String eventContent)
34             throws ServiceException, IOException {
35         CalendarEventEntry entry = new CalendarEventEntry();
36         entry.setTitle(new PlainTextConstruct(eventTitle));
37         entry.setContent(new PlainTextConstruct(eventContent));
38         Calendar calendar = new GregorianCalendar();
39         calendar.add(Calendar.MINUTE, 10);
40         DateTime startTime = new DateTime(calendar.getTime(), TimeZone.getDefault());
41         calendar.add(Calendar.MINUTE, 60);
42         DateTime endTime = new DateTime(calendar.getTime(), TimeZone.getDefault());
43         When eventTimes = new When();
44         eventTimes.setStartTime(startTime);
45         eventTimes.setEndTime(endTime);
46         entry.addTime(eventTimes);
47         addReminder(entry);
48         return service.insert(eventFeedUrl, entry);
49     }
50 
51     private static void addReminder(CalendarEventEntry myEntry) {
52         Reminder reminder = new Reminder();
53         reminder.setMinutes(5);
54         reminder.setMethod(Method.SMS);
55         myEntry.getReminder().add(reminder);
56     }
57 }
58 

想用的注意,把上面的用户名和密码改成自己的。


posted @ 2009-07-19 13:04 哈哈的日子 阅读(2281) | 评论 (4)编辑 收藏
1. 先到 oracle 网站上下载了 oracle 11g for linux 的 zip 包,并解压
2. 在用户下执行 ./runInstaller -jreLoc /usr/lib/jvm/java-6-sun/jre/(我指定了使用我安装的jdk,否则会中文乱码)
待续……
3. 一路下一步就可以了,但其中有一些依赖的东西需要先安装好,有
  a) libaio1
  b) rpm
  c) ksh
4. 要把一些命令 link 到 /usr/bin 目录下,其中 有
  a) awk -> /etc/alternatives/awk
  b) ksh -> /etc/alternatives/usr.bin.ksh
5. 还要把一个必须的目录建出来,就是 /opt,其实这个目录有可能已经存在了的。
6. 然后就一切 ok 了,但要启动 oracle 还需要增加一些环境变量,我一般就把这些放在 .bashrc 里了。
  a) export ORACLE_HOME=/home/haha/app/haha/product/11.1.0/db_1
  b) export ORACLE_SID=haha
  c) export NLS_LANG=american_america.utf8(这个是为了显示中文内容的时候不会乱码)
  d) export PATH=$PATH:/home/haha/app/haha/product/11.1.0/db_1/bin(这个就是为了方便,不设也行)
7. 测试安装是否成功,可以从下面的几个方面看
  a) 访问 https://domain:1158/em,看看能登录不。
  b) netstat -anop | grep 1521,看看 listener 启动没有


下次再启动 oracle 需要使用下面的命令
  a) 启动数据库实例: sqlplus "/as sysdba",然后 startup
  b) 启动 listener:lsnrctl start
  c) 启动 em:emctl start dbconsole(可选)


linux oracle 客户端可以使用 sql developer,在 oracle 网站上就能下载,其实这是无奈之举,毕竟 plsqldev 无法在 linux 下使用。

posted @ 2009-07-12 18:23 哈哈的日子 阅读(3291) | 评论 (5)编辑 收藏
找到一篇非常不错的文章,晚上回来操作一下。
http://zeroliu.blogdriver.com/zeroliu/1208212.html

应用场景:
玩个游戏文字mud,客户端使用mushclient,支持使用 lua 脚本来写 robot,以便自动练功。
但由于多个 id 之间 share 数据比较困难,导致地图数据在每个 id 都要加载一次,数量大了之后,内存用很多,而且还会出现莫明其妙的内存泄漏问题。所以想改用 java 实现(因为我不会用 c 实现)

最终选择了使用 lua 调用 c,然后调用 java
posted @ 2008-10-19 09:49 哈哈的日子 阅读(209) | 评论 (0)编辑 收藏
安装了cdt 5.0,以前可以build的project死都不能build。
错误是
**** Internal Builder is used for build               ****
g++ -O0 -g3 -Wall -c -fmessage-length=0 -osrc\Test.o ..\src\Test.cpp
Internal Builder: Cannot run program "g++": ϵͳÕҲ»µ½ָ¶¨µ
Build error occurred, build is stopped
Time consumed: 0  ms. 


把 MinGW 的运行目录加到classpath里,把mingw32-make.exe复制一个,改名为make.exe。
在命令行下,一切都没有问题,就是在 eclipse里面不能用,郁闷了几天了。

google 了一下,参考了
http://www.eclipseworld.org/bbs/read-cec-tid-18540-page-e.html
这个帖子中参考了
http://74.53.91.20/bbs/read-cec-tid-17557-fpage-2.html

最终的方法是将
org.eclipse.cdt.core.win32_5.0.0.200809120802.jar
解压成目录org.eclipse.cdt.core.win32_5.0.0.200809120802,注意把原来的jar删除。

要人命了,这也能行,不看 code 估计这辈子都解决不了这个问题了。
posted @ 2008-10-18 20:36 哈哈的日子 阅读(1716) | 评论 (4)编辑 收藏
今天安装了 svn 服务端。
为什么写呢?因为和以前安装的不一样。
有什么不一样呢?
1、方便了很多
2、安装了 viewvc

为什么要安装 viewvc,而不是fisheye呢?
不是因为viewvc比fisheye好,就是因为刚才的第一点,方便。

以前安装 svn 都是直接下载一个 svn windows 版的压缩包,解压,bin目录加到path里,使用 sc 命令用 svnserve 建个服务,启动,完成。
其实这个步骤还是很简单的,就是在使用 sc 建 service 的时候,命令行有些复杂而已。
但这样只能使用 svn://xxx/xxx 来使用,而且不能在 web 上看到版本库,那么,就想了点儿办法,安装一个 apache 吧,然后根据文档,一顿猛配,相当的麻烦。好处就是,可以使用 http://xxx/xxx 来使用,而且可以在 web 上浏览到最新的版本内容,虽然 web 功能土了点儿,但至少可以使用了。有的时候,深得这样不爽,就再加个 fisheye,我个人相当喜欢 fisheye 这个软件,以至于花了点儿时间破解了一下,需要的可以在 blog 上找一下,不是暴力的那种,是半注册的,可以跟着升级的那种。

但是,唯一,也是最大的问题,就是麻烦,安装这一套东西,那是相当的麻烦啊。

今天发现了一个方便的办法。

下载三个东西:
1、CollabNet Subversion Server
2、python
3、python win32api

安装过程和下载不太一样。
1、python
2、CollabNet Subversion Server
3、python win32api

2、3顺序无所谓的。

然后,就拥有了一个 svn + apache + viewvc 的环境了,相当的方便。
我喜欢。

呵呵…… ^_^
posted @ 2008-08-05 21:28 哈哈的日子 阅读(572) | 评论 (0)编辑 收藏
1、我想做什么
2、我该做什么
3、我要做多久
posted @ 2008-06-12 22:31 哈哈的日子 阅读(226) | 评论 (0)编辑 收藏
可以直接将 plugin 放到 dropins 目录下,即可自动完成安装。

dropins 目录支持下列形式的结构。

1、
 eclipse/
dropins/
org.eclipse.core.tools_1.4.0.200710121455.jar
org.eclipse.releng.tools_3.3.0.v20070412/
plugin.xml
tools.jar
... etc ...
...


2、

 eclipse/
dropins/
eclipse/
features/
plugins/


3、

 eclipse/
dropins/
emf/
eclipse/
features/
plugins/
gef/
eclipse/
features/
plugins/
... etc ...

4、 

 eclipse/
dropins/
emf.link

最后一种就相当原来的 links 目录,只要写
path = ...
就可以了。
posted @ 2008-04-13 13:02 哈哈的日子 阅读(4783) | 评论 (0)编辑 收藏
batch_size 即同时提交数据的数量,原本与事务并没有什么关系,但如果涉及到同一张表数据的同一种操作,可能就会发生微妙的关系了。

场景如下:
场景一:使用 spring 控制事务,将方法事务配置为 not_supported,向同一张表中插入两条数据,保证第一条数据正常插入,而第二条数据受约束(如唯一约束)插入失败。

预测结果:第一条数据成功,第二条失败。
实际结果:两条数据均失败。
原因:hibernate 将两条插入放到了同一个 batch 中,提交同时失败了。

场景二:同样使用 spring 控制事务,将方法事务配置为 not_supported,向第一张表中插入一条合法数据,成功,向第二张表插入数据,受约束(如唯一约束)插入失败。

预测结果:第一条数据成功,第二条失败。
实际结果:第一条数据成功,第二条失败。
原因:hibernate 分别插入数据并提交,在无事务的情况下,第一条成功,第二条失败。

那么如何让场景一得到预测结果呢,一个简单的解决方法,将 hibernate.jdbc.batch_size 设置为 1,即可。

所以,即使控制了事务,也未必能够得到期望的结果,还需要考虑某些特殊的场景带来的影响。
posted @ 2008-03-06 14:18 哈哈的日子 阅读(1807) | 评论 (2)编辑 收藏
CenquaCrack.rar

Include Clover(2.0.3), Fisheye(1.4) and Crucible(1.2) - Crack by Sea Chang
Crack by Sea Chang - 2007.12.16

posted @ 2007-12-16 10:58 哈哈的日子 阅读(3482) | 评论 (19)编辑 收藏
最好的代码测试覆盖率查看软件。

CloverCrack.rar


Crack By Sea Chang

2007.11.30
posted @ 2007-11-30 21:45 哈哈的日子 阅读(2056) | 评论 (5)编辑 收藏

在学习 lua 的时候,看到了一个生成序列的一个递归算法,比起我以前的算法,要好得很多,学到了。^_^

package com.sea.pc;
public class Permgen {
 
public static void main(String[] args) {
  Permgen permgen 
= new Permgen();
  String[] ss 
= { "a""b""c" };
  permgen.permgen(ss, 
3);
 }
 
public void permgen(Object[] os, int n) {
  
if (n == 0) {
   
for (Object obj : os) {
    System.out.print(obj 
+ "\t");
   }
   System.out.println();
  } 
else {
   
for (int i = 0; i < n; i++) {
    Object t 
= os[i];
    os[i] 
= os[n - 1];
    os[n 
- 1= t;
    permgen(os, n 
- 1);
    os[n 
- 1= os[i];
    os[i] 
= t;
   }
  }
 }
}

 
 

  

posted @ 2007-10-21 15:18 哈哈的日子 阅读(444) | 评论 (2)编辑 收藏
最先遇到的问题是编译的问题,我觉得环境对于一个新手有致命的阻碍作用。可能有人会说,去  google 一下不就完了,可是,实际上新手可能根本就不知道要 google 什么,我学 c 很多次放弃基本上都是环境原因。

这次弄 c 主要是为了和 lua 脚本语言集成,其实用 java 也有得选,luajava 不失为一个好的选择。但是长久以来的小体积什么都不依赖就能运行的 c 程序(.exe)文件对我很有吸引力,因为发布 java 程序就意味着要伴随十几M的jre(哪位知道不用jre的,请务必教教在下),所以,这次决定了,学习 c!

IDE 嘛,就选择了 CDT,实在是太习惯eclipse了,然后就是用 Programing in lua 中copy个例子下来,编译。我靠,错误,想了想,把 lua 的那些头文件加进来,把 lib 目录也加进来,我靠,还是编译不过,崩溃了,放弃。

sigh,c编译是我永远的痛!

一天在公司里,突然想起有个同事是弄 c 的,问问他吧。他人好热情,给我讲了好多。终于明白了,不仅要把 lib 目录加进来,还要指定具体的 lib 文件名字,编译通过,迎来了全新的世界。

经过一段时间的乱弄,终于如愿的把程序编译成动态链接库(windows下的dll),引入到 lua 里,插曲:lua 原来引入动态链接库是全局的 function 叫 loadlib ,我靠,升级到 5.1 竟然改成了 package.loadlib,害我 google 了半天。不过其实 5.1 的 changelog 里是说了的,^_^

我的 lua 终于可以调 c api 了,快乐之情无法表达啊!

来,再做一个使用 c 访问网页的功能,找了半天,决定使用 wininet 库,跑到 ms 的 msdn 上一顿猛找啊,终于,皇天还不负我这个学c有心人,终于在一个 xx 角落里找到了 wininet 的 api,我,我终于可以用他连网了!

经过一会儿的奋斗,终于,从 http://localhost:8080/index.html 中,把自己 tomcat 的主页访问了出来,快乐的瞬间!
马上就发现这个程序有间歇性失忆,一会儿好用,一会儿不好用。共发生过以下几种失忆情况:

1、把代码 copy 到一个函数中,在 main 调用这个函数,程序运行失败!
2、删除了调试用的 printf 方法,程序运行失败!
3、夸张,这个是最夸张的!把 BOOL b = HttpSendRequest(req, NULL, 0, NULL, 0); 前面的 BOOL b = 去掉,只留下 HttpSendRequest(req, NULL, 0, NULL, 0);,失败!!!!!!!这样居然都失败!加上去就好好的运行。精神一度处于崩溃的边缘,眼睛里的血丝一度超过狼人!

左思右想,左改右改,死都不行!

一个声音高叫着:放弃吧,玩会游戏!

放弃了,md,再也不被 c 玩了,俺要玩俺的 java 去,下载 luajava 去,不理你了!
临行前,我恋恋不舍地看了一眼俺的c代码,我靠,突然发现这 xx 代码居然有个问题,这真是豁然开朗啊。

原来是。。。(省略一万字)

LPDWORD n; // LPDWORD 是个 unsigned long *

没初始化!
天啊,这点问题就让我找了这么久啊,我改。
DWORD a = 0;
LPDWORD n = &a;

一切正常。

世界终于清静了……
posted @ 2007-09-06 21:50 哈哈的日子 阅读(1137) | 评论 (3)编辑 收藏

The girl who is standing there is my sister. 站在那里的女孩是我姐姐。

The dog is dead.
The dog is picked by me yestday.

The dog which he give me yestday is dead.

posted @ 2007-08-10 19:19 哈哈的日子 阅读(216) | 评论 (0)编辑 收藏
He is critical of everything I wear.
他对我穿什么都挑剔。

critically 挑剔地

Many people pretend that they understand modern art.
很多人假装懂现在艺术。

pattern 图案,典范

set a pattern 树立模范

draw curtain 拉窗帘
pull curtain 拨开窗帘

curtain 舞台上的幕

rise curtain 升幕布

material 材料,物质上的,非精神上的
food is a material need.

appreciate 鉴赏,感激
I don't appreciate the wine.
appreciate your help 感谢你的帮助

appreciation 赏识

notice v. 注意到 n. 通知

notice sb do/doing

noticable 引人注意的

The damage to my car is very noticable.

whether 是否

whether ... or not.
whether or not

hang 悬挂

The murderer was hanged. 那个杀人犯已经被绞死了。

upside down 上下颠倒

for a moment 持续了一会儿
for the moment 现在,目前
in a moment 不久,即将
at a moment 此时此刻
at the moment 在那个时候 = then

flat 瘪了,平坦的,一套住房

block n. 大块,硬的,n. 大楼 v. 阻塞

a block of flats 一栋公寓楼

blocking the pipe 阻塞管子

put up tent 搭帐篷

land <-> the sea
earth <-> the sun
ground <-> sky
soil 土壤
native soil 家乡
field
in field 在田地里
creep 爬行
the crept out of the tent 他们爬出了帐篷
sleeping bag
comfortable 舒适的
comfort 安慰
soundly 香甜地
sound adj. 香甜的 n. 声音 v. 听起来 adj. 身体无恙的,健康的

I had a sound sleep last night.
I slept soundly.

形容想法 sound ,指明智,有判断力的

sound advice 很好的建议
leap 跳跃
I lept over a low wall.
人高矮用 tall,short
声音,价格 hight,low

heavily

stream 小溪

form 形成 n. 形状,外貌
graceful 优美的
a graceful form of a women 一个女人优美的形态

wind 蜿蜒

no sooner ... that ...  =  as soon as ,一 ... 就 ... ,强调时间间隔很短


posted @ 2007-08-09 19:50 哈哈的日子 阅读(368) | 评论 (0)编辑 收藏

Maven Phases

Although hardly a comprehensive list, these are the most common default lifecycle phases executed.

  • validate: validate the project is correct and all necessary information is available
  • compile: compile the source code of the project
  • test: test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
  • package: take the compiled code and package it in its distributable format, such as a JAR.
  • integration-test: process and deploy the package if necessary into an environment where integration tests can be run
  • verify: run any checks to verify the package is valid and meets quality criteria
  • install: install the package into the local repository, for use as a dependency in other projects locally
  • deploy: done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects.

There are two other Maven lifecycles of note beyond the default list above. They are

  • clean: cleans up artifacts created by prior builds
  • site: generates site documentation for this project

翻译内容,摘自 IBM

生命周期

在Maven2中有了明确的生命周期概念,而且都提供与之对应的命令,使得项目构建更加清晰明了。主要的生命周期阶段:

  • validate,验证工程是否正确,所有需要的资源是否可用。
  • compile,编译项目的源代码。
  • test-compile,编译项目测试代码。
  • test,使用已编译的测试代码,测试已编译的源代码。
  • package,已发布的格式,如jar,将已编译的源代码打包。
  • integration-test,在集成测试可以运行的环境中处理和发布包。
  • verify,运行任何检查,验证包是否有效且达到质量标准。
  • install,把包安装在本地的repository中,可以被其他工程作为依赖来使用
  • deploy,在整合或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其他的开发者或者工程可以共享。
  • generate-sources,产生应用需要的任何额外的源代码,如xdoclet。
posted @ 2007-08-08 16:30 哈哈的日子 阅读(526) | 评论 (0)编辑 收藏
最近一个朋友做猜数字游戏的解法,我也尝试了一下,在做数据生成器的时候,就希望做一个类型无关的,其实这个问题在去迅雷面试的时候就被问到,不过当时想都没想就放弃了,虽然面试当天回来的时候,完成了一下,但结果还是差强人意。所以想借这个机会弄一下。

在记录一条数据(Record)的时候,我本来使用了 List 实例化成 ArrayList,然后开始算,不过借助 JProbe 看了一下,List.size() 和 List.get(i) 这两个方法因为调用次数太多而占用了大部分的时间,所以第一想法是改成数组。

当我 new Record 的时候,使用的是 list ,自然想把这个 List<T> 转换成数组 T[] ,不过非常麻烦的是 list.toArray(T[]) 中的 T[] 不知道如何得到,不知道如何弄到 T[] 的实例,new T[list.size()] 是没办法的。

第一个反应是从 list 或是 List<T> 定义的 class 中得到成员的类型,然后使用 Arrays.newInstance 来创建一个,我花了好长的时间都没有能够得到,后来和同事聊天时,猜测是不是编译完的 class 文件中根本就没有类型的信息,不过当时没能确定。

晚上接着猜数字的时候,旧事重提,google 了一下,看到了一个非常好的文章。
http://www.ibm.com/developerworks/cn/java/j-jtp01255.html
将泛型说明的非常清楚,其中一句是这样的“Java 语言中的泛型基本上完全在编译器中实现,由编译器执行类型检查和类型推断,然后生成普通的非泛型的字节码。这种实现技术称为擦除(erasure)(编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其清除)”。

验证了我的想法,在 class 文件中,根本就没有泛型的信息。

实际上,声明一个泛型数据的方法是

T[] array = (T[])new Object[length];

这样,问题解决,对 Java 泛型的理解增加了一些。
posted @ 2007-08-08 00:39 哈哈的日子 阅读(3882) | 评论 (3)编辑 收藏
newline(换行符) \n
horizontal tab(水平制表符) \t
vertical tab(垂直制表符) \v
backspace(退格键) \b
carriage return (回车键) \r
formfeed (进纸键) \f
alert (beel) (响铃符) \a
backslash (反斜杠键) \\
question mark (问号) \?
single quote (单引号) \'
double quote (双引号) \"
posted @ 2007-08-05 13:47 哈哈的日子 阅读(465) | 评论 (0)编辑 收藏
最近做 BEA Portal,头痛得要死。一大堆不明白的东西要弄。

今天刚刚进入点状态,弄了 Portal 的菜单,遍历当前 PagePresentionContext,把菜单打出来,顺便自定义一下菜单。
哈,全部出来了,所有的子内容都显示了出来,洋洋自得中~~~
随便点一个试试,哇靠,怎么只有当前 Context 下面的菜单了,其它的都不翼而飞了,完了,遭遇技术风险中…… fear

不过记得之前使用 multi level menu 的时候,无论点到哪个下面都可以显示全部的 context 啊,为什么现在就不行了呢。

嘎嘎,灵光一动(高手就这么产生了),想到是不是在 .menu 文件中配置的 singlelevel 和 multilevel 的原因?我自定义的菜单使用的是 singlelevel 的,改成 multilevel,虽然 menu 文件都一样。

嘎嘎嘎,成了!

头终于有了快乐的感觉。

真是,用了 BEA Portal ,嘿,真对得起咱这个头!

^_^

调侃之作
posted @ 2007-07-23 18:01 哈哈的日子 阅读(421) | 评论 (0)编辑 收藏
将 OID 相应的包放到 %WL_HOME%\server\lib\mbeantypes 目录下就可以了。
posted @ 2007-07-18 17:58 哈哈的日子 阅读(510) | 评论 (1)编辑 收藏
1、比较方便的办法
在 log4j 的配置中加上

 <logger name="org.hibernate.type" additivity="false">
  <level value="debug" />
  <appender-ref ref="CONSOLE" />
  <appender-ref ref="FILE" />
 </logger>
 <logger name="org.hibernate.sql" additivity="false">
  <level value="debug" />
  <appender-ref ref="CONSOLE" />
  <appender-ref ref="FILE" />
 </logger>
其中 org.hibernate.sql 不知道有什么用。

2、使用 p6spy 来显示 sql,配合 sqlprofile 比较方便,还可以使用 irontracksql。

sqlprofile 和 irontracksql 在得到 sql 的机制有些差别。

sqlprofile 是通过配置 log4j 的 socket append ,将 log 输出到 sqlprofile 的监听端口去。这样在调试程序的时候,只要先启动好 sqlprofile,就能得到 sql 了。

irontracksql 是在应用中监听一个端口,随应用启动,irontracksql 启动是连接到那个端口去得到 sql,所以要先启动用户,再让 irontracksql 连过去。

猜测:irontracksql 性能会好一些,而且不想看 sql 可以断下来。sqlprofile 则不行。但在调试程序的时候 sqlprofile 明显方便很多。
posted @ 2007-07-18 11:29 哈哈的日子 阅读(4084) | 评论 (3)编辑 收藏
找了半天,才找到 google 输入法的词库文件位置,在 c:\windows\system32\GooglePinyin.ime
然后,找输入法生成器,一样,找了半天,找到,在 C:\Program Files\Windows NT\Accessories\Imegen.exe

希望下次不要再找这么久了。
posted @ 2007-07-04 14:14 哈哈的日子 阅读(491) | 评论 (1)编辑 收藏

使用的目的就是为了抓取一下 http 包,看看服务端的重定向目的。
下载了 Ethereal 0.99.0 这个东西以前在开发协议栈的时候用过,非常不错的软件。
安装,并且在安装过程中,提示要安装 WinCap ,这个是要安装的,应该是抓包需要的插件吧。
打开软件,选择:capture->options,在 interface 中选择一个网卡,并且在 capture filter 中增加一个过滤器,就可以了。
常用的过滤器就是 host + ip ,可以抓与指定 ip 通信的包,是我最常用的。
然后 start ,就开始抓包了。
抓到了包之后,是二进制的,在包上面点击右键选择 Follow TCP Stream ,就可以看到 http 包了。
里面红色的是发出的请求,篮色的是响应。
ok,大功告成。

posted @ 2007-06-18 15:58 哈哈的日子 阅读(17404) | 评论 (7)编辑 收藏
今天刚好接到新的任务,改版现在的 weblogic portal,行!弄新东西我最在行了,说来就来,下载了一堆文档,看来看去。
看得两分熟了,准备弄个例子试试,weblogic workshop 还真是不错,轻松就建出来了一个 portal 项目,然后在其中建一个web项目,build 一下吧,惨!出错了,明明在 classpath 中配置了 portal 的包,居然现在告诉我 build 不过。
幸好同事告诉我,有命令行的办法 build ,那试一下,至少可以在 build 脚本中找出原因嘛,找到 wlwBuild.bat 瞄了一眼,我靠,居然是直接调用的 wls-ide.jar 来 build 的,看来在脚本里找到原因也比较难了。
突然发现,ide 中有一项功能,可以生成 ant 的 build 脚本,好,生成一个,用 ant build。
眼看着这几个依赖包就在 classpath 里,就非说找不到!去死吧,郁闷死我了,在同事的机器上一点儿问题都没有!
是不是 Program Files 的问题?改一下,改成 Progra~1,居然行了!疯了,弄来弄去,原来是因为我把 weblogic 安装到了 Program Files 目录下的原因,sigh,怕怕,windows 的路径问题真是苦恼啊。
索性删掉,重新安装到根目录下。
问题解决,快乐!
posted @ 2007-06-18 15:31 哈哈的日子 阅读(336) | 评论 (0)编辑 收藏

概括的说,就是回到过去,把现在不存在的东西删除了。
步骤:
1、删除一个目录 d,目录中有文件 f,提交。(状态:HEAD中已经没有 d 和 f 了)
2、switch 到前一个版本,就是没删除目录 d 的版本。
3、删除文件 f,提交,这时没有任何的提示,个人理解就是将 HEAD 中的 f 又删除了一次,而与当前状态不冲突,正常 merge。

4、Update 一下,更新到最初的版本 + 2,d 是不存在的,f 同样不存在。
posted @ 2007-06-04 16:30 哈哈的日子 阅读(288) | 评论 (1)编辑 收藏

今天看了一下基于 jquery 的 calendar js 控件,效果还不错,而且改变了我对 calendar 控件的恐惧感。

在 jquery 的官方网站上提供了两个 calendar 控件(http://docs.jquery.com/Plugins),Calendar (Pop-up Calendar)和DateSelector ,分别试用了一下。

先试了一下 DateSelector,这个出现的比较早,会比较成熟一些。
简单的下载了datePicker.js和styles.css (jquery当然也要下载)
写了个测试页面,成功了!非常非常简单好用,没什么依赖。
测试页面内容如下:
<html>
    
<head>
        
<link rel="stylesheet" type="text/css" href="styles.css" title="default" media="screen" />
        
<script type="text/javascript" src="jquery-latest.pack.js"></script>
        
<script type="text/javascript" src="datePicker.js"></script>
<script type="text/javascript">
$(document).ready(init);
function init() {
    $('input#date1').datePicker();
    $('input#date2').datePicker({startDate:'
2006-11-02', endDate:'2006-11-13'});
}
</script>
    
</head>
    
<body>
    
<form action="#" method="post">
        
<div class="demo-holder">
            
<label for="date1">Date 1</label>
            
<input type="text" class="date-picker" name="date1" id="date1" />
        
</div>
        
<div class="demo-holder">
            
<label for="date2">Date 2</label>
            
<input type="text" class="date-picker" name="date2" id="date2" />
        
</div>
        
<div style="float: left; margin: 2em 1em 1em;">
            
<select><option>Select doesn't display through calendar even in IE!</option></select>
        
</div>
    
</form>
    
</body>
</html>

 
静态页面如图,点击日历图标。

还能挡住 select 框,真是 cool 毕了!
不过,这是讨厌的英文,把那弄成中文吧,^_^
在 init 中加上


    $.datePicker.setDateFormat('ymd', '-');
    
    $.datePicker.setLanguageStrings(
        ['日', '一', '二', '三', '四', '五', '六'],
        ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
        {p:'上月', n:'下月', c:'关闭', b:'请选择'}
    );


一切 ok,顺利变成中文

不过这个控件有个很大的问题,就是不能选择年份,如果这个控件是让人选生日的,那可就麻烦了。

下次再介绍另一个吧,出去吃饭了。

posted @ 2007-06-02 11:09 哈哈的日子 阅读(6581) | 评论 (0)编辑 收藏
可以通过 linux 命令行的方式访问 url ,在有防火墙,不能使用 http 访问的时候,非常的有用。
posted @ 2007-05-31 16:42 哈哈的日子 阅读(285) | 评论 (0)编辑 收藏

今天测试的时候遇到一个问题,在本机运行好好的,但部署在远程的时候,突然出现奇怪的问题。

查了一下原因,是由于我们自已做的 Status 类是在 java 1.4 下自己制作的 Enum,判断的时候使用了 == 号,在一个 jvm 下,没有任何问题,但从远程传回来的 status 使用 == 显示是一定不可能是 true 了。

从而出现了上面的问题。

不知道 java 5 的 enum 会不会有这个问题。

singleton 的 equals 应该会同样有这个问题。

posted @ 2007-05-31 11:15 哈哈的日子 阅读(365) | 评论 (0)编辑 收藏

我常用的 JDK 自带工具有几个,最常用的 javac、javadoc、java、jar 就不说了

1、native2ascii,不说也知道,是作国际化的时候,将中文 unicode 转成 ascii 的,有一个有用的参数 -reverse ,将 ascii 转回来。
2、javap,将 class 反编译成 Java bytecodes,类似于 jvm 上的汇编。
3、javah,将带有 native 方法的 java 文件编译出 c/c++ 的头文件。
4、jdb,java debug 工具
5、jps,查看 jvm 进程状态信息
6、keytool,生成 keystore 文件

还有几个 rmi 和 applet 的工具,平时很少用到。

posted @ 2007-05-24 11:22 哈哈的日子 阅读(1008) | 评论 (1)编辑 收藏
     摘要: Oracle使用的hints调整机制一直很复杂,Oracle Technical Network对使用hints调整Oracle SQL的过程有很好的全面评述。根据对10g数据库的介绍,可使用更多新的optimizer hints来控制优化行为。现在让我们迅速了解一下这些强大的新hints:   阅读全文
posted @ 2007-05-23 13:44 哈哈的日子 阅读(237) | 评论 (0)编辑 收藏

在尝试服务器某个服务是否打开的时候,经常会使用 telnet 命令
telnet IP PORT
比如
要测试 192.168.1.101 的 1521 端口,就是 telnet 192.168.1.101 1521
如果成功,就黑屏,什么也不显示,这时候要退出,我以前总是关闭窗口的,实际上可以使用
CTRL+] ,然后进入命令行,quit ,退出。

屏幕显示如下



欢迎使用 Microsoft Telnet Client

Escape 字符是 'CTRL+]'


Microsoft Telnet> quit

posted @ 2007-05-21 09:39 哈哈的日子 阅读(930) | 评论 (0)编辑 收藏

因为需要在两台机器上同步一些数据,在网上找了一下,发现 cwRsync 是可以的。尝试了一下

1、安装
安装的过程很简单,也很顺利,从 cwRsync 网站上下载的 server and client ,都安装了一下,不过后来发现,其实是不需要安装 client 的,只要 server 就可以了,server 包括了 client 的功能。安装完 server 后,会在 service 中增加 Rsync 和 ssh 服务。

2、配置
配置了一下 rsyncd.conf

use chroot = false
strict modes = false
hosts allow = *
log file = rsyncd.log
pid file = rsyncd.pid

# Module definitions
# Remember cygwin naming conventions : c:\work becomes /cygwin/c/work
#
[test]
path = /cygdrive/c/work
read only = false
transfer logging = yes

只是将 [test] 中的 path 改成了我本机的备份目录

[test]
path = /cygdrive/d/backup
read only = false
transfer logging = yes

3、数据同步
因为只是最简单的数据同步,所以就不使用 ssh 了,直接启动 rsync 服务就可以了。然后按照 usage 上面教的。

rsync -av /cygdrive/d/test localhost::test

完成了数据的同步工作,一切顺利。顺便说一下,/cygdrive/d 是安装完 cwRsync ,会自动将系统上所有的盘 mount 成 /cygdrive/x ,x 表示盘符,小写的,并把安装目录 mount 成 / 了。

4、绿色安装
我将 cwRsync copy 到另一台机器上,试图不安装就启动 cwRsync server,启动过程比较正常,只要运行 rsync --config=$config_file --daemon --no-detach 就可以了,这里面的 $config_file 指的是前面配置的 rsyncd.conf ,路径要写成 /cygdrive/d 这样的形式。

5、安装成服务
程序包中带了 cygwin 的 cygrunsrv ,可以通过这个命令将 rsync server 做成 windows 服务,但我试了一下,路径中有空格没有成功,命令是这样的

cygrunsrv.exe -I "Rsync" -p /cygdrive/d/cwRsyncServer/bin/rsync.exe -a "--config=/cygdrive/d/cwRsyncServer/rsyncd.conf --daemon --no-detach" -f "Rsync"

也很顺利的安装成服务了。

6、问题二
惨的是当我在第二台机器上同步数据的时候,权限却成了问题,同步过去的文件(目录)所有者是 SYSTEM,不是我,而且我没有访问的权限,只有在安全中把自己加进来(我用管理员帐户),给自己权限,才能访问。

或者在 cygwin 下使用 chmod 给自己授权,和在 windows 中给自己授权没什么区别。

最后:

问题2已经解决
方法:只要把 cwRsyncServer 这个目录 mount 到 / ,就可以了,估计是 rsync 同步数据的时候,会调用 /bin/chmod 来授权,如果是安装版的,这个目录会在安装的时候 mount 好。 (好象不是这个问题了)
posted @ 2007-05-20 14:36 哈哈的日子 阅读(13838) | 评论 (2)编辑 收藏

PMD 在 check 的时候,告诉我不要使用 new Interger(int i) 方法,要使用 Integer.valueOf(int i) 方法,如我所料,Integer 将-128~127 之间的 Interger cache 了,好啊,就用这个方法了。

后来悲惨的发现,JDK 5.0 才有这个方法 1.4 中是没有的。

苦在我开发的时候使用的是 JDK 5.0 ,部署在 1.4 的环境中,运行出错。

sigh,不小心被 PMD 撞了一下,它怎么也不告诉我不能用在 1.4 里啊。^_^

posted @ 2007-05-16 10:41 哈哈的日子 阅读(248) | 评论 (0)编辑 收藏

今天安装了一下 jira 的 svn acceptance,遇到了不少问题,实际上这些问题在之前学习 subversion hooks 的时候也有遇到,没记下,又弄一次,真是心烦得很。

1、hooks 中不能使用任何环境变量,svn acceptance 使用的是 pre-commit ,里面调用 python 的脚本。python 要写绝对路径,脚本 jira-client.py 也要写绝对路径,将 python 放在 path 中是没有用的。(这个在 svn acceptance 安装步骤中有,没有细看就安装,苦啊!)
2、pre-commit.bat 中路径或者使用老 DOS 的方式,如 @D:\Progra~1\Python25\python.exe" E:\SVN\repos\hooks\jira-client.py %1 %2。或者加上双引号,如@"D:\Program Files\Python25\python.exe" E:\SVN\repos\hooks\jira-client.py %1 %2
3、jira-client.py 中的路径也一样,或者使用 DOS,如 svnlookPath = 'D:\\Progra~1\\svn-win32-1.4.3\\bin\\svnlook.exe'。或者加上双引号,如svnlookPath = '"D:\\Program Files\\svn-win32-1.4.3\\bin\\svnlook.exe"'
4、hooks 中 exit 1 就是拒绝提交,exit 0 或什么都不写就是允许提交(windows 2000 中好象必须要 exit 0)
5、提交显示的错误信息在脚本中放在 system err 中,bat 文件只要 echo "haha" >&2 就可以了,python 中 print >> sys.stderr, 'haha' 就可以了
6、用户信息是通过 svnlook author 得到,注释信息是通过 svnlook log 得到

ps:subversion acceptance plugins 安装容易得很

posted @ 2007-05-14 11:14 哈哈的日子 阅读(1361) | 评论 (0)编辑 收藏
奇怪为什么 fisheye 一直都找不到 crack?难道是我寻找 crack 的水平有限?
崩溃了,自己弄了一个,再这么下去,都要成愤青了。

fisheye-1.3_20070424_crack.rar


copy 到 fisheye 安装目录,针对 fisheye 1.3 build 20070424 版本
posted @ 2007-05-13 22:53 哈哈的日子 阅读(2137) | 评论 (17)编辑 收藏
当数据库字段类型为 Number 时,IBatis 可以映射 Java 类型为 Integer,这样就一切没问题了。
不过这样比较麻烦,尤其是在使用 JDK 1.4 的时候。

如果选择映射为 int 类型,在数据库字段可以为 null 的情况下,需要设置 result 的 nullValue ,否则会出错。
posted @ 2007-04-30 16:17 哈哈的日子 阅读(2015) | 评论 (0)编辑 收藏
6.0 的 crack 不能用了,就自己弄了一个 7.0 的 crack ,如果有什么问题,给我留言。
http://www.blogjava.net/Files/haha1903/jp7.0-crack-20070530.rar
crack by Sea Chang
posted @ 2007-04-13 15:35 哈哈的日子 阅读(4587) | 评论 (21)编辑 收藏
教你如何注册msn.com的 邮箱


  在很久很久以前,我们注册的时候,可以选择注册hotmail.com还是msn.com的信箱。而现在微软把注册页面改掉了,进入hotmail.com只能注册以hotmail.com结尾的信箱了,而msn.com则找不到北了。而很多很多人还是很想注一个msn.com的,好记嘛,这么短小精悍。

  说了半天,到底怎么注册呢?简单!

  点这个链接https://accountservices.passport.net/reg.srf?ns=msn.com
就可以注册msn.com的信箱啦,哈哈哈~~~

  当然,如果你的电脑上装有msn browser的话,那用那个创建用户,就默认是msn.com的用户啦,不过好像那个玩儿在国内用的不多好像,我是两三年前用过的。



(提示:您必须在没用登陆 spaces或者 MSN hotmail油箱的前提下才可以申请 )

转自:http://my.opera.com/hotel/blog/show.dml/112387
posted @ 2007-04-11 20:13 哈哈的日子 阅读(9783) | 评论 (16)编辑 收藏
设置 Header Content-disposition 可以
如果设置为 attachment 就下载
如果设置为 inline 就直接打开

response.setContentType("application/msexcel");
加上
response.setHeader("Content-disposition", "attachment; filename=\"export.xls\"");

response.setHeader("Content-disposition", "inline; filename=\"export.xls\"");
posted @ 2007-02-06 16:47 哈哈的日子 阅读(1213) | 评论 (2)编辑 收藏
背景:
EasyMock 2 版本必须要 JDK5 才能使用 EasyMock 1.2 可以在 JDK 1.4 使用
也可以使用 Retrotranslator 将 EasyMock 2 版本改为 JDK 1.4 也可以使用的。
目前使用的是 EasyMock 2.2

准备:
先弄个接口 Haha 用来 Mock 的,两个方法
void haha(String s);
String hehe(String s);

开始 Mock:

静态导入 EasyMock
import static org.easymock.EasyMock.*;

然后
Haha haha=createMock(Haha.class);

无返回值的调用可以直接调用 Mock 方法

haha.haha("haha");

有返回值的可以

expect(haha.hehe("hehe")).andReturn("ok");

这样做完后

你要 replay(haha); 一下,表示录完 mock ,准备重放了。

就可以调用 haha.haha("haha") 了,同样的,调用 haha.hehe("hehe") 的返回值是 "ok"

全部调用完了,使用 verify(haha); 查看一下预期的调用是不是都调了,如果预期要调用一次,却没调,那就会 AssertionError 哦。

调用次数

上面这些都是默认调用一次,就相当于 expect(haha.hehe("hehe")).andReturn("ok").times(1); 或 expect(haha.hehe("hehe")).andReturn("ok").once();

如果想调用任意次,就 expect(haha.hehe("hehe")).andReturn("ok").anyTimes();

如果想最少调用一次,就 expect(haha.hehe("hehe")).andReturn("ok").atLeastOnce();

如果想调用 1 至 3 次,就 expect(haha.hehe("hehe")).andReturn("ok").times(1,3);

预期的结果

还可以 expect(haha.hehe("hehe")).andReturn("ok").andReturn("ok too").andThrow(new RuntimeException());

这样,第一次调用 haha.hehe("hehe") 时返回 "ok" ,第二次返回 "ok too",第三次调用就比较惨了,会抛出一个 RuntimeException,需要注意
的是,如果抛出的异常是 unchecked 的,就是 Runtime 的,就随便抛,如果是 checked 的,那就一定要抛这个方法定义的,否则会在 andThrow 这行出 IllegalArgumentException 。

终极解决办法还可以使用 andAnswer(IAnswer<T> answer) 传一个实现 IAnswer 接口的实例,这个接口只有一个方法
T answer() throws Throwable;
随便你返回什么,或是抛出什么异常。

调用顺序

不过如上面所说,haha.haha("haha") 与 haha.hehe("hehe") 是没有顺序的,将 createMock 改成 createStrictMock 或在 createMock 后面加一行 checkOrder(haha,true) 就可以了,这时,就一定要按照定义的顺序来调用了。

如果多个不同的 mock 也要保证顺序呢?那就不能使用 createMock 来创建这些 mock 了,因为每次 createMock 都会使用一个新的 IMocksControl 实例来单独控制这个 mock ,我们希望将多个 mock 用同一个 IMocksControl 控制,只需要

IMocksControl ctrl = createStrictControl();
Haha haha1= ctrl.createMock(Haha .class);
Haha haha2 = ctrl.createMock(Haha .class);

haha1.haha("haha1");
haha2.haha("haha2");

ctrl.replay();

就可以了

预期的参数

刚才 haha.haha("haha") 中的 "haha" 就是预期的参数,EasyMock 提供了很多预期参数的方法,比如 haha.haha(eq("haha")),与前面的方法功能完全一样
haha.haha((String)anyObject)  随便你传什么参数都没问题。
haha.haha(not(eq("haha"))) 这个只要不传 haha ,其它什么都成

同样可以自定义,只要调用     public static void reportMatcher(IArgumentMatcher matcher) 方法,将自定义的 IArgumentMatcher  传进去就可以了,这个接口有两个方法 boolean matches(Object argument)  和 void appendTo(StringBuffer buffer) 第一个方法的参数是调用实际传入的值,返回是否匹配,第二个方法是错误时向 buffer 中 append 错误信息。

将方法弄成 Stub

Stub 方法,我想应该就是随便调,爱怎么调就怎么调,返回的都是那个值,最后也不会验证到底调用了多少次。
如果想把一个方法弄成 Stub,无返回值的只要 asStub() 就是 expect(haha.haha("haha")).asStub() ,有返回值的就 andStubReturn() , andStubAnswer() 这样就可以了。

友好的Mock

我们使用 createMock 创建出来的 mock 对象,如果没有录过,调用这个方法都会出 AssertionError ,但如果使用 createNiceMock 就不会了,会返回 0 , null , false 这样的。
posted @ 2007-01-18 23:03 哈哈的日子 阅读(3046) | 评论 (5)编辑 收藏
RandomAccessFile file  =   new  RandomAccessFile(lockFile,  " rw " );
FileChannel channel 
=  file.getChannel();
FileLock tryLock 
=  channel.tryLock();
System.out.println(
" try lock ok  "   +  tryLock);

 

posted @ 2007-01-17 09:34 哈哈的日子 阅读(376) | 评论 (0)编辑 收藏
通过 XMLEncoder 可以将 JavaBean 序列化为 XML 形式

String file = "D:/temp/a.obj";
FileOutputStream fos 
= new FileOutputStream(file);
XMLEncoder encoder 
= new XMLEncoder(fos);
encoder.writeObject(a);
encoder.flush();
encoder.close();
fos.close();

序列化结果

<?xml version="1.0" encoding="UTF-8"?> 
<java version="1.4.2_08" class="java.beans.XMLDecoder"> 
 
<object class="A"> 
  
<void property="a"> 
   
<string>a</string> 
  
</void> 
  
<void property="b"> 
   
<object class="B"> 
    
<void property="e"> 
     
<string>e</string> 
    
</void> 
    
<void property="f"> 
     
<string>f</string> 
    
</void> 
   
</object> 
  
</void> 
  
<void property="c"> 
   
<string>c</string> 
  
</void> 
  
<void property="d"> 
   
<string>d</string> 
  
</void> 
 
</object> 
</java> 

通过 XMLDecoder 来将 XML 内容反序列化

String file = "D:/temp/a.obj";
FileInputStream fis 
= new FileInputStream(file);
XMLDecoder decoder 
= new XMLDecoder(fis);
A obj 
= (A) decoder.readObject();
fis.close();
System.out.println(obj);
posted @ 2007-01-16 17:27 哈哈的日子 阅读(700) | 评论 (0)编辑 收藏

起因:
 CruiseControl 与 JBoss 进程启动在固定的端口上,分别为 1099 和 8080 ,每次杀掉这两个进程的时候,就手动的执行 netstat -anp | grep 1099 和 netstat -anp | grep 8080 ,看到进程号,把他们杀掉,然后重启。

郁闷:
   但这样实在是太麻烦了,每天调试程序,重启 n 遍,看得我眼睛都花了。想办法自动杀死。

解决部分:
   想起了当初使用 awk 命令得到进程号,有了进程号,不就可以 kill -9 干掉他了!快乐,开始找 awk 命令用法,google 了一下,可以使用 netstat -anp | grep 1099 | gawk '{print substr($7,0,index($7,"/java")-1)}' 命令得到我想要的进程号,但说什么都不能对这个进程号运行 kill -9 ,再找!

解决问题:
   google 了一下,可以使用
   kill -9 `netstat -anp | grep 1099 | gawk '{print substr($7,0,index($7,"/java")-1)}'`
   果然好用!
   想起了使用过的 cd = `pwd` 原来 ` 号包围起来的命令可以执行,并放在相应位置上。

遗留问题:
   解决问题时,还 google 到,可以使用 netstat -anp | grep 1099 | gawk '{print substr($7,0,index($7,"/java")-1)}' | xargs -t -i kill -9 {} 来完成,需要了解管道符号的作用了。

posted @ 2007-01-16 10:18 哈哈的日子 阅读(415) | 评论 (0)编辑 收藏
svn 支持多个版本库的管理,可以将不同部门,不同项目组的代码库同时管理。

比如:

建立代码库根目录 repos

在其中建立 dept1 , dept2

repos
├─dept1
└─dept2

在 dept1 中建立 proj1 , proj2
在 dept2 中建立 proj3 , proj4

repos
├─dept1
│  ├─proj1
│  └─proj2
└─dept2
    ├─proj3
    └─proj4

然后运行

svnadmin create repos/dept1/proj1
svnadmin create repos/dept1/proj2
svnadmin create repos/dept2/proj3
svnadmin create repos/dept2/proj4

ps:实际上 proj1-proj4 可以不建,svnadmin create 会自动创建。

最后

svnserve -d -r repos 或使用 apache 就可以了

使用 svn://IP/dept1/proj1 或 http://IP/dept/proj1 可以访问
posted @ 2007-01-15 11:41 哈哈的日子 阅读(904) | 评论 (0)编辑 收藏
     摘要:   阅读全文
posted @ 2007-01-11 09:45 哈哈的日子 阅读(418) | 评论 (0)编辑 收藏
     摘要: 一.安装subversion
二.建立Repository(保存文档各个版本的数据库)
三.配置Repository
四.启动subversion服务器
五.客户端的使用   阅读全文
posted @ 2007-01-10 16:39 哈哈的日子 阅读(476) | 评论 (0)编辑 收藏

在 CruiseControl 中需要监测 ClearCase 中的变化,以便在变化时进行构建动作。

配置如下:

<modificationset quietperiod="5">
      <clearcase branch="dev_ct2.0" viewpath="D:\temp\cruisecontrol-bin-2.5 view\hello\group_ct\temp\test_project\hello" />
<modificationset>

CruiseControl 会每次调用

cleartool lshistory -branch dev_ct2.0 -r -nco -since 10-一月-2007.09:59:23 -fmt %u#~#%Nd#"~#%En#~#%Vn#~#%o#~#!%l#~#!%a#~#%Nc@#@#@#@#@#@#@#@#@#@#@#@

这个命令去监测 ClearCase 的变化

其中 dev_ct2.0 与配置的 branch 一致 -since 后面的时间保存在 listeners 中,默认一般为 status.txt 中


ps:有个问题就是这个命令不会监测没有在 View 中的文件的变化,也就是说,只在 ClearCase 根目录(因为其它目录中增加ClearCase认为目录变化,会监测到)中增加文件而没有更改文件,这个命令认为没有变化!

posted @ 2007-01-10 10:53 哈哈的日子 阅读(801) | 评论 (1)编辑 收藏

如果是 jar 包,在 Plugin 中配置

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <addMavenDescriptor>false</addMavenDescriptor>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>

如果是 war 包,在 Plugin 中配置

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <configuration>
        <archive>
          <addMavenDescriptor>false</addMavenDescriptor>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>

这个是在 maven-archiver 中设置的,可以查看代码。

 

posted @ 2007-01-04 20:37 哈哈的日子 阅读(4432) | 评论 (0)编辑 收藏

 public static String getSystemEnv(String name) {
  final String perfix = "env";
  Project project = new Project();
  Property property = new Property();
  property.setProject(project);
  property.setEnvironment(perfix);
  property.execute();
  return project.getProperty(perfix + "." + name);
 }

同样可以利用这个方法处理 properties 文件中 ${} 引用。

posted @ 2007-01-04 14:14 哈哈的日子 阅读(185) | 评论 (0)编辑 收藏
     摘要:   阅读全文
posted @ 2007-01-04 07:58 哈哈的日子 阅读(265) | 评论 (0)编辑 收藏
规格说明是必不可少的,我理解 Scrum 中的 UserStory 就是规格的一部分,但规格还包含了更多的东西,比如部分的需求,在华为的时候,需求是在规格之前的,分成不同的文档写成,不知道在 Scrum 中,是如何来描述需求的,是否是在 UserStory 中一并完成了?

进度表一章最大的感觉就是那段塞木块,要么增大盒子,要么丢掉木块。有了进度表,就给了你这样的选择。

目前的项目中,这两个东西都是没有的,一是导致进度延迟看不到,二是心里没底,人心惶惶。

盲点,软件做了这么久了,对这些最基本的东西还是没有深刻的理解,早该学习了,再玩就要饿死了。
posted @ 2007-01-01 09:12 哈哈的日子 阅读(157) | 评论 (0)编辑 收藏

有两种方法:
一、比较传统,运行完 Test 后,在 JUnit View 中选择一个 TestCase ,右键,Run or Debug 就可以了。
二、在 OutLine View 中选择一个方法(在 Test 类中),右键,Run As->JUnit Test ,就可以了,这个方法可以将所有的方法做为 TestCase 运行,但要注意的是要 public and 无参数,不检查返回值。

posted @ 2006-12-29 09:13 哈哈的日子 阅读(2836) | 评论 (1)编辑 收藏

XFire 的服务中有两类参数:

一、Project ,包含 Views ,即 View 的数组
二、View ,包含一个 Project 引用,即本身所在的 Project

本地操作经测试没有任何问题。

封装成 XFire 的 webservice ,同样的测试用例,产生 StackOver Error。

没有解决,将 View 中 Project 引用改为对 Project Key(ID)的引用。

期待根本解决问题。

不知哪位大侠遇到同样问题。

posted @ 2006-12-28 08:06 哈哈的日子 阅读(402) | 评论 (0)编辑 收藏

本来写好了一个 XFire 的 service ,但一时习惯,误将 impl 类做成 singleton 的了,害得没法用,所以想到测试,看了 ss 上面的测试方法,对比之下,觉得 xfire.local 的方式比较好。回头试一下,补充进来。

posted @ 2006-12-27 08:04 哈哈的日子 阅读(213) | 评论 (0)编辑 收藏
1.删除C:\Documents and Settings\All User\Application Data\Windows Genuine Advantage\data\data.dat 文件。
2.禁用网络链接.因为ie7安装的时候会自动链接网络。
3.安装 IE7 大功告成!
posted @ 2006-12-24 21:11 哈哈的日子 阅读(164) | 评论 (0)编辑 收藏
再一次同步 svn 库,又遇到了上次的问题,记下来,不要再次了。

一、文件系统的 url 是 file:///d:/... (三个正斜线)这样的,又写错,写成了 file://(两个正斜线)
二、增加一个 hook -pre-revprop-change ,要在目标库中的 hook 目录增加 pre-revprop-change.bat 就可以了

命令是 svnsync sync file:///d:/work/svn/repos 这样子

一切 OK !

如果需要同步备份,只要在 hook 中写

echo off
set SVN_HOME="D:\Subversion"
%SVN_HOME%\bin\svnsync sync --non-interactive svn://localhost/project2

就可以了
posted @ 2006-12-21 17:23 哈哈的日子 阅读(1176) | 评论 (0)编辑 收藏
Maven 会每天检查一次 SNAPSHOT 包的更新,也可以通过配置

...
<repository>
...
   <releases>
      <updatePolicy>interval:60</updatePolicy>
   </releases>
</repository>

来定义更新时间,如果需要强制更新,需要在 command line 加 -U 选项。
posted @ 2006-12-21 14:52 哈哈的日子 阅读(1032) | 评论 (0)编辑 收藏

在 web.xml 中修改 mime-mapping 就可以了,比如,增加 ear 文件类型为 application/java-archive ,只要在 web.xml 中增加

    <mime-mapping>
        <extension>ear</extension>
        <mime-type>application/java-archive</mime-type>
    </mime-mapping>

就可以了。

posted @ 2006-12-20 15:27 哈哈的日子 阅读(173) | 评论 (0)编辑 收藏
在启动后的 Server 上单击右键->Monitoring->Monitor port 8080(http) 就可以了。
然后在Server 上单击右键->Properties 里面看到映射的端口号,访问那个端口,就可以在 TCP/IP Monitor 中看到实际的包数据了。
posted @ 2006-12-20 15:24 哈哈的日子 阅读(4173) | 评论 (5)编辑 收藏

可以设置的最大JVM内存和JVM版本以及操作系统版本有关,一般Windows下1200-1500M左右,Linux下最大能到2600M;
具体可以使用命令 java -XmxXXXXM -version 来进行测试(如:java -Xmx1024M -version),然后逐渐的增大XXXX的值,如果执行正常就表示指定的内存大小可用,否则会打印错误信息。

posted @ 2006-12-09 11:04 哈哈的日子 阅读(513) | 评论 (1)编辑 收藏

现在的 OA 系统必不可少的就是邮件系统,很多基于 Notes 的系统自带,但 Notes 毕竟是需要 money 的,自架 Email 服务器也不失为一个好办法。
还有一个就是现在流行的短信系统,早上起来上网研究了一下这方面的东西:

邮件系统:
       邮件服务器可以使用 Apache 的 James,在 http://www.5dmail.net/;上面有很多相关的文档

短信系统:
      短信发送我查了一下,通过 GSM Modem 加上一块普通的 SIM 卡,就可以发送短信了,GSM Modem 的价格大概在千元左右,看了几种 GSM Modem 都是使用的西门子的 TC35i 模块的,一般有发送短信,接收短信的功能,有的还有语音功能。

还有个叫做 MC35 的无线模块,也是西门子(Siemens)的,是支持 GPRS 的,并且也有 TC35 的全部功能,但估计价格会贵一些。在 ebay 上面查,TC35i 每块大概 270-300 元,MC35i Google 了一下,大概 420 元。

一些 GSM Modem 还提供 Java 接口,大概了看了一下,基本上是封装的 JNI 接口,虽然不能移植,但还是能减少不少工作量的,也可以使用 java 的串口通信包自己写一个,不过 AT 指令还是蛮多的。

网上这方面的资料还是很丰富的,包括指令集信息等

posted @ 2006-05-07 07:12 哈哈的日子 阅读(1248) | 评论 (0)编辑 收藏
JSF 是一个页面开发能力极强的技术,又拥有大量的扩展。同时 JSF 提供了一定的 IoC 能力,如果再集成 Spring 强大的 IoC 能力,将会给我们带来更多的方便(其实我是喜欢用 Spring 集成 Hibernate 的 ORM 能力和 Spring 的事物管理 ^_^)。
Spring 本身已经提供了集成 JSF 的能力,只要在 JSF 的 配置文件中增加一个 resolver 就可以了,具体如下:
<faces-config>
  <application>
    <message-bundle>resources.application</message-bundle>
    <locale-config>
      <default-locale>zh_CN</default-locale>
    </locale-config>
    <variable-resolver>
     org.springframework.web.jsf.DelegatingVariableResolver
    </variable-resolver>
  </application>
...
</faces-config>
posted @ 2006-04-23 09:16 哈哈的日子 阅读(1834) | 评论 (0)编辑 收藏

        本文对Java规则引擎与其API(JSR-94)及相关实现做了较详细的介绍,对其体系结构和API应用有较详尽的描述,并指出Java规则引擎,规则语言,JSR-94的相互关系,以及JSR-94的不足之处和展望。

  复杂企业级项目的开发以及其中随外部条件不断变化的业务规则(business logic),迫切需要分离商业决策者的商业决策逻辑和应用开发者的技术决策,并把这些商业决策放在中心数据库或其他统一的地方,让它们能在运行时(即商务时间)可以动态地管理和修改从而提供软件系统的柔性和适应性。规则引擎正是应用于上述动态环境中的一种解决方法。

  本文第一部分简要介绍了规则引擎的产生背景和基于规则的专家系统,第二部分介绍了什么是规则引擎及其架构和算法,第三部分介绍了商业产品和开源项目实现等各种Java规则引擎,第四部分对Java规则引擎API(JSR-94)作了详细介绍,讲解了其体系结构,管理API和运行时API及相关安全问题,第五部分则对规则语言及其标准化作了探讨,第六部分给出了一个使用Java规则引擎API的简单示例,第七部分给予小结和展望。

  1、 介绍

  1.1 规则引擎产生背景

  企业管理者对企业级IT系统的开发有着如下的要求:(1)为提高效率,管理流程必须自动化,即使现代商业规则异常复杂(2)市场要求业务规则经常变化,IT系统必须依据业务规则的变化快速、低成本的更新(3)为了快速、低成本的更新,业务人员应能直接管理IT系统中的规则,不需要程序开发人员参与。

  而项目开发人员则碰到了以下问题:(1)程序=算法+数据结构,有些复杂的商业规则很难推导出算法和抽象出数据模型(2)软件工程要求从需求->设计->编码,然而业务规则常常在需求阶段可能还没有明确,在设计和编码后还在变化,业务规则往往嵌在系统各处代码中(3)对程序员来说,系统已经维护、更新困难,更不可能让业务人员来管理。

  基于规则的专家系统的出现给开发人员以解决问题的契机。规则引擎由基于规则的专家系统中的推理引擎发展而来。下面简要介绍一下基于规则的专家系统。

  1.2 基于规则的专家系统(RBES)

  专家系统是人工智能的一个分支,它模仿人类的推理方式,使用试探性的方法进行推理,并使用人类能理解的术语解释和证明它的推理结论。专家系统有很多分类:神经网络、基于案例推理和基于规则系统等。

  RBES包括三部分:Rule Base(knowledge base)、Working Memory(fact base)和Inference Engine(推理引擎)。它们的结构如下所示:

图1.基于规则的专家系统组成
图1.基于规则的专家系统组成

  如上图所示,推理引擎包括三部分:Pattern Matcher、Agenda和Execution Engine。Pattern Matcher何时执行哪个规则;Agenda管理PatternMatcher挑选出来的规则的执行次序;Execution Engine负责执行规则和其他动作。

  推理引擎通过决定哪些规则满足事实或目标,并授予规则优先级,满足事实或目标的规则被加入议程。存在两者推理方式:演绎法(Forward-Chaining正向链)和归纳法(Backward-Chaining反向链)。演绎法从一个初始的事实出发,不断地应用规则得出结论(或执行指定的动作)。而归纳法则是从假设出发,不断地寻找符合假设的事实。
  2、 规则引擎

  2.1 业务规则
 
  一个业务规则包含一组条件和在此条件下执行的操作,它们表示业务规则应用程序的一段业务逻辑。业务规则通常应该由业务分析人员和策略管理者开发和修改,但有些复杂的业务规则也可以由技术人员使用面向对象的技术语言或脚本来定制。业务规则的理论基础是:设置一个或多个条件,当满足这些条件时会触发一个或多个操作。

  2.2 规则引擎

  什么是规则引擎?规则引擎是如何执行规则的?这可以称之为"什么"与"如何"的问题。到底规则引擎是什么还是目前业界一个比较有争议的问题,在JSR-94种也几乎没有定义。可以这样认为充分定义和解决了"如何"的问题,"什么"问题本质上也迎刃而解。也许这又是一种"先有蛋还是先有鸡"哲学争论。今后标准规则语言的定义和推出及相关标准的制定应该可以给这样的问题和争论划上一个句号。本文中,暂且这样述说什么是规则引擎:规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据规则做出业务决策。

  2.3 规则引擎的使用方式

  由于规则引擎是软件组件,所以只有开发人员才能够通过程序接口的方式来使用和控制它,规则引擎的程序接口至少包含以下几种API:加载和卸载规则集的API;数据操作的API;引擎执行的API。开发人员在程序中使用规则引擎基本遵循以下5个典型的步骤:创建规则引擎对象;向引擎中加载规则集或更换规则集;向引擎提交需要被规则集处理的数据对象集合;命令引擎执行;导出引擎执行结果,从引擎中撤出处理过的数据。使用了规则引擎之后,许多涉及业务逻辑的程序代码基本被这五个典型步骤所取代。

  一个开放的业务规则引擎应该可以"嵌入"在应用程序的任何位置,不同位置的规则引擎可以使用不同的规则集,用于处理不同的数据对象。此外,对使用引擎的数量没有限制。

  2.4 规则引擎架构与推理

  规则引擎的架构如下图所示:

图2. 业务规则引擎架构
图2. 业务规则引擎架构

  规则引擎的推理步骤如下:a. 将初始数据(fact)输入至工作内存(Working Memory)。b. 使用Pattern Matcher将规则库(Rules repository)中的规则(rule)和数据(fact)比较。c. 如果执行规则存在冲突(conflict),即同时激活了多个规则,将冲突的规则放入冲突集合。d. 解决冲突,将激活的规则按顺序放入Agenda。e. 执行Agenda中的规则。重复步骤b至e,直到执行完毕Agenda中的所有规则。

  任何一个规则引擎都需要很好地解决规则的推理机制和规则条件匹配的效率问题。

  当引擎执行时,会根据规则执行队列中的优先顺序逐条执行规则执行实例,由于规则的执行部分可能会改变工作区的数据对象,从而会使队列中的某些规则执行实例因为条件改变而失效,必须从队列中撤销,也可能会激活原来不满足条件的规则,生成新的规则执行实例进入队列。于是就产生了一种"动态"的规则执行链,形成规则的推理机制。这种规则的"链式"反应完全是由工作区中的数据驱动的。

  规则条件匹配的效率决定了引擎的性能,引擎需要迅速测试工作区中的数据对象,从加载的规则集中发现符合条件的规则,生成规则执行实例。1982年美国卡耐基·梅隆大学的Charles L. Forgy发明了一种叫Rete算法,很好地解决了这方面的问题。目前世界顶尖的商用业务规则引擎产品基本上都使用Rete算法。

  2.5 规则引擎的算法
 
  大部分规则引擎产品的算法,基本上都来自于Dr. Charles Forgy在1979年提出的RETE算法及其变体,Rete算法是目前效率最高的一个Forward-Chaining推理算法,Drools项目是Rete算法的一个面向对象的Java实现,Rete算法其核心思想是将分离的匹配项根据内容动态构造匹配树,以达到显著降低计算量的效果。

  3、 Java规则引擎
 
  目前主流的规则引擎组件多是基于Java和C++程序语言环境,已经有多种Java规则引擎商业产品与开源项目的实现,其中有的已经支持JSR94,有的正朝这个方向做出努力,列出如下:

  3.1 Java规则引擎商业产品

  Java规则引擎商业产品主要有(Jess不是开源项目,它可以免费用于学术研究,但用于商业用途则要收费):



  3.2 Java规则引擎开源项目

  开源项目的实现主要包括:

  Drools - Drools规则引擎应用Rete算法的改进形式Rete-II算法。从内部机制上讲,它使用了和Forgy的算法相同的概念和方法,但是增加了可与面向对象语言无缝连接的节点类型。

  Mandarax 基于反向推理(归纳法)。能够较容易地实现多个数据源的集成。例如,数据库记录能方便地集成为事实集(facts sets),reflection用来集成对象模型中的功能。目前不支持JSR 94

  OFBiz Rule Engine - 支持归纳法(Backward chaining).最初代码基于Steven John Metsker的"Building Parsers in Java",不支持JSR 94

  JLisa - JLisa是用来构建业务规则的强大框架,它有着扩展了LISP优秀特色的优点,比Clips还要强大.这些特色对于多范例软件的开发是至关重要的.支持JSR 94

  其它的开源项目实现有诸如Algernon, TyRuBa, JTP, JEOPS, InfoSapient, RDFExpert, Jena 2, Euler, JLog, Pellet OWL Reasoner, Prova, OpenRules, SweetRules, JShop2等等。

  4、 Java规则引擎API(JSR-94)

  4.1 简介

  过去大部分的规则引擎开发并没有规范化,有其自有的API,这使得其与外部程序交互集成不够灵活。转而使用另外一种产品时往往意味需要重写应用程序逻辑和API调用,代价较大。规则引擎工业中标准的缺乏成为令人关注的重要方面。2003年11月定稿并于2004年8月最终发布的JSR 94(Java规则引擎API)使得Java规则引擎的实现得以标准化。

  Java规则引擎API由javax.rules包定义,是访问规则引擎的标准企业级API。Java规则引擎API允许客户程序使用统一的方式和不同厂商的规则引擎产品交互,就像使用JDBC编写独立于厂商访问不同的数据库产品一样。Java规则引擎API包括创建和管理规则集合的机制,在Working Memory中添加,删除和修改对象的机制,以及初始化,重置和执行规则引擎的机制。

  4.2 简介Java规则引擎API体系结构

  Java规则引擎API分为两个主要部分:运行时客户API(the Runtime client API)和规则管理API(the rules administration API)。

  4.2.1规则管理API

  规则管理API在javax.rules.admin中定义,包括装载规则以及与规则对应的动作(执行集 execution sets)以及实例化规则引擎。规则可以从外部资源中装载,比如说URI,Input streams, XML streams和readers等等.同时管理API提供了注册和取消注册执行集以及对执行集进行维护的机制。使用admin包定义规则有助于对客户访问运行规则进行控制管理,它通过在执行集上定义许可权使得未经授权的用户无法访问受控规则。

  管理API使用类RuleServiceProvider来获得规则管理(RuleAdministrator)接口的实例.规则管理接口提供方法注册和取消注册执行集.规则管理器(RuleAdministrator)提供了本地和远程的RuleExecutionSetProvider.在前面已提及,RuleExecutionSetProvider负责创建规则执行集.规则执行集可以从如XML streams, input streams等来源中创建.这些数据来源及其内容经汇集和序列化后传送到远程的运行规则引擎的服务器上.大多数应用程序中,远程规则引擎或远程规则数据来源的情况并不多见.为了避免这些情况中的网络开销,API规定了可以从运行在同一JVM中规则库中读取数据的本地RuleExecutionSetProvider.

  规则执行集接口除了拥有能够获得有关规则执行集的方法,还有能够检索在规则执行集中定义的所有规则对象.这使得客户能够知道规则集中的规则对象并且按照自己需要来使用它们。

  4.2.2 运行时API

  运行时API定义在javax.rules包中,为规则引擎用户运行规则获得结果提供了类和方法。运行时客户只能访问那些使用规则管理API注册过的规则,运行时API帮助用户获得规则对话并且在这个对话中执行规则。

  运行时API提供了对厂商规则引擎API实现的类似于JDBC的访问方法.规则引擎厂商通过类RuleServiceProvider(类RuleServiceProvider提供了对具体规则引擎实现的运行时和管理API的访问)将其规则引擎实现提供给客户,并获得RuleServiceProvider唯一标识规则引擎的URL.

  URL推荐标准用法是使用类似"com.mycompany.myrulesengine.rules.RuleServiceProvider"这样的Internet域名空间,这将有助于访问URL的唯一性.类RuleServiceProvider内部实现了规则管理和运行时访问所需的接口.所有的RuleServiceProvider要想被客户所访问都必须用RuleServiceProviderManager进行注册。注册方式类似于JDBC API的DriverManager和Driver。

  运行时接口是运行时API的关键部分.运行时接口提供了用于创建规则会话(RuleSession)的方法,规则会话如前所述是用来运行规则的.运行时API同时也提供了访问在service provider注册过的所有规则执行集(RuleExecutionSets).规则会话接口定义了客户使用的会话的类型,客户根据自己运行规则的方式可以选择使用有状态会话或者无状态会话。

  无状态会话的工作方式就像一个无状态会话bean.客户可以发送单个输入对象或一列对象来获得输出对象.当客户需要一个与规则引擎间的专用会话时,有状态会话就很有用.输入的对象通过addObject() 方法可以加入到会话当中.同一个会话当中可以加入多个对象.对话中已有对象可以通过使用updateObject()方法得到更新.只要客户与规则引擎间的会话依然存在,会话中的对象就不会丢失。

  RuleExecutionSetMetaData接口提供给客户让其查找规则执行集的元数据(metadata).元数据通过规则会话接口(RuleSession Interface)提供给用户。

  使用运行时Runtime API的代码片断如下所示:

  RuleServiceProvider ruleProvider = RuleServiceProviderManager.getRuleServiceProvider
   ("com.mycompany.myrulesengine.rules. RuleServiceProvider");
RuleRuntime ruleRuntime = ruleProvider.getRuleRuntime();
StatelessRuleSession ruleSession = (StatelessRuleSession)ruleRuntime.createRuleSession(ruleURL,
   null, RuleRuntime.STTELESS_SESSION_TYPE);
List inputRules = new ArrayList();
inputRules.add(new String("Rule 1"));
inputRules.add(new Integer(1));
List resultRules = ruleSession.executeRules(inputRules);

  4.3 Java规则引擎API安全问题
  
  规则引擎API将管理API和运行时API加以分开,从而为这些包提供了较好粒度的安全控制.规则引擎API并没有提供明显的安全机制,它可以和J2EE规范中定义的标准安全API联合使用.安全可以由以下机制提供,如Java authentication and authorization service (JAAS),the Java cryptography extension (JCE),Java secure Socket Extension (JSSE),或者其它定制的安全API.JAAS能被用来定义规则执行集的许可权限,从而只有授权用户才能访问。

  4.4 异常与日志

  规则引擎API定义了javax.rules.RuleException作为规则引擎异常层次的根类.所有其它异常都继承于这个根类.规则引擎中定义的异常都是受控制的异常(checked exceptions),所以捕获异常的任务就交给了规则引擎。规则引擎API没有提供明确的日志机制,但是它建议将Java Logging API用于规则引擎API。

  4.5 JSR 94 小结

  JSR 94 为规则引擎提供了公用标准API,仅仅为实现规则管理API和运行时API提供了指导规范,并没有提供规则和动作该如何定义以及该用什么语言定义规则,也没有为规则引擎如何读和评价规则提供技术性指导.JSR 94规范将上述问题留给了规则引擎的厂商.在下一节我将简要介绍一下规则语言。
  5、 规则语言

  JSR 94中没有涉及用来创建规则和动作的语言.规则语言是规则引擎应用程序的重要组成部分,所有的业务规则都必须用某种语言定义并且存储于规则执行集中,从而规则引擎可以装载和处理他们。

  由于没有关于规则如何定义的公用规范,市场上大多数流行的规则引擎都有其自己的规则语言,目前便有许多种规则语言正在应用,因此,当需要将应用移植到其他的Java规则引擎实现时,可能需要变换规则定义,如将Drools私有的DRL规则语言转换成标准的ruleML,Jess规则语言转换成ruleML等。这个工作一般由XSLT转换器来完成。

  规则语言的详情这里不作详细介绍,名称及其网址列出如下:
  Rule Markup language (RuleML)
  http://www.ruleml.org/ Simple Rule Markup Language (SRML)
  http://xml.coverpages.org/srml.html Business Rules Markup Language (BRML)
  http://xml.coverpages.org/brml.html SWRL: A Semantic Web Rule Language Combining OWL and RuleML
  http://www.daml.org/2003/11/swrl/

  多种规则语言的使用使得不同规则引擎实现之间的兼容性成为问题.通用的规则引擎API或许可以减轻不同厂家API之间的问题,但公用规则语言的缺乏将仍然阻碍不同规则引擎实现之间的互操作性.尽管业界在提出公用规则语言上做出了一些努力, 比如说RuleML,SRML的出现,但距离获得绝大部分规则引擎厂商同意的公用标准还有很长的路要走。

  6、 Java规则引擎API使用示例

  6.1 设置规则引擎

  Java规则引擎的管理活动阶段开始于查找一个合适的javax.rules.RuleServiceProvider对象,这个对象是应用程序访问规则引擎的入口。在J2EE环境中,你可能可以通过JNDI获得RuleServiceProvider。否则,你可以使用javax.rules.RuleServiceProviderManager类:

javax.rules.RuleServiceProviderManager class:
String implName = "org.jcp.jsr94.ri.RuleServiceProvider";
Class.forName(implName);
RuleServiceProvider serviceProvider = RuleServiceProviderManager.getRuleServiceProvider(implName);

  拥有了RuleServiceProvider对象,你就可以获得一个javax.rules.admin.RuleAdministrator类。从RuleAdministrator类中,你可以得到一个RuleExecutionSetProvider,从类名可以知道,它用于创建javax.rules.RuleExecutionSets对象。RuleExecutionSet基本上是一个装入内存的,准备好执行的规则集合。

  包javax.rules.admin包括两个不同的RuleExecutionSetProvider类。RuleExecutionSetProvider类本身包括了从Serializable对象创建RuleExecutionSets的方法,因此在规则引擎位于远程服务器的情况下,仍然可以使用RuleExecutionSetProvider类,构造器的参数可以通过RMI来传递。另一个类是LocalRuleExecutionSetProvider,包含了其他方法,用于从非Serializable资源(如java.io.Reader-本地文件)创建RuleExectionSets。假设拥有了一个RuleServiceProvider对象,你可以从本地文件rules.xml文件创建一个RuleExectionSet对象。如以下的代码所示:

  RuleAdministrator admin = serviceProvider.getRuleAdministrator();
HashMap properties = new HashMap();
properties.put("name", "My Rules");
properties.put("description", "A trivial rulebase");
FileReader reader = new FileReader("rules.xml");
RuleExecutionSet ruleSet = null;
try {
LocalRuleExecutionSetProvider lresp =admin.getLocalRuleExecutionSetProvider(properties);
ruleSet = lresp.createRuleExecutionSet(reader, properties);
} finally {
reader.close();
}

  接下来,你可以使用RuleAdministrator注册获得的RuleExecutionSet,并给它分配一个名称。在运行时,你可以用同一个名称创建一个RuleSession;该RuleSession使用了这个命名的RuleExecutionSet。参见下面的用法:admin.registerRuleExecutionSet("rules", ruleSet, properties);

  6.2 执行规则引擎

  在运行时阶段,你可以参见一个RuleSession对象。RuleSession对象基本上是一个装载了特定规则集合的规则引擎实例。你从RuleServiceProvider得到一个RuleRuntime对象,接下来,从javax.rules.RuleRuntime得到RuleSession对象。

  RuleSession分为两类:stateful和stateless。它们具有不同的功能。StatefulRuleSession的Working Memory能够在多个方法调用期间保存状态。你可以在多个方法调用期间在Working Memory中加入多个对象,然后执行引擎,接下来还可以加入更多的对象并再次执行引擎。相反,StatelessRuleSession类是不保存状态的,为了执行它的executeRules方法,你必须为Working Memory提供所有的初始数据,执行规则引擎,得到一个内容列表作为返回值。

  下面的例子中,我们创建一个StatefulRuleSession实例,添加两个对象(一个Integer和一个String)到Working Memory,执行规则,然后得到Working Memory中所有的内容,作为java.util.List对象返回。最后,我们调用release方法清理RuleSession:

  RuleRuntime runtime = rsp.getRuleRuntime(); 
 StatefulRuleSession session = (StatefulRuleSession)runtime.createRuleSession("rules",
properties,RuleRuntime.STATEFUL_SESSION_TYPE);
 session.addObject(new Integer(1));
session.addObject("A string");
session.executeRules();
List results = session.getObjects();
session.release();

  7、 结束语

  Java规则引擎API(JSR-94)允许客户程序使用统一的方式和不同厂商的规则引擎产品交互,一定程度上给规则引擎厂商提供了标准化规范。但其几乎没有定义什么是规则引擎,当然也没有深入到规则是如何构建和操纵的,规则调用的效用,规则与Java语言的绑定等方面。并且JSR-94在对J2EE的支持上也不足。规则语言的标准化,JSR-94的进一步的充实深化都有待研究。
         转载自 http://www.javajia.com/modules.php?op=modload&name=News&file=article&sid=1545&mode=thread&order=0&thold=0


posted @ 2006-03-29 22:43 哈哈的日子 阅读(489) | 评论 (0)编辑 收藏
何仁杰 梁冰

业务规则管理系统的基本原理是:用一个或多个规则引擎替换以程序代码“固化”在应用系统中的业务逻辑。一个完善的BRMS可以对业务规则的整个生命周期实现全程管理。

业务规则的全生命周期管理如图1所示。BRMS在应用系统中的地位与数据库管理系统(DBMS)类似,处于比较基础的位置,是其他高端应用的基石。图2是GIGA Information Group 给出的IT架构中BRMS的位置图。

业务规则管理如何实现?

业务规则

一个业务规则包含一组条件和在此条件下执行的操作,它们表示业务规则应用程序的一段业务逻辑。业务规则通常应该由业务分析人员和策略管理者开发和修改,但有些复杂的业务规则也可以由技术人员使用面向对象的技术语言或脚本来定制。业务规则的理论基础是:设置一个或多个条件,当满足这些条件时会触发一个或多个操作。

规则引擎

这是一种嵌入在应用程序中的组件,它的任务是把当前提交给引擎的数据对象与加载在引擎中的业务规则进行测试和比对,激活那些符合当前数据状态下的业务规则,根据业务规则中声明的执行逻辑,触发应用程序中对应的操作。

目前主流的规则引擎组件多是基于Java和C++程序语言环境。在2000年11月,Java Community Process(简称JCP) 组织开始着手起草Java规则引擎的API标准,即JSR 94 规范。参与JSR 94起草的有BEA、IBM、ILOG、甲骨文、Novell、ATG、Unisys、Fujitsu等著名的软件企业。JSR 94 在2003年11月25日正式定稿,支持JSR 94标准的规则引擎也几乎同时推向市场,包括ILOG 的JRules和Blaze的Advisor。

规则引擎的使用方式

由于规则引擎是软件组件,所以只有开发人员才能够通过程序接口的方式来使用和控制它,规则引擎的程序接口至少包含以下几种API:加载和卸载规则集的API;数据操作的API;引擎执行的API。开发人员在程序中使用规则引擎基本遵循以下5个典型的步骤:创建规则引擎对象;向引擎中加载规则集或更换规则集;向引擎提交需要被规则集处理的数据对象集合;命令引擎执行;导出引擎执行结果,从引擎中撤出处理过的数据。使用了规则引擎之后,许多涉及业务逻辑的程序代码基本被这五个典型步骤所取代。

一个开放的业务规则引擎应该可以“嵌入”在应用程序的任何位置,不同位置的规则引擎可以使用不同的规则集,用于处理不同的数据对象。此外,对使用引擎的数量没有限制。

规则引擎的内部实现

规则引擎的基本机制是:对提交给引擎的数据对象进行检索,根据这些对象的当前属性值和它们之间的关系,从加载到引擎的规则集中发现符合条件的规则,创建这些规则的执行实例。这些实例将在引擎接到执行指令时、依照某种优先序依次执行。一般,规则引擎内部由下面几个部分构成:工作内存,用于存放被引擎引用的数据对象集合;规则执行队列,用于存放被激活的规则执行实例;静态规则区,用于存放所有被加载的业务规则,这些规则将按照某种数据结构组织,当工作区中的数据发生改变后,引擎需要迅速根据工作区中的对象现状,调整规则执行队列中的规则执行实例。规则引擎的结构示意图如图3所示。

任何一个规则引擎都需要很好地解决规则的推理机制和规则条件匹配的效率问题。

当引擎执行时,会根据规则执行队列中的优先顺序逐条执行规则执行实例,由于规则的执行部分可能会改变工作区的数据对象,从而会使队列中的某些规则执行实例因为条件改变而失效,必须从队列中撤销,也可能会激活原来不满足条件的规则,生成新的规则执行实例进入队列。于是就产生了一种“动态”的规则执行链,形成规则的推理机制。这种规则的“链式”反应完全是由工作区中的数据驱动的。

规则条件匹配的效率决定了引擎的性能,引擎需要迅速测试工作区中的数据对象,从加载的规则集中发现符合条件的规则,生成规则执行实例。1982年美国卡耐基·梅隆大学的Charles L. Forgy发明了一种叫Rete算法,很好地解决了这方面的问题。目前世界顶尖的商用业务规则引擎产品基本上都使用Rete算法。

BOM赋予规则行业特性

业务规则一定是针对某种业务的,不同的业务有自己特有的业务模型——业务对象模型(Business Object Mode,简称BOM)。BOM为业务规则语言提供了绝大多数的词汇,多由业务系统分析员设计,由开发人员具体实现。从面向对象的编程角度来看,BOM就是一个简化的类图,类图中有类名、类的属性、类的方法等。这些要素都将是业务规则语言中的基本“词汇”。BOM的来源可以是Java对象模型、C++对象模型、XML Schema、Web服务定义等。

假定我们有一个简单的宠物商店购物车应用程序,在这个应用程序中,顾客能够在购物车中放入各种宠物和相关物品对象。这个应用程序的业务对象集合就可以有ShoppingCart(购物车)、Customer(用户)、Item (条目)和ItemType(条目类型)这几个类。

表述业务规则的语法就是业务规则语言。由于规则语言的使用者主要有两类:业务人员和技术人员,所以规则语言一般也分为两类:“面向程序技术”的规则语言,它技术性很强,可读性较弱,比较适合IT 技术人员使用,一般每个规则引擎开发商都有自己的一套“面向程序技术”的规则语言语法,不过OASIS组织定义了不同应用情况下的规则语言规范,包括SRML(Simple Rule Markup Language),BMRL(Business Markup Rule Language)和RuleML(Rule Markup Language)等;“面向业务”的规则语言,它是业务人员使用的语言,必须具备非技术性和可定制性,通常它需要经过“翻译”之后才能被规则引擎解析。BRMS必须提供这种“翻译”机制,而开发人员要实现从“面向业务”规则语言到“面向程序”规则语言的映射。

“面向业务”的规则语言无论从语法上还是语句结构上都可能千变万化,不同行业可能有自己的“行话”。一个好的BRMS应该提供一个完善的规则语言框架,能够迅速地为业务人员定制不同的“行话”,否则业务人员还是无法真正成为业务规则的主人。

“单纯”的规则如何互连?

业务规则有一个非常明显的特性:单纯性。每个业务规则只描述自己特有的条件和满足条件的操作,业务规则本身并不关心它与其他规则的关系,如优先关系、互斥关系、包含关系等。每个业务规则本身可以有自己的属性,称元信息,可以用来处理规则之间相关性,例如引擎可以使用规则的优先级来依序执行规则的操作。

有些BRMS还提供一种称为“规则流”的定制功能。规则流是一个图表,定义了解决问题或执行业务流程的顺序。类似于统一建模语言(UML)的活动图,由一组任务以及定义这些任务之间执行顺序的转换逻辑组成。一个转换由条件控制,只有当该限制条件为“真”时才能完成这种转换。

这些任务可以是规则任务、函数任务或子规则流任务。规则任务包含一组要作为任务主体执行的规则,规则的执行逻辑由用户设置的任务属性严格控制。这些属性决定规则的排序、规则触发策略、执行算法等;函数任务包含要作为任务主体执行的脚本代码;子规则流任务则包含任务开始后将依次执行的子规则流。

为了方便开发人员和业务人员管理业务规则,BRMS必须提供具有直观用户界面的工具来实现业务规则管理。规则管理工具至少应该具备以下功能:规则的定制和编辑、规则流的定制、决策表形式的规则定制、规则的查询、规则有效期限的控制、规则的组织结构、规则模板的定制、规则库访问权限的控制、规则变更历史的记录、规则文档的管理等。

·小资料2·

业务规则管理系统其实是一组工具集,它包括:规则引擎、规则库、规则语言框架、规则管理集成开发环境。业务规则管理系统的基本工作原理如图所示。

规则引擎(Rules Engine)

是执行业务规则的软件组件,它嵌入在程序中,是业务规则管理系统的核心元素。规则引擎的类型有:简单型、数据中心型和面向事务型。

规则库(Rules Repository)及其服务机制

用于存储规则和规则元数据(Meta Data)以及与规则有关的属性。它提供一组工具用于存储、分类、查询、版本控制、权限控制、测试、提交等,规则的状态和有效性可以跟踪。规则库可以依托文件系统或数据库管理系统。

规则语言框架(Rules Language Framework)

规则语言一般分为两类:“面向程序技术”的规则语言,使用者是技术人员;“面向业务”的规则语言,使用者是业务人员。规则语言框架则为定制“面向业务”的规则语言提供支持。

规则管理工具(Rules Management Tool)

用于管理、创建、修改和部署业务规则的图形化工具,易用性强,除了开发人员外,业务人员也可以使用这套图形化工具实现对规则的管理。

规则集成开发环境(Rules IDE)

一般规则集成开发环境只有规则编辑器,而高级的规则集成开发环境可以实现对规则和规则库的管理:如规则的创建、分类、检索、修改、版本控制、权限管理等;甚至可以实现对多个规则引擎的“在线”调试;对规则集合进行冲突检查等。

一个完整的BRMS应该提供规则管理(Rules Management)、规则部署(ules Deployment)、规则分析(Rules Analysis)、规则定制和设计(Rules Design and Authoring)等功能。

(计算机世界报 第14期 B6、B7)

posted @ 2006-03-26 19:11 哈哈的日子 阅读(1354) | 评论 (0)编辑 收藏
Maven 在第一次运行的时候会在网上下载一些 plugin ,可是找了好久都找不到在什么位置。

而且我在安装的 maven 中运行,下载了一次,在 maven 的 eclipse plugin 中运行又下载了一次,很是奇怪。
寻找解决方法中……

找到原因了,%MAVEN_HOME%/conf/settings.xml 文件中写了位置,如下:

<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ~/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->

因为对 maven 机制不熟悉,没注意到这个。

默认存放的位置是你的 Document and Settings 下面用户目录的 .m2/repository 这个目录下。

也可以在这个地方配置。

另外一个就是 maven 可以在 settings.xml 文件中配置代理服务器,以方便访问 internet ,我在公司的时候就需要配置代理服务器才行。

但是,现在还是不知道为什么要下载这么多的 plugin
posted @ 2006-03-16 23:29 哈哈的日子 阅读(3469) | 评论 (2)编辑 收藏
从他们的 MVC 模型上面看,请求转发的模型基本一致。
性能的区别我觉得主要在 View 这一层上。

Struts 将 JavaBean 转至 JSP 页面,来处理页面显示,比较直接,而 Struts 本身也是关注的是 MVC 的分离,在页面处理方面并没有给予过多的关注。直接的显示让 Struts 在 View 层的性能有比较好的表现。

而 JSF 在 View 这一层:一、需要维护组件树的状态。二、需要使用渲染器来将组件渲染。性能就会比 Struts 差一些。


从生命周期的角度上来看

Struts 请求的基本周期是。经过 front servlet 的请求分发,然后生成 command 对象,由 action 调用 Model 直至转向 View。

JSF 的基本周期是,经过 front servlet 请求分发(这一步同 struts),然后 restore view , apply request value, process validations , update model 这些生命周期相当于 struts 生成 command 对象阶段,invoke application 相当于调用 model ,render response 相当于转向 view 阶段。

对比来看,请求分发阶段不会产生更多的性能差异,然后对比其它阶段
struts 生成 command 对象阶段包含 conversion 和部分 validation ,相当于 JSF 的 apply request value 和 process validations 阶段,但 JSF 还需要 restore view 和 update model(保持 Managed Bean 的状态),性能会差一点,但要补充的是 restore view 在 myfaces 的实现中,会将 view 对象放在客户端保存(好象可以配置不保存),下一次请求如果有 view 对象,会直接反序列化得到 view root ,相当于在客户端 cache了,而 update model 只会在部分与数据相关的组件会使用。最后的 invoke application 与 struts 的调用 action ,然后 lifecycle 中的 render response 阶段会找到对应的 view 并转向,然后由页面的 tag 调用 render 来渲染出页面。最后调用 tag 渲染页面阶段相当于 struts 的前台显示,但由于更大粒度和更精细的渲染,在这个阶段会与 struts 有一定的性能差。

总体来说,JSF 使用了大量的 cache 手段,尽量减少一些性能开销,但比 struts 增强的 backing bean 管理、事件处理能力和丰富的组件能力会让 JSF 在生命周期性能上比 struts 略逊一筹。

但这并不是所有的应用场景性能上都要比 struts 差,比如:同样是后台数据验证的情况下,JSF 在验证错误时立即会返回用户页面,而没有经验其它生命周期,可 struts 还是一样会走完全部生命周期,这种情况 JSF 就会达到比 struts 更好的性能。

瑕不掩瑜,性能上部分的劣势并不能掩盖 JSF 强大的功能和为我们省下的大量的时间,我相信 JSF 肯定会在将来的开发中得到更多开发者的青睐。

posted @ 2006-03-07 23:22 哈哈的日子 阅读(2277) | 评论 (1)编辑 收藏
  知道有java这个东西,是一年前的事。呵呵,不要误会,我不是刚接触电脑的小孩,过了年,我就是26岁了。
  知道java,是因为我有个傻瓜老公,他会这个。
  几天前,他告诉我买了个网址(不要挑剔我的用词,外行不是我一个人的错),把他的blog连到那上面去。看他天天回家就“抱”着电脑,嘴角还傻傻地向上翘,我就纳闷呀,blog我也知道,不就是一些闷骚的人说一些感性在先理性在后的话吗?至于置我这个“掌门”于不顾吗?趁他起身如厕之际,我急忙跑到电脑前,探个究竟。
  BlogJava?
        就是这个东东呀!
  恍然大悟,然后挠头,累不累呀!
  他在华为做研发,每天就用这个什么Java干活。华为那个可憎的XX公司,老总是个典型的资本家,天天要加班到很晚(九、十点钟是正常),而且每四个星期还要有一个星期六义务奉献。动辄罚款降薪,而且还要连带你的上司一同受惩!置《劳动法》于不顾,大大的坏!!可是为什么这样的辛苦,休息的时候还弄这个鬼鬼Java呀?哎呀,男人心,海底针呀!
  我就在这个Blog上逛了逛,哦,这样的人还真不少啊!难怪这家伙像看到亲人了似的。
  呵,呵呵,简单的浏览之后,我确定这里有多个我老公的copy版。每天起来做的第一件事就是打开信箱收发邮件;电脑桌面要简单,源文件里密密麻麻的才叫“眩”;上厕所双击开关,坐在马桶上用《程序员》来打发时间。
  不过我现在不会再抱怨了,虽然他依然听不见我的问话,即使我站在电脑旁边。我知道这是他唯一的心血,唯一的爱好,唯一的执着,唯一的事业,那么,我为什么不支持呢?
  现在的我还是不懂得什么是Java,但是我骄傲,因为老公是个出色的“程序员”。他不理我并不是我的魅力不及电脑,不然怎么会把所有的薪水花在我这边?没有时间理我,算了。因为我也没有那么多时间,我要收拾房间,搞好个人和“他”人卫生,还要花大量时间研究营养学,都说长久用电脑的人要多多补充的!
  祝愿所有用Java赚钱的人身体健康,一生平安!
  

  
  
  
posted @ 2006-03-03 10:33 哈哈的日子 阅读(1197) | 评论 (17)编辑 收藏