2007年8月2日 星期四

Atlassian Confluence 2.3 的LDAP缓存配置问题

在 Atlassian Confluence 2.3中,如果用户和组来自于LDAP,当一个用户事先未加入用于授权的组,此时用户访问WIKI页面时会提示“Not Permitted”,但管理员将该用户加入授权的组,访问时仍然会提示未许可。这是因为Confluence使用了缓存机制。以管理员进入Confluence后,点击右上角的"Administration"打开管理页面,选择左边菜单 Administration->Cache Statistics。打开这个页面可以看到系统的缓存信息:

点击Flush可以手动清除缓存。


Confluence的缓存使用的是Orachle的Coherence技术,配置在confluence-coherence-cache-config.xml配置文件中定义的(在目录..\confluence\WEB-INF\classes下)。详细的配置定义可以参看
Coherence的配置元素参考,这里简要说明需要调整的配置。


缓存配置的问题


配置文件的根节点包含两个部分:
定义要配置的项,下表中的项是配置文件默认的LDAP部分的定义:


<cache-mapping> 
<cache-name>com.atlassian.user.impl.ldap.LDAPUserManagerReadOnly.users_ro</CACHE-NAME>
<scheme-name>user</SCHEME-NAME>
</CACHE-MAPPING>
<cache-mapping>
<cache-name>com.atlassian.user.impl.ldap.LDAPUserManagerReadOnly.repositories</CACHE-NAME>
<scheme-name>user</SCHEME-NAME>
</CACHE-MAPPING>
<cache-mapping>
<cache-name>com.atlassian.user.impl.ldap.LDAPGroupManagerReadOnly.groups</CACHE-NAME>
<scheme-name>user</SCHEME-NAME>
</CACHE-MAPPING>
<cache-mapping>
<cache-name>com.atlassian.user.impl.ldap.LDAPGroupManagerReadOnly.groups_hasMembership</CACHE-NAME>
<scheme-name>user</SCHEME-NAME>
</CACHE-MAPPING>
<cache-mapping>
<cache-name>com.atlassian.user.impl.ldap.LDAPGroupManagerReadOnly.groups_getGroupsForUser</CACHE-NAME>
<scheme-name>user</SCHEME-NAME>
</CACHE-MAPPING>
<cache-mapping>
<cache-name>com.atlassian.user.impl.ldap.LDAPGroupManagerReadOnly.repositories</CACHE-NAME>
<scheme-name>user</SCHEME-NAME>
</CACHE-MAPPING>


schema-name定义了配置表的名称为user,上面的LDAP的配置都使用user配置表,前面提到加入组无效的问题,就是因为"com.atlassian.user.impl.ldap.LDAPGroupManagerReadOnly.groups_getGroupsForUser"缓存的原因。

接下来我们看配置的缓存值,节定义各个schema的缓存值,与LDAP相关的是如下部分:


<local-scheme> 
<scheme-name>default</SCHEME-NAME>
<class-name>com.atlassian.confluence.cache.tangosol.HitTrackingLocalCache</CLASS-NAME>
<high-units>1000</HIGH-UNITS>
<expiry-delay>3600</EXPIRY-DELAY>
</LOCAL-SCHEME>
<local-scheme>
<scheme-name>user</SCHEME-NAME>
<scheme-ref>default</SCHEME-REF>
<high-units>5000</HIGH-UNITS>
<expiry-delay>300s</EXPIRY-DELAY> //定义缓存过期的时间,可以根据需要进行调整
</LOCAL-SCHEME>

user的schema使用default。从这个表看,user的expiry-delay项为300秒,也就是过5分钟后,该用户就可以具有权限访问WIKI页面了,但实际上并非如此,用户依然未授权。后检查发现,这个配置项根本不起作用!而是使用了default的设置,3600秒也就是60分钟才会过期。问题出在cache-mapping的定义上,在Cache Statistics的页面可以看到缓存定义项的名字比配置文件中的定义名多了一级:ldapRepository。这是atlassian-user.xml配置的ldap库的名字,原来Confluence内部的缓存配置项名加上了库的名字,但在默认的配置项定义中却没有,因此上面的配置根本不起作用。Confluence的文档也未提到这一点,让我折腾了很长时间!!


解决办法

解决办法很简单,就是在cache-mapping的cache-name值的com.atlassian.user.impl.ldap.LDAPGroupManagerReadOnly后面加上库的名字(这里是ldapRepository)即可,新的配置如下:


<cache-mapping> 
<cache-name>com.atlassian.user.impl.ldap.LDAPUserManagerReadOnly.ldapRepository.users</CACHE-NAME>
<scheme-name>user</SCHEME-NAME>
</CACHE-MAPPING


修改后重启Tomcat即可。

2007年7月12日 星期四

论“巴比塔”软件的建不成(杂乱无章版)

2005-02-23 12:07:50

某公司要开发一个软件,“能够管理一件事情从商谈到执行的全过程和过程相关的活动”,这是产品的Vision。产品的提出者认为现在人们管理一件事情,需要用到各种独立的软件,比如Instant Messenger进行交流,合同管理前期商谈结果,Microsoft Project进行项目计划和跟踪,财务系统来管理相应的资金活动,生产系统管理生产资料和制造计划,而这些活动都是相关的,目前似乎缺少一种可以把所有这些相关的活动集中管理的软件。于是,产品的提出者希望通过一个叫"Case"的概念来管理与这个Case相关的活动:


  • Case的请求者(Requester)和执行者(Performer)之间的商谈过程。同时管理包括费用、工期、交付项等所有可商谈的内容。

  • Case的Performer方的实施活动

  • Case的Requester和Performer之间关于实施活动的管理

起初听到这个想法的人会有两种反应:部分开发人员认为这将是一个非常庞大的系统,无法实现,但产品经理说可以由简到繁逐步完成;而另一部分人则认为“把相关的事情放在一起管理,似乎是一个不错的主意”。

各位可以先考虑一下:是否存在这样的软件?这样的软件是否合理?
最初的概念大家还能接受:

  • Case的商谈过程。Requester和Performer利用Message交流,修改Case文档,达成一致后签字确定。

  • 填写进度报告,体现实施的进度。

  • 验收Case完成的内容,关闭Case。

注意我前面重点标示的“相关性”,它是这个产品在引入功能时使用的一个原则,产品组在强调一个功能应该存在时,喜欢说“这个功能与Case相关,不放在这里,放在什么地方呢?”。

但随着功能的逐步细化,需求的深入分解,系统要完成的事越来越多。首先是Requester和Performer扩展为一个团队。产品组认为无论从甲方还是乙方在谈判时,都有许多人参与到相关的工作,比如其中一个人被临时邀请绘制Case里需要参考的一张工程图。既然是相关的,就应该让Case来管理这些参与者。

然后需要增加一个文档功能,用来管理Case相关的文档,包括Requester和Performer各自团队的文档以及共享的文档,产品组甚至为此设计了一个复杂的权限控制策略:有的文档属于两个团队共享,有的属于其中一个团队,而有的有只能由某一个团队的某个角色才能看见。

需求开始变得越来越复杂。越来越多的功能被考虑进来:Case的文档需要文档管理系统,Case可以用来制作Business Plan,执行阶段的项目管理,产品组甚至认为这个软件理论上可以替代现有的所有业务软件,“如果有足够的财力和资源的话”。同时一项简单的功能其业务规则也越来越复杂。产品组一直用一个看似颇有些道理的思想来构筑整个产品:


    “相关的事情需要在Case里管理”


于是,Requester/Performer从个体变成独立的团队以体现协商双方实际可能是以小组工作的,所使用的相关文档要放在里面,所有相关的活动要在Case里管理。这使我想起了著名的“六度理论”,一个数学领域的猜想,名为Six Degrees of Separation。20世纪60年代,耶鲁大学的社会心理学家米格兰姆(Stanley Milgram)设计了一个连锁信件实验。他将一套连锁信件随机发送给居住在内布拉斯加州奥马哈的160个人,信中放了一个波士顿股票经纪人的名字,信中要求每个收信人将这套信寄给自己认为是比较接近那个股票经纪人的朋友。朋友收信后照此办理。最终,大部分信在经过五、六个步骤后都抵达了该股票经纪人。六度分割(也叫“六度空间”),“小世界”[1]的概念由此而来。



通过这个连锁实验,体现了一个似乎很普遍的客观规律:社会化的现代人类社会成员之间,都可能通过“六度空间”而联系起来,绝对没有联系的A与B是不存在的。这是一个更典型、深刻而且普遍的自然现象。我们看似不相关的事物常常可能具有相关性。同样在企业活动里,我们仍然可以假定不用六度就可以建立一项活动和另一项活动的相关性,比如人员招聘和财务、生产之间的关系。如果用“相关性”来考虑,一个Case几乎要关系到所有的活动:立项审批、财务、生产系统、资源管理、...,最终这个软件就像一个巨大的“巴比塔”[2],它试图包含所有的业务功能,而结果是变成一个没有边界永远无法完成的怪物。

因此,仅仅使用“相关性”是无法作为一个软件功能的选择基础的。应该怎样来考虑一个产品的功能才合理呢?除了需要有明确的用户需要,为客户提供价值,从分析角度考虑,它应当服务某一个特定“领域”(Domain)。


什么是领域?在回答这个问题之前,我们先来看另一个问题,我们怎样解释“人”?在自然物种学科里“人”是“高级灵长类动物”。在社会系统中,它代表社会中的个体。在自然基因图谱的它不过是一组与其它生物具有一些相同部分又具有不同部分的基因组成。我们得到的解释都是在某一学科或者某种特定的上下文——一个特定的维度下进行的,听上去难以理解,但实际情况是我们无法完全准确的描述一个物体。同样,一个软件也无法解决所有的问题,真实世界具有无穷尽的复杂度,它需要面对特定的问题域。这个域中的问题并非毫无关系,它是根据某个特征维度聚合起来的,这个聚合的纬度就是我们前面提到的“领域”。即便对于Case这样一个看似简单的概念,如果我们不能明确它的领域,就无法对它进行明确的解释,也难以明确解决问题的范围。

领域通常具有以下特征:


  • 具有公共的领域概念。例如字处理器的“Glyph”,“Style”,“View”等概念。

  • 具有共同特征的使用此领域概念的用户。例如Java IDE工具面向Java开发人员,财务系统面向会计、出纳人员。

如果一个系统试图包含一个以上“领域”,概念就会相互混杂,系统将变得难以理解,并带来复杂度的倍增。仍然考虑前面的例子,产品组为前面的文档功能设计了其权限控制规则:

  • Requester的文档只能Requester团队的成员才能查看,有的文档需要Requester Team的特定角色(比如Leader)才可以查看。

  • Performer规则同上。


产品组花了很长时间来解释权限控制规则。而这只是Case的一个很小的功能,却要求如此复杂的安全需求。它需要这种复杂度吗?对于商谈活动来说,不需要单独的文档,所有文档都是为商谈共享的,因此既然是双方都能查看,就不需要控制查看权限。对于团队工作活动,其文档的控制通常基于个人再团队中的角色。两个活动单独来看其文档控制策略要简单得多,当两个活动放在同一模型里,却带来了规则的相互约束,于是就有了上面那个复杂的安全规则列表。产生这种现象的原因是因为这两种业务面向的使用者和业务特征是不一致的。如果关注商谈活动这个领域,其面向的是协约双方,关注协作过程和结果。而如果关注其中的一方怎样以团队的方式工作,则面向的一个团队内部,核心的概念可能是小组结构、任务分解。多个领域概念放在同一个模型里,将使业务规则产生“阶乘”式增长,从而导致业务复杂度的倍增!

因此,系统首先必须要有一个清晰的领域概念,它让我们明确解决的问题与,而这是判断入一项功能应否加入系统的权衡“依据”。考虑下面的例子,有人打算给一个Java IDE工具软件增加如下两项功能:


  • 支持Rename方式的重构。

  • 基于Database的版本控制系统(VCS),使代码可以保存在数据库中。


首先来看Rename功能。Rename是"Code"的重构,而"Code"是Java IDE的领域核心概念。VCS则不一样,VCS可以管理所有文档,它有一个与Java IDE完全不一样的领域概念,如“版本”、“分支”、“标签”等,而Java IDE关注的是Java "Code"的编写、调试、编译、打包。但我们也知道,目前几乎所有的开发工具都支持版本控制系统——它不是直接实现,而是提供对一个独立VCS系统的接口。这两个IDE相关的功能其实正好体现了“六度空间”中不同的相关性。在使用“六度理论”来分析社会关系时,把直接相关("我"的朋友)的称之为“强关联”,而把间接相关(“我”的朋友的朋友)称之为“弱关联”。我们可以把与系统领域相关的功能称之为“强关联”,而把与相关领域有关的功能称之谓“弱关联”。按照这种方式,Rename相对于Java IDE是“强关联”的功能,而VCS是拥有自己领域的“弱关联”功能。对于“强关联”功能应该在系统内实现,而不同领域则应当考虑建立独立的领域系统,使用松散耦合的方式来建立关联。对于一个大的复合系统,如果无法定义为一个领域,就应该分解成多个领域,保持独立领域的概念完整,并使用松散耦合的方式来建立领域之间的关联,使系统保持在一个可接受的复杂度中。

在面向对象设计范畴里,“高内聚”是衡量一个优良设计的基本标准。而从用户和系统价值来看,“解决用户的域相关问题的能力是软件的心””[3],“领域”分析是帮助建立用户问题域为中心的高内聚系统的基础。

要选择一个清晰的案例来阐明上面的观点,并不是一件容易的事。如果有人认为Case案例的场景也可能存在一个我并不清楚的领域模型,我是同意这种说法的,因为领域本身并没有固定的概念,但为了讲解的必要,需要假定Case案例存在这样一种令人迷惑混乱的“百慕大”三角区[4]。而这种误区和带来的后果在我们的软件开发生涯中却并非罕见。

另外一个需要注意的问题是这里的“领域”并不是通常意义的领域模型,它不是指一个具体的模型。我更强调它是根据某个维度产生的,自然内聚的关键概念。


------
[1].小世界。Small World,由Six Degrees of Separation引申出来的概念。从2001年秋天开始,美国哥伦比亚大学的社会学教授瓦茨(Duncan Watts)组建了一个研究小组,利用Email这一现代通信工具,开始进行“小世界假设”(Small World Project)的实验。在1年多时间里,总共有166个国家和地区的6万多名志愿者参与实验,实验结果证明,一封邮件平均被转发6次,即可回到接收者那里。See Small World Project
[2].巴比塔。Babel,也译作“巴别塔”。巴比塔是《圣经》故事中提到的一座通天塔,他由挪亚的后代所建。《旧约•创世纪》第11章曾有这样一段描述:古时候,天下人都说一种语言。人们在向东迁移的进修,走到一个叫示拿的地方,发现一片平原,就住下来。他们计划修一座高塔,塔顶要高耸入云,直达天庭,以显示人们的力量和团结。节选自《失落的文明:巴比伦》,华东师范大学出版社。
[3].引自Eric Evans的《Domain-Driven Design: Tackling Complexity in the Heart of Software》一书,"Part I:Putting the Domain Model to Work"部分。
[4].“百慕大”三角区。美国东南沿海的西太平洋上,北起百慕大,延伸到佛罗里达州南部的迈阿密,然后通过巴哈马群岛,穿过波多黎各,到西经40度附近的圣胡安,再折回百慕大,形成一个三角地区。自1945年12月由五架美国军用飞机组成的飞行中队在这里失踪后,发生了数起飞机、轮船的神秘失踪事件,这个区域因此被称为百慕大三角区或“魔鬼三角”。

More Readings
------
Rational Unified Process关于领域模型开发的相关内容
关于六度分割理论,有很多关于Six Degree of Separation和Small World的链接。

The Small-World Phenomenon: An Algorithmic Perspective
《Domain-Driven Design: Tackling Complexity in the Heart of Software》, Eric Evans, Addison Wesley Published. 中文版《领域驱动设计》由清华大学出版社引进。
 

2007年6月3日 星期日

Iris:Web Page Decoration Framework

(实验性项目,已不再维护)

Iris是为了处理Web页面装饰和布局管理的框架,它的设计思想基于GoF 的decoraotr设计模式。Iris分离页面正文和布局装饰的部分,使得Web页面更容易被测试和维护。

如果要了解Iris的更多信息请看Iris IntroduceIris Developer Guide

Features

  • 支持多级装饰器
  • 支持可扩展的decorator filter结构
  • ASP.Net技术
  • C#实现

下载