Monthly Archives: April 2011

通过Runtime.getRuntime().exec() 调用系统应用时,应该异步打印verbose信息

如果你这样打, 可能会导致执行阻塞

	private static void printInput(Process p) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
		String line;
		while ((line = in.readLine()) != null) {
			System.out.println(line);
		}
		in.close();
	}

所以,你要用非阻塞的方式来打。CXF源代码里有个不错的例子:

        if (p.getErrorStream() != null) {
            StreamPrinter errorStreamPrinter = new StreamPrinter(p.getErrorStream(), "", System.out);
            errorStreamPrinter.start();  //StreamPrinter是一个线程
        }

        if (p.getInputStream() != null) {
            StreamPrinter infoStreamPrinter = new StreamPrinter(p.getInputStream(), "[INFO]", System.out);
            infoStreamPrinter.start();  //StreamPrinter是一个线程
        }

讨论:如果一个布尔值可能为空,则不要用布尔来定义它的类型

“肚子里的孩子是不是男的?”? 除了回答“是”或“否”,还可以回答“不知道/未定”

原始的boolean类型不能赋值为“未定”,不能用;

java.lang.Boolean类型的对象可以赋值为“null”,似乎可以解决这个问题。 但这种做法仍有隐患:

  1. 有的人对“Boolean值可能为空”缺乏意识。 比如你的同事再调用你的 isBoy()时可能并不会先判断它是否为null.

  2. 有些框架对封装类型如Boolean, Integer会使用默认值机制。比如有些Web Service框架就会把客户端传来的Boolean值强行设置成Boolean.FALSE

为了解决这个问题,最好弃用布尔类型,改用enum,或者字符串。人们在潜意识里都知道enum和字符串可能为空,因此不会贸然犯错。

enum Gender{
  MALE, FEMALE
}

无自动ORM时父子关系的实现模式:parent.children 还是child.parentId ?

如果你的系统没有像Hibernate这样的自动ORM框架,即不会在对象Navigation时自动查数据库,那下面两种编码风格你会用哪种?

//领域概念:Order关联Customer

//风格1
public class Order {
	
	PK orderId;
	Customer customer;
 	
}

//风格2
public class Order {
	PK orderId;
	FK customerId;
}

详细内容请见附件。

jax-ws中映射多态

public interface AnimalService {
    @WebMethod
    void add(Animal animal);
}

这里Animal是抽象类,它有两个子类Cat和Dog; 有没有办法在WSDL里实现这种多态?

答案是可以,使用@XmlSeeAlso注解即可

@XmlSeeAlso({Cat.class, Dog.class})
public abstract class Animal{
} 

这样产生的WSDL里会有这样的东西:

<xs:complexType name="cat">
<xs:complexContent>
<xs:extension base="tns:animal">
<xs:sequence>
...
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>

SalesForce: 一个Managed Package的ISV应该采用什么样的开发部署过程?

一个第三方开发者(ISV) 需要开发Managed Package让消费者使用,而在这个ISV组织内部,软件开发又要经历 Dev -> QA测试 -> UAT测试 -> 上线 等步骤,而且Dev还要跟源码版本控制工具(如CVS)结合起来。

最佳模式是什么? 

首先,应该利用SalesForce的Migration Tool把Package中的所有Metadata 变成文件,然后把这些文件纳入到CVS中进行管理。在Dev时,这些文件应该放在一个“开发源码分支”中。 文件修改后,可以利用Migration Tool把它们作为MetaData塞回SalesForce服务器,最后开发人员可以登录SalesForce网站进行功能测试。 

那QA环境怎么办? 是否应该把“开发源码分支”中的文件集成到一个“QA源码分支”,然后再把这些文件塞回SalesForce,最后在SalesForce网站中测试?   答案是不行。因为namespace会冲突。 我们知道Dev和QA各有一个SalesForce实例,Managed Package在Dev分支中建立后,这个package对应的namespace已经被Dev实例独占了; 如果你想用Migration Tool把这个Package下的Metadata送到QA实例,则意味着QA实例也需要使用这个namespace. 但这是不可能的,因为一个namespace只能属于一个SalesForce实例。

那不同的实例用不同的namespace行不行?  不行。因为namespace会被直接硬编码到Apex代码中,它不是一个可以放在配置项里的东西。

所以,我们只能在Dev实例中手动打包,然后以publisher/subscriber的方式将这个包发布到QA实例中。 不过,QA实例的“安装pakcage”这种行为无法让某种配置管理工具自动记录下来。这是一个问题。

(未完待续)

SalesForce: 企业开发模式

Development Modes:

  1.直接在PROD环境中用WEB界面开发

  2.Dev -> PROD

  3.Dev -> QA -> PROD

  4.Dev -> QA -> Stage(UAT) -> PROD  适用于多个项目一起上线的情形

  5.最后一种做法,它适用于多个项目一起开发但不同时走的情形. 这种做法很复杂,在此不表.

2/3/4/5 都要遵守一个约定: 在PROD上手动做的改动,都应该集成到其他环境中. 否则, 当DEV,QA,Stage -> PROD时,可能会发生冲突

 

关于PROD -> DEV的同步,有一些最佳实践

  1. 不准直接在PROD上做改动.所有改动都要从DEV开始

  2. 如果要改PROD,只做Metadata API相关的改动;因为这种改动会生成一条可追踪的轨迹

  3. PROD上只设一个Admin.单人管理,比多人管理,可以集中记录所有的改动

  4. 定期做PROD->DEV同步,以避免遗漏

 

Release时还要注意SalesForce自己的升级问题.  而且,SalesForce中Sandbox和PROD的版本还未必一致.Sandbox的版本可能更高,也可能更低

SalesForce: Package中,Apex里的日志会对subscriber隐藏

也就是说,Package Provider自己跑这个程序时,可以看到日志; 而Subscriber在使用这个包时,就看不到任何日志。。。。。。

也就是说Provider无法通过日志为Sucbscriber 做Debug

SFDC的人在想什么? 真蠢!

p.s. 这个问题在2010年就有人提出来了

http://success.salesforce.com/ideaView?c=09a30000000D9xtAAC&id=087300000007Py4AAE