[架构]超越SOA:动态业务应用的新企业应用框架

mikel阅读(821)

第一部分——即使拥有全部需求和最佳设计,你的架构仍然很可能失败,原因在于……

目前的管理学校,教育培养的是公司经营者。设计公司几乎没有引起重视……几乎从来没有任何人为了取得计划的增长和稳定性,有意识和有思想地设计一个组织。

相关厂商内容

Dev2Dev技术日:如何在SOA参考架构中使用Eclipse、Java、Flex和SOA?

SOA中国关键任务论坛(5.22北京)Free电子票下载

相关赞助商

5月6日至5月22日全国8站,BEA Dev2dev TechDays与您一起探讨Java2SOA最新技术变革。即刻免费报名参加,获赠BEA/Adobe软件和SOA书籍。

——  Jay W. Forrester,设计未来(1998)

介绍

在一篇名为《动态业务应用势在必行(The Dynamic Business Applications Imperative)》的论文中,Forrester的高级分析师John R. Rymer指出了当今应用的一个致命缺陷:

当今应用迫使人们去寻找一种将孤立的信息和功能组映射到他们任务和过程的方法,它们强迫IT人员花高额预算来跟踪不断变化的市场、策略、规章制度和业务模型。

在下一个5年内,IT的主要目标应该是发明新一代企业软件,适应业务和业务工作,同时能随业务演变而演变。

Forrester称这个新生代为动态业务应用, 强调了和业务过程及工作(为人而设计)的紧密配合,对业务变化的自适应(为变化而构建)。在这个阶段,动态业务应用的需求比创建它们所需的设计实践更清 晰。工具都是现成的:面向服务架构(SOA)、业务过程管理(BPM)和业务规则领域中的先驱——包括独立软件开发商(ISV)——已经开始向我们展示了 这种方法。现在就是开始这段旅程的时候。

在这篇由两部分组成的文章中,我们会从架构和方法论的角度,采用历史的观点来看待这些动态业务应用(DBA)的发展。我们的目标是获得一种能使应用容易适应业务变化和其他必要修改的构建方法。随着企业在21世纪关注灵活性,DBA是使业务和IT在未来几十年内成功的关键。

图 1. 灵活性和效率——21世纪企业的两个主要驱动力

动态性对我们意味着什么?

在软件工程领域,许多框架或产品都声称具有自适应性。在我们设法理解一个解决方案在适应变化方面究竟有多好之前,需要给系统是如何变化的——它们的动态性——下一个可靠的定义。

早期的面向对象方法论认识到[1]:为了使系统分析中立,它必须基于两类现实世界的需求:

  • 现实世界的实体 —— 收集现实世界实体的信息和它们间的关系,有助于分析师开始以一种系统的、结构的、客观的观点来看待需求,而非一种技术的、主观的观点
  • 现实世界的事件 —— 系统行为只由改变现实世界实体状态的事件的出现来驱动

在这样的背景下,对于每一个被分析的系统,我们总能识别一个或多个最重要的实体。每个实体都又包含3个关联元素:事件、状态和生命周期。每个事件代 表状态中的一个变化,所有普通实体状态的有序和代表了一个生命周期。但是,那些触发状态变化且是正常流程一部分的事件与那些触发状态变化但不是正常流程一 部分的事件之间有明显的差异。例如,当一个产品订单被提交之后,一组可能发生的事件包括付费处理和订单交付。当一个用户变更订单或当企业改变价格时,我们 不能认为这些动作是正常流程的一部分,因此它们与实体(如订单)的生命周期无关。核心实体实例的生命周期单独定义了在正常操作中系统最有可能处理的东西。 所有其他事件类型,如变化或中间步骤,被区别对待。

这个场景对很多工程师都不陌生:一个系统模型包含一个核心实体结构,该实体具有一组事件,这些事件组成了实体的生命周期。这个系统模型对分析师和设 计者都很清晰且易于理解。建模工具,如有限状态机、实体关系图、实体状态转换图和数据流图,为了帮助这种方法已经经过了快20年的完善。那些为复杂系统 (如空客380或F-22,后者是世界上最高级的战斗机)服务、拥有数十亿行代码的软件就是这样被编写出来的。使用对象流图(它是捕获事件和状态转换的基 础模型)虚拟化实体生命周期是这个模型的关键。在这个情况下,架构可以被认为是静态的,因为整个系统状态在时间轴上的任意一点都是确定的。

图 2. 事件模型、状态变化和生命周期是正常操作的核心

普通事件、状态、生命周期间的关系,以及从其他事件类型中分出的普通事件是理解所建议的动态操作框架的基础。正如James Martin 和James Odell很久以前在《面向对象分析设计》中所写的,分析师、设计师和实现者都应该使用同一系统模型。分析师使用数据流图思考,设计师使用结构图思考,程 序员使用Java和SQL思考。在数据流上下文中,分析师识别对象类型,并思考改变对象状态的事件。最终用户也理解这个相同的认识。他们也应该按照对象类 型、事件、对象状态的变化,以及触发和控制事件的业务规则进行思考。Martin和Odell强调了对象流图对系统设计师的重要性:“事件模式适合按照事 件、触发器、条件和操作来描述过程。但是这种方式不适合描述大型复杂过程。一个系统领域常常太大或太复杂,无法表示成事件和触发器。此外,可能只有一个高 级别的认识才是必要的。这对战略级别的规划尤其正确。在这样的情况下,一个对象流图是有用的。对象流图(OFD)与数据流图(DFD)类似,因为它们描述 了活动和其他活动间的接口。在DFD中,这个接口传递数据。在对象技术中,我们不再限于数据传递。相反,图应该表示从一个活动传递到另一个活动的任何类型 事物:不论它是报表、零部件、已完货物、设计、服务、硬件、软件——或数据。简而言之,OFD指的就是被产生的对象,以及产生和交换它们的活动。”

为了捕获与业务操作关联的信息流,业务分析师用价值流程图(Value Stream Mapping)对OO方法论进行了补充。价值流程图起源于丰田,与精益制造关系紧密。美国国家环境保护局将价值流程图定义为“用来认识那些产生产品或交 付服务的活动序列与信息流程的精益过程映射方法。”此处的关键词是“产品”和“服务”。它们显现了合适的信息流程在整个企业中扮演的统一角色。

把过程流图和价值流程图两个概念结合在一起后,它产生了一个完全代表整个企业经营范围、可被方便翻译成OO(图2)概念的框架基础。

但是,许多系统并不是静态的,它们变化无常的行为无法被一组关系和事件捕获。事实上,它们发生在不可知的[2]未来,传统用来捕获它们动态特点的工具不起作用。所有的业务应用和绝大多数现实世界的系统都归于此类。这些系统,基于它们和其他外部系统的交互方式,处理3类变化:

  • 正常工作 —— 组成主实体或实体们生命周期的正常事件序列。通过每个事件——实体改变其状态——通常可以方便地定义一个过程。在正常工作行为内部,有些操作上下文元素不 期望被改变。例如,当一个客户订购一个产品时,在整个提取订单、准备订单和交付订单的过程中,诸如价格、组成和交付方式等是不期望被改变的。
  • 内部变化 —— 如上所述,在整个核心实体生命周期内,某些上下文元素不期望被改变。在现实世界中,这并不总是真理,因为管理决策或其他因素会迫使上下文元素变化。我们称内部系统属性的变化是内部变化。
  • 外 部或环境变化 —— 不管一个企业如何相信他们“拥有”一个客户,但是这个客户总有保留改变他或她意志的自由。一个系统不太可能与外部系统(如客户或供应商)总是有一个“固定 的”合同。然而,正常工作很可能围绕这个“固定的”规则集合进行设计。我们称系统外部引起的变化为外部变化。

要对现实世界系统建模,就必须处理好这所有3种变化类型。这种模型与静态架构模型相比,在管理复杂性上有了极大的提高。从正常工作的观点来看,内部 和外部系统完全独立于主信息流运行。内部和外部系统甚至有它们自己的操作——管理有其自身的决策周期,客户有其自己的操作环境——由各自的信息流描述。就 信息流而言,这3种系统分别运行在3个平行宇宙中。解决这3种非同步信息流的唯一办法就是为每个信息流实现一个独立全面的变更管理。这种复杂交互在图3 (动态操作图)中表示。

邮轮公司给客户提供的服务可以作为解释动态操作的例子。在订购时,一个客户会决定在游览期间他计划参与的服务。但是,不仅客户可能在游览前和游览中 改变主意,而且邮轮公司也可能会为了利用新机会或应对未知事件改变服务。按照当前方法设计的系统,大部分变更都以极高的运营成本人工处理。使用基于动态业 务应用架构原则设计出的系统,来自客户和内部管理决策的变更由两个与正常工作完全集成的变更管理子系统负责。这不仅能降低成本,而且还提高了服务质量,甚 至可以最优化运营来提高利润。因为是完全通用的,它还可以重用标准组件。最终结果对于参与的每个人、业务、IT和客户来说是多赢的。

图 3. 动态操作有3个维度——正常事件、内部控制和外部反馈

动态业务应用的目标之一就是使设计和软件实现变得简单,以支持对所有业务来说司空见惯的动态系统。以我们的经验,与一个框架优先的工程学相结合是构建一个DBA的最有效的技术方法。

设计企业系统要求框架先行

构建动态业务应用说起来简单,做起来难。工程,包括软件工程,都采用了有百年历史的框架优先方法。设计一座桥梁、一架飞机或者甚至是一个软件应用都 使用相同的方法:一个设计团队先收集需求,然后使用一组定义良好的框架步骤来设计和构建系统。在设计桥梁和其他工程系统时,现有框架已被证明非常成功。但 在使用它来为业务系统开发软件时,却碰了壁。这两类系统之间有一个根本区别。在设计桥梁和飞机时,最终结果总是一个拥有静态架构的系统:当变更发生时,如 增加桥梁负重或飞机速度,整个系统可能就要重头重新设计。不幸的是,软件也常常使用一个静态架构进行设计:每当一个非预期的变更被引入到运营中时,很可能 所有事情都停了下来,使用包含新增功能的系统替代现有系统。因为业务运营在一个不断变化的环境中,而且比以往更依赖IT系统,这种停——走式的解决方案是 不可接受的。持续升级和在企业基础设施中集成系统的成本已经达到了无法支撑的地步。

依赖业务涉众作为我们全部需求的输入首先就是个问题。考虑到需求,目前还没有真正适合动态操作的“框架优先”软件设计方法。甚至卡内基梅隆软件工程 学院也表示架构是由场景驱动的,场景以涉众输入为基础被创建出来:“诱导一个软件密集型系统的业务目标是标准架构设计和分析方法的一个组成部分。业务目标 是驱动方法的引擎,通过将它们的实现作为场景……一个理想的设计方法或过程必须考虑众多涉众和众多影响。”

作为工程师,当我们收集系统需求时,我们怎能知道我们得到了正确的场景或是否遇上了正确的涉众?我们又如何能说明业务未来的变化,而这些变化通常连参与的涉众都不知道?

“企业经营者和企业设计师之间存在着根本区别。为了说明这点,考虑一下在一架飞机成功操作背后的两种最重要的人。一个是飞机设计师,另一个是这架飞 机的飞行员。设计师创造的飞机连平庸的飞行员都可成功驾驶。一般情况下,经理更像是飞行员而非一个设计师。一个经理管理一个组织,这和一个飞行员驾驶飞机 没什么两样。飞行员的成功依赖于那些创造了一架成功飞机的飞机设计师。另一方面,是谁来设计一家由管理者管理的公司呢?几乎从没有任何人有意识和有思想的 去设计一个组织,以取得有计划的增长和稳定性。在当前的管理学校中,教育培养的是企业的经营者,而如何设计企业几乎不受重视。”

在几年前完成的报告“设计未来”中,MIT的教授和系统动态之父Jay Forrester,指出这个问题是我们为企业设计系统的基本限制:

Forrester的观察进一步使当前的企业架构方法失效。在我们需要设计一个企业系统架构时,作为知识主要来源的涉众甚至是错误的分类。他们是企 业的“用户”,不是“设计师”。在设计飞机时,飞机设计师决不可能去询问飞行员或乘客关于飞机制造方面的事情。但是,在学校、工程或MBA课程中却没有企 业设计这门课。

那么回到企业架构,其中有一个根本的断档。企业架构的“用户”是企业涉众,很可能是熟悉企业动态性的企业毕业生,但是他们不熟悉工程方法。企业系统 的设计者和构建者——软件工程师——熟悉静态框架,但是对动态框架却很陌生。事实上,还没有说明业务动态的框架。根据企业架构框架,这是一个需要填补的缺 口。这个框架只描述企业是如何“被设计的”,但是也会定义开发路线图和主要组件,使用它们来构建企业的支持系统。

图 4. 企业架构的业务和工程方法

我们建议根本改变我们架构和设计信息系统的方式,以一种不要求业务涉众作为主要输入的方式。我们推荐利用一个以业务实体生命周期和事件模型为中心的框架作为架构的主要输入来源。业务场景只被用来微调一个已完架构,而不是作为主要驱动力。

这种框架优先方法从一开始就说明了业务动态,而不是事后诸葛亮。它暗示被设计的企业应用是动态适应的,而不是像由今天的方法论所实现的那样是静态适应的。这种方法成数量级的减小了开发和维护软件的成本,并砍掉了与改变和维护现有系统直接相关的超过70%的IT开销。

Fig 5. 基于框架的软件解决方案开发方法

在我们建议的方法中,业务场景只被作为一个已完架构的微调,而不是主要驱动力。我们将我们的直觉、经验和技巧输入到设计过程中越晚,产生导致巨大损失的错误的可能性就越少。由涉众输入引起的需求变更会在已经建好的现有解决方案框架中处理,减少了风险和延迟。

一份Standish报告研究表明,超过1千万美元的项目,成功率只有3%。行业咨询和哈佛商学院教授Andrew McAfee表示,部署如此高成本技术(如ERP、CRM、供应链管理、电子商务和其他企业应用)组织的成功率在25% ~ 70%之间。McAfee总结说:“这些面临的问题并非是单独的,它们都是同一事情的不同例子,基本上都是使用IT改变业务过程的结果。”。最近,这些百 分比有所提高,但是对于复杂系统IT仍缺乏清晰的路线。框架优先的方法能使业务变化集成到IT实现中,并提供了业务和技术之间更清晰的转换,可以将成功率 提高接近100%。建构复杂系统的时间由几个月或几年缩短至几天。

动态操作的服务器架构 —— 忘记SOA,迎接信息装配线

90年代早期,事件几乎是每本面向对象方法论书籍中的核心角色。随着象Windows这样基于GUI操作系统的出现,GUI开发平台依靠复杂事件模型来设计和构建单个应用。但是,在客户机-服务器环境中,服务器端的事件处理总是基于一个简单得多的模型。

当基于Web的技术(如J2EE和.NET)开始替代传统的客户机-服务器应用,客户机和服务器都经历了根本的转变。客户端的富OS事件模型由 Web浏览器和原始的脚本语言代替。在服务器端,事件处理由无状态、扁平的、静态架构所替代。其方式非常类似将网页传给Web浏览器的方式。

为了模拟现实世界的需求,需要一个有状态的、层次的、动态的和分布式的架构,设计必须严重依赖数据库来存储范围广泛的各种动态信息。但是根据其定 义,关系数据库非常适合存储不常变化的数据间关系。保存动态、分布式、层次的和有状态信息要求一个不同的基础设施,它不是以关系数据库为中心的。

基于Web的技术为支持现实世界系统引入了其他挑战。当J2EE应用服务器在一个分布式环境被使用时,使用Java作为编程语言的一个最大优势完全 没有了。Java虚拟机的垃圾回收从来没有被设计成能自动清除在多实例间交换的内存对象。在这种情况下,架构师和设计师必须编排整个对象生命周期,不考虑 编程语言的能力。甚至在数据保存在数据库中时,这种相同的数据清除问题也变得非常困难。

正如我们已经看到的,一旦我们能从正常工作中分离变化,架构就能只依赖事件和生命周期进行设计和实现。围绕生命周期进行系统设计已经经历了一个世纪——它被称为装配线。

在装配线于20世纪早期引入之前,制造业的工作方式多多少少和今天面向服务架构(SOA)处理信息的方式一样。每个对于SOA服务的调用一般都被视 为一个无状态调用。为了说明以前调用的历史,每个服务必须完全实现如何处理系统内部状态。一旦需求改变,几乎所有服务也需要以成本极高的方式重新编码来改 变它们各自的实现。

图 6. 服务器架构是以事件模型为基础的

我们建议使用以事件模型和生命周期为中心的信息架构作为业务需求和系统架构的双向翻译平台。事件模型在下一级被扩展成四个基本模型:状态、分布式、层次和动态。所有这5个模型可被基础需求和架构模型中的业务或技术人员方便地解释:

  • 事件模型/生命周期—— 它是构建其他模型的基础核心。对业务用户来说,它是价值流,反映产品/服务生命周期和为客户创造价值的过程序列。对技术人员来说,同一事件序列反映了代表 业务实体对象的状态变化。最终结果是,事件模型扮演了解耦元素,大大简化了设计和实现。事件模型还扮演了另一个重要角色。因为其他四个模型是围绕事件模型 而构建的,它还扮演一个集成平台。事实上,事件模型是创造实现变更、层次和分布式组件的唯一办法。
  • 状态模型—— 对业务用户来说,这个模型扮演了企业的面板,捕获当前经营的整体状况。对技术人员来说,它是系统的整体状态,它是全部生命周期实例的当前状态,以及它们的变化之和。
  • 分布式模型 —— 对业务用户来说,这个模型捕获了其生命周期内控制产品/服务的各种组织。对技术人员来说,主实体只能基于分布式模型来控制。
  • 层次模型—— 所有业务都有代表管理层级的层次结构。所有系统设计应该在架构上反映这种控制层次。正如销售VP不能给CEO下命令一样,低层级的组件不能给高层级的组件发送执行“命令”。
  • 动态模型—— 继事件模型之后最重要的模型。业务用户使用它来捕获平时必须被处理的全部变更。如前所述,有两种变化类型:外部,如客户输入;内部,如管理决策。对技术人员来说,动态模型被翻译成一个匹配各种事件、生命周期和变化类型的插件架构。

这5个模型不仅可以被用在初始设计,对贯穿整个系统生命周期的需求变更亦有裨益。它们一起形成了自适应系统设计所缺失的框架步骤。这5个模型排除了用例作为企业架构的主输入的必要性。它们可以被翻译成一个清晰和全面的工程问题集合,与在桥梁或飞机设计中使用的方法类似。

图 7. 自适应架构是以5个模型为基础的信息架构结果

这5个模型定义了以信息变化和装配线为中心的动态业务应用通用架构。最重要的子系统是:静态模型、变更管理、虚拟装配对象和事件处理。在下一个细化层级,还有两个子系统:系统命令和控制与持久化。

这个架构还解决了在寻求一个适用于事务型工作流隐喻的通用解决方案过程中长期存在的问题,它是由Jim Gray[3]在 几十年前提出的。因为整个设计以单个事件的执行为中心,不仅可以实现“移动到下一个装配步骤”,而且也可实现“移动到前一个装配步骤”。实现需要根据用户 的输入决定前往哪个“方向”。通过将多个步骤“链接”在一起,可以使用相同的架构实现一个事务型工作流的“撤销(Undo)”操作。

动态业务应用的一个关键元素是事件处理。使用新的自适应系统信息理论,可以使用一个通用组件结构来“执行”每个事件。这个组件使用声明性编程来内嵌 业务逻辑、调用工作流引擎、调度器和业务规则引擎。这个实现不仅可以极大加速自适应系统开发,而且可以使后期改变非常容易处理,也减少了维护复杂集成的需 要。

我们建议围绕事件(操作)和事件生命周期创建一个供给控制、运营和环境的物理模型。生命周期控制器为离散事件管理装配信息。变更管理功能指导标准事件模型和个体事件内外部变更的执行。

结论

我们已经讨论了扁平、无状态、静态、客户端——服务器、基于Web的解决方案的演变方式所带来的IT架构和层次、有状态、动态、分布式业务的现实世 界之间的脱节。我们还讨论了传统工程方法为什么不能支撑能支持动态业务的自适应系统的开发。我们展示这两个问题的可能解决方案可以用一种新的模型驱动架构 方法来找到。

本文的第二部分将描述动态业务应用的可能架构,并给出一个案例研究,介绍我们概念的实际实现。

参考文献

[1] Yourdon Systems Method —— Model Driven Systems Development —— Yourdon Press, 1993

[2] Eric D. Beinhocker —— "The origin of Wealth", HBS Press Book,2006 —— 在他的新书“The origin of Wealth”中,麦肯锡公司高级顾问Eric D. Beinhocker声称,将经济视为一种静态、平衡的系统的传统观点正在经受一场彻底的反思,包括为数众多的原则。新的中心是:“复杂经济学”,其中经 济被视为一种高度动态的、不断演变、几乎无法预测的系统。这个摘录涉及在未来未知时公司如何来制定战略。

[3] Mark Whitehorn ,The Register, Interview with Jim Gray —— http://www.regdeveloper.co.uk/2006/05/30/jim_gray/

查看英文原文Beyond SOA: A New Enterprise Architecture Framework for Dynamic Business Applications

[架构]什么是软件工厂

mikel阅读(901)

前言

  Microsoft Patterns & Practices已经提供了不少“软件工厂(Software Factory)”,例如Smart Client Software FactoryWeb Service Software FactoryMobile Client Software Factory。而在CodePlex上也已经有了Microsoft P & P Team正在开发的下一代产品:Web Client Software Factory。这是一个非常有价值,非常值得关注的项目,目前正在以Weekly Drop的形式发布,按照计划将会在年底发布。在Terry Lee和我都曾经对它进行过介绍。

  那么什么是“软件工厂”呢?它的作用又是什么呢?Jezz Santos在写了数篇有关这方面非常精彩的文章,他本人已经同意我将其文章进行翻译。我将陆续将它们翻译成中文,帮助大家和我自己理解一些概念。

原文信息

  原文《FAQ – What is a Software Factory?》公布在Jezz Santos的博客上,版权归作者所有。
 

正文翻译

  什么是“软件工厂”?这个问题经常能够引发下面的疑问:

  如何给出软件工厂的定义?紧接着考虑下面的问题:我创建了一个命令行程序/一个指导性的包(Package)/一段脚本用于生成一些有用的组件 – 请您作出选择,它们也是软件工厂吗?

  想用三言两语就给出清楚定义还真不是一件容易的事情。

背景

  事实上这并不是个足够完整的问题,大多数人也正有这样的疑问,而且他们正在通过一些已经做好的东西或者重新去理解它们的区别,来设法搞清楚自己是否已经有了一个“工厂”或者“工厂”对他们来说还是个新事物。

解答

  让我们先从“软件工厂”的官方定义开始谈起,然后我会尝试着使用更简单的词汇来解释它,并且使用一些示例来给出这些定义的衍生,希望能帮助您理解这些。

  您能在这里找到一个官方而泛泛的定义,但是我想从JackKeth的那本有关软件工厂的书中所使用的那段短小些的定义开始。您也能够在我们的术语表中找到另一些定义。

软件工厂是 使用一个基于软件工厂模式(Software Factory Schema)的软件工厂模版(Software Factory Template)来配置外部工具,过程和内容的一条产品线。通过适配(Adapting),装配(Assembling)和配置一些框架化的组件,能够 自动化地对一个典型架构的产品进行开发和维护变化的工作。”

  呃……好吧(“咕嘟”——咽了一下口水), 这是一个学院派定义,我们来将它进行一点小小的延伸:首先,“软件工厂”的基本元素是一条使用一系列的工具(比如编辑器,代码模版,领域专用语言,命令行 工具等等)创建出来的“产品线”。这些工具会是用一个被称为“工厂模版”的东西来配置普遍适用的,能够扩展的开发工具(就像Visual Studio)。工厂模版实际上只是“工厂规范”的一个物理实现(例如,一个工厂模版包含了工具,指导和这些工具创建和配置一些东西的蓝本)。接着,则会 通过组装一些必须的组件,把这些工厂创建出来的不同产品的开发和维护过程进行自动化操作——理想情况下,这个过程会复用那些作为产品基础而存在的框架。

  好吧,这里最关键的一点是产品线工厂规范,它的工厂模版以及一个产品。在我看来,如果您有了所有这些,您就已经基本上接近于有了一个工厂了,因为剩下的玩意儿都是通过这些东西来得到的。

  “框架”也是非常重要的东西,因为有了它, 您就已经在“为产品线上的产品定义变量”这个过程中迈出了一大步,大多数的工作它已经帮你完成了。请记住,您不应该为一个您还没有解决的方案创建一个工 厂,因此,创建一个工厂最基本的前提是:您已经有了对一些解决方案进行自动化操作的资本。

[当Visual Studio团队发布了一些能够帮助您自定义软件工厂的工具,那么微软对于这些术语的定义会变得更为具体,而且我猜想,如果要完全符合这个具体的工厂模 版,您只能使用被微软认可的软件工厂。但是就目前来说,您任何可以使用当前的工具和一些您自己的“创新”来创建符合上述定义的软件工厂。]

产品

  让我们先从产品谈起,首先搞清楚一点:一个产品是一个特定的工厂创建的产物。

“一个产品是一个工厂生产线的最终产物”

  千万不要将“生产线(production line)”和“产品线(product line)”混淆起来。

  现在,一个产品并不需要真正的完成,结束,包装成一个像“Microsoft Word”这样的东西,虽然可能大多数人听到“产品”这个词的第一反应是这个。这个单词的含义只是描述一个工厂的产出。

  例如,一个汽车引擎制造商生产出了汽车引擎,这就是它的“产品”,然后把引擎卖给其它的工厂,让它们将这些引擎组装进一辆汽车。一个汽车引擎依旧属于一个引擎工厂的“产品”。

  所以,所有的工厂会建造一个有用的产品,这个产品可能会被组装进入一个更大的产品,当然也有可能不会。

  工厂会为这个产品定义一个模型,这就是这个产品的“模式(schema)”,它包含了产品的各个部分和它们的变量。这个模型为用户提供了一个独立创建,配置或者维护产品各部分的方法。

工厂模式(Factory Schema)与工厂模版(Factory Template)

  我们已经花了不少功夫定义了工厂模式(Factory Schema),所以我不打算在这里再完全重复一遍。

  不过我们在这里这么说已经足够了:“工厂模式”是产品(和它的变量)以及它的各种配置的蓝图——也就是工厂产物的蓝图。它不只定义了工厂该建造那些东西,也包括建造这些东西方式,建造时所用的“零件”,以及在建造时所使用的工具。

  顺便提一下,“工厂模版(Factory Template)”则是指工具、运行时、文档和框架等其它作为您的工厂的的组成部分一起发布的那些东西——例如一起打包在一个MSI安装文件中。

产品线

  那么现在就谈一下产品线——这到底是什么?这可不是指“生产线”。

产品线,由工厂产物的变量组成。

  好,为了真正对开发有用,工厂需要能够创建产品的多个实例(我们把其中的一个叫做一个“产品变量”)。更准确的说,一个产品“变量”就是每一个您生产出的实例,而不是产品的实际类型。一个工厂能够定义多种产品的“类型”(每一个对应了产品的一个可变的方面)。

  因此,您的产品线定义了您工厂的解决方案领域

[您能够在这里得到有关一个产品可变性以及其变量(是什么?应该如何使用?)更深入的讨论。]

 

  那么,您的一个命令行程序/一个指导性的包(Package)/一段脚本是一个软件工厂吗?

[模式]软件工厂

mikel阅读(839)

Gunther Lenz是微软的一名架构师,Christoph Wienands是在西门子工作的一名软件工程师,两人担当起了一个项目,目标是评估以Microsoft Visual Studio 2005 Domain Specific Languages工具为基础建立的软件工厂(Software Factory)的优势

虽然对于目前基于文本的软件开发工作来说,重用增加、抽象层次提高、自动化水平提高这些都是显而易见的好处,但还不足以向管理层及其他利益相关者证明先期投入的必要性。因此我们着手寻找定量的数据,以图清楚地在商业上确立这种范型。

该分析的目标是在框架及应用程序开发领域识别出自动化和重用的机会。为此作者开发了一个软件工厂模板(Software Factory Template):

软件工厂模板是在Software Factory Schema的基础上实现的。我们提供了多个T4模板——有工件生成、向导和DSL——全都包含在安装包里。这些模板给开发者提供了额外的工具和上下文敏感的自动化机制。

他们的项目分为两个部分:

  • 用DSL生成框架性的C#工件
  • 通过指导(guidance)和自动化为应用程序开发者提供支持

经过初步研究,他们发现:

对于开发者来说,以前定义加上使用要输入320行的代码,而现在只需要输入几个字符串,然后决定几个选项就可以了。最终不但节省了时间,而且质量也提高了——因为只能在合理的选项中选择,而且在工件生成之前还会对输入进行验证。

总而言之,结论就是:

DSL开发成10倍地提高生产率,投资收益率超过100%。

对于指导包(guidance package),即使在最低投入的情况下也可以达到超过300%的投资收益率。

作者们计划在未来解决一些更复杂的问题:

  • 如何将此方法扩展到更广阔的领域?
  • 如何让工具适应更复杂的实现?
  • 能够节省多少维护工作?
  • 如何处理DSL元模型及模型的演进?

查看英文原文:Making the Business Case for Software Factories

[服务]豆瓣的API服务使用指南

mikel阅读(2340)

豆瓣 API 使用指南

豆瓣API是豆瓣为第三方开发人员提供的编程接口。利用豆瓣API,你可以在你的网站或程序中使用豆瓣的数据和功能。 目前的豆瓣API支持的功能包括:

  • 搜索并查看书籍、电影、音乐信息
  • 搜索并查看用户信息
  • 查看用户收藏
  • 添加、更新、删除用户收藏
  • 查看评论
  • 发布、修改、删除评论

在未来我们会支持更多的功能,例如查看、增删友邻.

本文档为需要快速了解豆瓣API的用户提供一个概览, 更为完整的豆瓣API信息请参阅 豆瓣API 参考手册. 现在可以使用Python 或者Javascript客户端进行开发,欢迎爱好者提供其他语言的客户端。

如果你编写了一个有趣的API应用,欢迎到API小组发布, 另外也欢迎到API小组参与豆瓣API的讨论,提出你对豆瓣API各种意见和建议。

Python客户端: http://code.google.com/p/douban-python/
Java客户端: http://code.google.com/p/douban-java/
ActionScript客户端: http://code.google.com/p/douhua/ (Meaglith Ma贡献)

目录

API Key

为了保护豆瓣用户的数据;防止API被滥用或恶意使用,豆瓣要求每个API的使用者申请一个API Key, 而每个API Key唯一标识一个API使用者. 你可以在申请页面获得API Key, 在页面中填写必要信息后提交,你会得到你的API Key,例如

c4579586f41a90372f762cb65c78be5d

在之后的API使用过程中,你需要在请求中包括apikey参数,例如

http://api.douban.com/people/1345767?apikey={apikey}

注:如果只是想试验一下API,豆瓣也允许在不申请API Key的情况下进行API调用。不过在这种情况下,API调用被限制为每分钟请求不超过10次。使用API Key时,对访问的限制较为宽松,为每分钟40次,超过限制的话会被封禁(包括豆瓣主站的访问)。

快速入门

示例

下面通过一个简单的示例来演示豆瓣API的使用.

这个示例中展示了使用API获得ID为1220562的书的信息, 请求的url如下(注意将{yourapikey}替换为你的API Key)

http://api.douban.com/book/subject/1220562?apikey={yourkeyapi}

返回值为XML文档

<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:gd="http://schemas.google.com/g/2005"
xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/"
xmlns:db="http://www.douban.com/xmlns/">
<category scheme="http://www.douban.com/2007#kind"
term="http://www.douban.com/2007#book" />
<db:tag count="20" name="片山恭一" />
<db:tag count="14" name="日本" />
<db:tag count="10" name="小说" />
<db:tag count="8" name="日本文学" />
<db:tag count="4" name="爱情" />
<title>满月之夜白鲸现</title>
<author>
<name>(日)片山恭一</name>
</author>
<content>
冷静地想一想吧!公寓的一个房间里只有两上人,连被褥都铺好了,理应是犯
错误的时候,我为什么却这么拘谨?一直胆小的毛病又犯了。事到如今,不要
说上床,就连接吻也还差得很远。这就是横亘在男人和女人之间的又深又暗的
河流吗?
如果有可能,我希望把手伸进她的心里,把她内心所有的东西都掏出来。她对
我究竟是一种什么感觉呢?我在她的心昊确实占有一席之地吗?抑或只是她生
命中的匆匆过客?
</content>
<link rel="self" href="http://api.douban.com/book/subject/1220562" />
<link rel="alternate" href="http://www.douban.com/subject/1220562/" />
<link rel="image" href="http://otho.douban.com/spic/s1747553.jpg" />
<db:attribute name="author">(日)片山恭一</db:attribute>
<db:attribute name="isbn10">7543632608</db:attribute>
<db:attribute name="isbn13">9787543632608</db:attribute>
<db:attribute name="pages">180</db:attribute>
<db:attribute name="tranlator">豫人</db:attribute>
<db:attribute name="price">18.00</db:attribute>
<db:attribute name="publisher">青岛出版社</db:attribute>
<db:attribute name="binding">平装(无盘)</db:attribute>
<db:attribute name="author-intro">
片山恭一,1959年生于日本爱媛县,九州大学农学系农业经济学专业毕业。
学生时代通读了包括夏目漱石和大江健三郎在内的日本近现代文学全集,
同时读了笛卡尔、莱布尼茨到结构主义的欧洲近现代哲学。也读了马克思。
学士论文写的是马克思,硕士论文写的是恩格斯。二十二三岁开始创作小说。
代表作有《在世界中心呼唤爱》、《世界在你不知道的地方运转》、《气息》、
《别相信约翰·列侬》、《满月之夜白鲸现》、《空镜头》以及新作
《倘若我在彼岸》、《雨天的海豚们》等。
</db:attribute>
<id>http://api.douban.com/book/subject/1220562</id>
<gd:rating min="1" numRaters="39" average="3.69" max="5" />
</entry>

通过请求中包括alt参数,你可以改变返回值的格式。 目前支持的alt参数值包括:

  • atom (默认)
  • json

通过将alt设置为json来获得json格式的返回值:

{"category":{
"@scheme":"http://www.douban.com/2007#kind",
"@term":"http://www.douban.com/2007#book"},
"db:tag":[
{"@count":20,"@name":"片山恭一"},
{"@count":14,"@name":"日本"},
{"@count":10,"@name":"小说"},
{"@count":8,"@name":"日本文学"},
{"@count":4,"@name":"爱情"}
],
"title":{"$t":"满月之夜白鲸现"},
"author":[
{"name":{"$t":"(日)片山恭一"}}
],
"content":{"$t":"冷静地想一想吧!公寓的一个房间里只有两上人,连被褥都铺
好了,理应是犯错误的时候,我为什么却这么拘谨?一直胆小的毛病又犯了。事到
如今,不要说上床,就连接吻也还差得很远。这就是横亘在男人和女人之间的又深
又暗的河流吗?\n    如果有可能,我希望把手伸进她的心里,把她内心所有的东
西都掏出来。她对我究竟是一种什么感觉呢?我在她的心昊确实占有一席之地吗?
抑或只是她生命中的匆匆过客?"},
"link":[
{"@rel":"self","@href":"http://api.douban.com/book/subject/1220562"},
{"@rel":"alternate","@href":"http://www.douban.com/subject/1220562/"},
{"@rel":"image","@href":"http://otho.douban.com/spic/s1747553.jpg"}
],
"db:attribute":[
{"$t":"(日)片山恭一","@name":"author"},
{"$t":"7543632608","@name":"isbn10"},
{"$t":"9787543632608","@name":"isbn13"},
{"$t":"180","@name":"pages"},
{"$t":"豫人","@name":"tranlator"},
{"$t":"18.00","@name":"price"},
{"$t":"青岛出版社","@name":"publisher"},
{"$t":"平装(无盘)","@name":"binding"},
{"$t":"片山恭一,1959年生于日本爱媛县,九州大学农学系农业经济学专业
毕业。学生时代通读了包括夏目漱石和大江健三郎在内的日本近现代文学全集,
同时读了笛卡尔、莱布尼茨到结构主义的欧洲近现代哲学。也读了马克思。
学士论文写的是马克思,硕士论文写的是恩格斯。二十二三岁开始创作小说。
代表作有《在世界中心呼唤爱》、《世界在你不知道的地方运转》、《气息》、
《别相信约翰·列侬》、《满月之夜白鲸现》、《空镜头》以及新作《倘若我在
彼岸》、《雨天的海豚们》等。","@name":"author-intro"}
],
"id":{"$t":"http://api.douban.com/book/subject/1220562"},
"gd:rating":{"@min":1,"@numRaters":39,"@average":"3.69","@max":5}
}

JavaScript 支持

对于JavaScript开发人员,豆瓣API提供一种更简单的方式可以直接在HTML页面中使用API, 下面给出这种使用方式的简单示例。

首先你需要在HTML页面中如下script标签:

<script type="text/javascript" src="http://www.douban.com/js/api.js?v=2" />

之后你需要在JavaScript中设置好你的apikey:

DOUBAN.apikey = 'c4579586f41a90372f762cb65c78be5d'

而后你就可以调用豆瓣API,其中通过定义callback函数来操作返回的JSON数据:

DOUBAN.getMovie({
id:'2340927',
callback:function(movie){
var title = movie.title['$t'];
...
}
})

此外,豆瓣也提供了解析函数来帮助你更容易地使用JSON格式的返回值。使用豆瓣提供的解析函数,你需要在页面中添加如下的script标签:

<script type="text/javascript" src="http://www.douban.com/js/api-parser.js?v=1"></script>

接下来你就可以使用豆瓣提供的解析函数来处理返回值,例如:

var book = DOUBAN.parseSubject(result)

解析函数返回更容易使用的javascript对象,例如你可以这样得到书的封面图片:

book.link.image

下面HTML页面使用API获得ID为2340927电影的信息并展示在页面上(注意将{yourapikey}替换为你的API Key)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML xmlns="http://www.w3.org/1999/xhtml">
<HEAD>
<TITLE></TITLE>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<style>
body {padding:0;margin: 0;background: #FEFEFE;}
body,td,th { font: 12px Arial, Helvetica, sans-serif; line-height: 150%; }
span.title {
margin:5px;
}
</style>
<script type="text/javascript" src="http://www.douban.com/js/api.js?v=2"></script>
<script type="text/javascript" src="http://www.douban.com/js/api-parser.js?v=1"></script>
<BODY>
</BODY>
<script>
DOUBAN.apikey = {yourapikey}
DOUBAN.getMovie({
id:'2340927',
callback:function(re){
var subj = DOUBAN.parseSubject(re)
var tl = subj.title ? subj.title : "";
var author = subj.author ? subj.author : "";
var di = subj.attribute.director ? subj.attribute.director.join(' / ') : "";
var tmp = "<img src="+subj.link.image+" style='margin:10px;float:left'>";
tmp += "<div>Title : <a href="+subj.link.alternate+" target='_blank'>"+tl+"</a></div>";
if (subj.attribute.author) tmp += "<div>Authors : "+(subj.attribute.author.join(' / '))+"</div>";
if (subj.attribute.director) tmp += "<div>Director : "+(subj.attribute.director.join(' / '))+"</div>";
if (subj.attribute.cast) tmp += "<div>Casts : "+(subj.attribute.cast.join(' / '))+"</div>";
if (subj.attribute.aka) tmp += "<div>A.k.a : "+(subj.attribute.aka.join(' <br/>   '))+"</div>";
if (subj.attribute.language) tmp += "<div>Language : "+(subj.attribute.language.join(' / '))+"</div>";
if (subj.attribute.country) tmp += "<div>Country : "+(subj.attribute.country.join(' / '))+"</div>";
if (subj.rating.average)
tmp +="<div>Rating: "+subj.rating.average+" / "+subj.rating.numRaters+decodeURI("%E4%BA%BA")+ "</div>"
tmp += "<p>"+(subj.summary ? subj.summary : "")+"</p>";
document.body.innerHTML = tmp;
}
})
</script>
</HTML>

注:实现上,豆瓣API使用 JSONP 方式来支持跨域调用API 因此你也可以使用自己熟悉的javascript库来调用JSONP风格的豆瓣API. 此时,你需要将alt设置为xd同时提供callback参数。

例如使用JQuery,前面的例子则可以写为

$.getJSON("http://api.douban.com/movie/subject/2340927?alt=xd&callback=?", function(movie){
var title = movie.title['$t'];
...
});

[问题]Petshop4.0注册提示安全密码问题

mikel阅读(1197)

Petshop4.0 中注册时出现Please enter a more secure password.的解决方法:
在网上找到答案:

查看C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config
中membership/providers/add 属性inRequiredNonalphanumericCharacters="1"

知道密码中至少有一个非alpha字符,例如要出现一个@之类的

这 个主要是machine.config配置文件下面的<membership…><providers…> minRequiredPasswordLength="7",minRequiredNonalphanumericCharacters="1" 这两个项要设置
第一项要求了至少密码长度为7,第二项是要求了至少一个非字母数字字符.如果不更改设置,则在密码中包含以下字符"!@#$%^&*()"等中的一个可以解决。或者在web.config文件中更改设置。


<connectionStrings>
  
<add name="MySQLConnection" connectionString="Data Source=MySQLServer;Initial Catalog=aspnetdb;Integrated Security=SSPI;" />
</connectionStrings>
<system.web>
..
<membership defaultProvider="SQLProvider" userIsOnlineTimeWindow="15">
    
<providers>
      
<clear />
      
<add 
        name
="SQLProvider" 
        type
="System.Web.Security.SqlMembershipProvider" 
        connectionStringName
="MySqlConnection"
        applicationName
="MyApplication"
        minRequiredNonalphanumericCharacters
="0" 
        minRequiredPasswordLength
="6" 
        passwordStrengthRegularExpression
="" />
    
</providers>
</membership>

[资源]What is SWFObject 2.0?

mikel阅读(623)

What is SWFObject 2.0?

SWFObject 2.0:

Why should you use SWFObject 2.0?

SWFObject 2.0:

The A List Apart article Flash Embedding Cage Match [ http://www.alistapart.com/articles/flashembedcagematch/ ] describes the full rationale behind SWFObject 2.0.

Why does SWFObject 2.0 use JavaScript?

SWFObject 2.0 primarily uses JavaScript to overcome issues that cannot be solved by markup alone; it:

Should I use the static or dynamic publishing method?

SWFObject 2.0 offers two distinct methods to embed Flash Player content:

  1. The static publishing method embeds both Flash content and alternative content using standards compliant markup, and uses JavaScript to resolve the issues that markup alone cannot solve
  2. The dynamic publishing method is based on marked up alternative content and uses JavaScript to replace this content with Flash content if the minimal Flash Player version is installed and enough JavaScript support is available (similar like previous versions of SWFObject and UFO)

The advantages of the static publishing method are:

  1. The actual authoring of standards compliant markup is promoted
  2. The mechanism of embedding Flash content does not rely on a scripting language, so your Flash content can reach a significant bigger audience:

The advantages of the dynamic publishing method are:

  1. It avoids click-to-activate mechanisms to activate active content in Internet Explorer 6/7 and Opera 9+. Please note that Microsoft is currently phasing out all active content from its Internet Explorer browsers [ http://www.swffix.org/devblog/?p=19 ]
  2. It integrates very well with scripted applications

How to embed Flash Player content using SWFObject 2.0 static publishing

STEP 1: Embed both Flash content and alternative content using standards compliant markup

SWFObject's base markup uses the nested-objects method (with proprietary Internet Explorer conditional comments) [ http://www.alistapart.com/articles/flashembedcagematch/ ] to ensure the most optimal cross-browser support by means of markup only, while being standards compliant and supporting alternative content [ http://www.swffix.org/testsuite/ ]:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 - step 1</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  </head>
  <body>
    <div>
      <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="780" height="420">
        <param name="movie" value="myContent.swf" />
        <!--[if !IE]>-->
        <object type="application/x-shockwave-flash" data="myContent.swf" width="780" height="420">
        <!--<![endif]-->
          <p>Alternative content</p>
        <!--[if !IE]>-->
        </object>
        <!--<![endif]-->
      </object>
    </div>
  </body>
</html>

NOTE: The nested-objects method requires a double object definition (the outer object targeting Internet Explorer and the inner object targeting all other browsers), so you need to define your object attributes and nested param elements twice.

Required attributes:

  • classid (outer object element only, value is always clsid:D27CDB6E-AE6D-11cf-96B8-444553540000)
  • type (inner object element only, value is always application/x-shockwave-flash)
  • data (inner object element only, defines the URL of a SWF)
  • width (both object elements, defines the width of a SWF)
  • height (both object elements, defines the height of a SWF)

Required param element:

  • movie (outer object element only, defines the URL of a SWF)

NOTE: We advise not to use the codebase attribute to point to the URL of the Flash plugin installer on Adobe's servers, because this is illegal according to the specifications which restrict its access to the domain of the current document only. We recommend the use of alternative content with a subtle message that a user can have a richer experience by downloading the Flash plugin instead.

How can you use HTML to configure your Flash content?

You can add the following often-used optional attributes [ http://www.w3schools.com/tags/tag_object.asp ] to the object element:

  • id
  • name
  • class
  • align

You can use the following optional Flash specific param elements [ http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=tn_12701 ]:

Why should you use alternative content?

The object element allows you to nest alternative content inside of it, which will be displayed if Flash is not installed or supported. This content will also be picked up by search engines, making it a great tool for creating search-engine-friendly content. Summarizing, you should use alternative content when you like to create content that is accessible for people who browse the Web without plugins [ http://www.adobe.com/devnet/flash/articles/progressive_enhancement_03.html ], create search-engine-friendly content [ http://www.adobe.com/devnet/flash/articles/progressive_enhancement_04.html ] or tell visitors that they can have a richer user experience by downloading the Flash plug-in.

STEP 2: Include the SWFObject JavaScript library in the head of your HTML page

The SWFObject library consists of one external JavaScript file. SWFObject will be executed as soon as it is read and will perform all DOM manipulations as soon as the DOM is loaded – for all browsers that support this, like IE, Firefox, Safari and Opera 9+ – or otherwise as soon as the onload event fires:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 - step 2</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <script type="text/javascript" src="swfobject.js"></script>
  </head>
  <body>
    <div>
      <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="780" height="420">
        <param name="movie" value="myContent.swf" />
        <!--[if !IE]>-->
        <object type="application/x-shockwave-flash" data="myContent.swf" width="780" height="420">
        <!--<![endif]-->
          <p>Alternative content</p>
        <!--[if !IE]>-->
        </object>
        <!--<![endif]-->
      </object>
    </div>
  </body>
</html>

STEP 3: Register your Flash content with the SWFObject library and tell SWFObject what to do with it

First add a unique id to the outer object tag that defines your Flash content. Second add the swfobject.registerObject method:

  1. The first argument (String, required) specifies the id used in the markup.
  2. The second argument (String, required) specifies the Flash player version your content is published for. It activates the Flash version detection for a SWF to determine whether to show Flash content or force alternative content by doing a DOM manipulation. While Flash version numbers normally consist of major.minor.release.build, SWFObject only looks at the first 3 numbers, so both "WIN 9,0,18,0" (IE) or "Shockwave Flash 9 r18" (all other browsers) will translate to "9.0.18".
  3. The third argument (String, optional) can be used to activate Adobe express install [ http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75 ] and specifies the URL of your express install SWF file. Express install displays a standardized Flash plugin download dialog instead of your Flash content when the required plugin version is not available. A default expressInstall.swf file is packaged with the project. It also contains the corresponding expressInstall.fla and AS files (in the SRC directory) to let you create your own custom express install experience. Please note that express install will only fire once (the first time that it is invoked), that it is only supported by Flash Player 6.0.65 or higher on Win or Mac platforms, and that it requires a minimal SWF size of 310x137px.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 - step 3</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <script type="text/javascript" src="swfobject.js"></script>
    <script type="text/javascript">
    swfobject.registerObject("myId", "9.0.0", "expressInstall.swf");
    </script>
  </head>
  <body>
    <div>
      <object id="myId" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="780" height="420">
        <param name="movie" value="myContent.swf" />
        <!--[if !IE]>-->
        <object type="application/x-shockwave-flash" data="myContent.swf" width="780" height="420">
        <!--<![endif]-->
          <p>Alternative content</p>
        <!--[if !IE]>-->
        </object>
        <!--<![endif]-->
      </object>
    </div>
  </body>
</html>

TIPS

How to embed Flash Player content using SWFObject 2.0 dynamic publishing

STEP 1: Create alternative content using standards compliant markup

SWFObject's dynamic embed method follows the principle of progressive enhancement [ http://www.adobe.com/devnet/flash/articles/progressive_enhancement.html ] and replaces alternative HTML content for Flash content when enough JavaScript and Flash plug-in support is available. First define your alternative content and label it with an id:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 dynamic embed - step 1</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  </head>
  <body>
   
    <div id="myContent">
      <p>Alternative content</p>
    </div>
   
  </body>
</html>

STEP 2: Include the SWFObject JavaScript library in the head of your HTML page

The SWFObject library consists of one external JavaScript file. SWFObject will be executed as soon as it is read and will perform all DOM manipulations as soon as the DOM is loaded – for all browsers that support this, like IE, Firefox, Safari and Opera 9+ – or otherwise as soon as the onload event fires:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 dynamic embed - step 2</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
 
    <script type="text/javascript" src="swfobject.js"></script>
  </head>
  <body>
    <div id="myContent">
      <p>Alternative content</p>
    </div>
  </body>
</html>

STEP 3: Embed your SWF with JavaScript

swfobject.embedSWF(swfUrl, id, width, height, version, expressInstallSwfurl, flashvars, params, attributes) has five required and four optional arguments:

  1. swfUrl (String, required) specifies the URL of your SWF
  2. id (String, required) specifies the id of the HTML element (containing your alternative content) you would like to have replaced by your Flash content
  3. width (String, required) specifies the width of your SWF
  4. height (String, required) specifies the height of your SWF
  5. version (String, required) specifies the Flash player version your SWF is published for (format is: "major.minor.release")
  6. expressInstallSwfurl (String, optional) specifies the URL of your express install SWF and activates Adobe express install [ http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75 ]. Please note that express install will only fire once (the first time that it is invoked), that it is only supported by Flash Player 6.0.65 or higher on Win or Mac platforms, and that it requires a minimal SWF size of 310x137px.
  7. flashvars (Object, optional) specifies your flashvars with name:value pairs
  8. params (Object, optional) specifies your nested object element params with name:value pairs
  9. attributes (Object, optional) specifies your object's attributes with name:value pairs

NOTE: You can omit the optional parameters, as long as you don't break the parameter order. If you don't want to use an optional parameter, but would like to use a following optional parameter, you can simply pass false as its value. For the flashvars, params and attributes JavaScript Objects, you can also pass an empty object instead: {}.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
  <head>
    <title>SWFObject v2.0 dynamic embed - step 3</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <script type="text/javascript" src="swfobject.js"></script>
   
    <script type="text/javascript">
    swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0");
    </script>
  </head>
  <body>
    <div id="myContent">
      <p>Alternative content</p>
    </div>
  </body>
</html>

How can you configure your Flash content?

You can add the following often-used optional attributes [ http://www.w3schools.com/tags/tag_object.asp ] to the object element:

  • id (NOTE: when undefined, the object element automatically inherits the id from the alternative content container element)
  • name
  • styleclass (used instead of class, because this is also an ECMA4 reserved keyword)
  • align

You can use the following optional Flash specific param elements [ http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=tn_12701 ]:

How do you use JavaScript Objects to define your flashvars, params and object's attributes?

You can best define JavaScript Objects using the Object literal notation, which looks like:

<script type="text/javascript">
var flashvars = {};
var params = {};
var attributes = {};
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

You can add your name:value pairs while you define an object (note: please make sure not to put a comma behind the last name:value pair inside an object)

<script type="text/javascript">
var flashvars = {
  name1: "hello",
  name2: "world",
  name3: "foobar"
};
var params = {
  menu: "false"
};
var attributes = {
  id: "myDynamicContent",
  name: "myDynamicContent"
};
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

Or add properties and values after its creation by using a dot notation:

<script type="text/javascript">
var flashvars = {};
flashvars.name1 = "hello";
flashvars.name2 = "world";
flashvars.name3 = "foobar";
var params = {};
params.menu = "false";
var attributes = {};
attributes.id = "myDynamicContent";
attributes.name = "myDynamicContent";
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

Which can also be written as (the less readable shorthand version for the die-hard scripter who love one-liners):

<script type="text/javascript">
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", {name1:"hello",name2:"world",name3:"foobar"}, {menu:"false"}, {id:"myDynamicContent",name:"myDynamicContent"});
</script>

If you don't want to use an argument you can define it as false or as an empty Object:

<script type="text/javascript">
var flashvars = false;
var params = {};
var attributes = {
  id: "myDynamicContent",
  name: "myDynamicContent"
};
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

The flashvars Object is a shorthand notation that is there for your ease of use. You could potentially ignore it and specify your flashvars via the params Object:

<script type="text/javascript">
var flashvars = false;
var params = {
  menu: "false",
  flashvars: "name1=hello&name2=world&name3=foobar"
};
var attributes = {
  id: "myDynamicContent",
  name: "myDynamicContent"
};
swfobject.embedSWF("myContent.swf", "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>

TIPS

SWFObject 1.5 to SWFObject 2.0 migration tips

  1. SWFObject 2.0 is NOT backwards compatible with SWFObject 1.5
  2. It is now preferred to insert all script blocks in the head of your HTML page
  3. The library itself is now written in lowercase: swfobject instead of SWFObject
  4. Methods can only be accessed via the library (instead via a SWFObject instance in SWFObject 1.5)
  5. The API is entirely different and more elaborate: [ http://code.google.com/p/swfobject/wiki/SWFObject_2_0_api_javascript_dev ]
  6. SWFObject 2.0 replaces your entire alternative HTML content block, including the referenced HTML container element, for Flash content when enough JavaScript and Flash support is available, while SWFObject 1.5 only replaces the content inside the referenced HTML container. When you don't specify an id attribute, the object element will automatically inherit the id of the HTML container element of your alternative content.

UFO to SWFObject 2.0 migration tips

  1. SWFObject 2.0 replaces your entire alternative HTML content block, including the referenced HTML container element, for Flash content when enough JavaScript and Flash support is available, while UFO only replaces the content inside the referenced HTML container. When you don't specify an id attribute, the object element will automatically inherit the id of the HTML container element of your alternative content.
  2. UFO's setcontainercss feature has not been incorporated in SWFObject 2.0, however it can easily be replicated by using the SWFObject 2.0 API, see: swfobject.createCSS(selStr, declStr) in [ http://code.google.com/p/swfobject/wiki/SWFObject_2_0_api_javascript_dev ]

Does SWFObject 2.0 support MIME type application/xhtml+xml?

SWFObject does NOT support XML MIME types, which is a design decision.

There are a number of reasons why we are not supporting this:

COMMENTS POLICY

We will try to keep this page lean and mean, because it is used by many people. For this purpose we will periodically review all comments and remove all comments that are outdated or irrelevant to this documentation page itself.

If you have any questions/comments about SWFObject 2.0 or have problems with an implementation:

  1. Please make sure you have read our FAQ [ http://code.google.com/p/swfobject/wiki/SWFObject_2_0_faq_web_authors ]
  2. Use the SWFObject 2.0 discussion group [ http://groups.google.com/group/swfobject ]

If you find any bugs or want to request a future enhancement, you can fill in an issue report on the SWFObject 2.0 issues page [ http://code.google.com/p/swfobject/issues/list ]

[教程]Live Camera Previews in Android

mikel阅读(802)

This code replaces an earlier version which is still available

The Android SDK provided by Google doesn't provide any camera emulation beyond a stand-in animation (see below). Since Google haven't yet provided a working implementation (or even a date by which one will be available), I'm publishing the source code for a set of temporary classes that I wrote to overcome this limitation. It's the first code I wrote on the Android platform, and it was written in haste, though it has functioned very well for me.

The code is public domain. I make no warranty as to its fitness for any particular purpose.

The code consists of:

  • CameraSource
    A light interface that protects client code from the choice of camera.
  • GenuineCamera
    A CameraSource implementation that uses the device's camera.
  • HttpCamera
    A CameraSource implementation that GETs images over an HTTP connection.
  • SocketCamera
    A CameraSource implementation that obtains images directly over a TCP/IP connection.
  • BitmapCamera
    A CameraSource implementation that uses a supplied bitmap.
  • WebcamBroadcaster
    A small Java application that uses JMF to broadcast captured stills over the network.

Results

When drawing the output of the genuine camera to screen, you will see something that looks like this:

Device's Camera preview output.

When drawing the output of a remote camera that is obtaining frames from a running webcam broadcaster you would see this (if you were stood over my desk).

Still obtained from a webcam broadcaster.

To save myself more time, I chose to produce a small settings configuration activity too (the code for which is not included).

A simple configuration activity for the camera settings.

Usage

Using a camera source is very simple:

CameraSource cs = new SocketCamera("192.168.0.100", 9889, 320, 240, true); if (!cs.open()) { /* deal with failure to obtain camera */ } while(/*some condition*/) { cs.capture(canvas) //capture the frame onto the canvas } cs.close();

The HttpCamera implementation should be able to obtain stills from any HTTP serving webcam or webcam software. At present I am using WebCam2000 which I run under Windows XP.

Fabian Necci kindly emailed me to let me know that he has successfully used this code on a MacBook using EvoCam to publish JPEG frames to an internal web server. Other software should be available on other systems.

Torben Vesterager has used the code with his MacBook Pro laptop which has Apple's own iSight built-in. He reports that the camera only supports YUVFormats and so had to change the code in the WebcamBroadcaster to use YUVFormat instead of RGBFormat.

Jeffrey Sharkey has used Gentoo Linux with a Logitech QuickCam express using the WebcamBroadcaster and the Linux-native JMF library. He followed this by using DV4Linux to get JMF to recognize his firewire MiniDV camera. This gave him much clearer pictures in Android; he wrapped his JMF calls using the dv4lstart utility:

dv4lstart jmfinit dv4lstart java WebcamBroadcaster

If you successfully use this code on a platform other than those listed above, or have used other webcam software, please let me know so that I can include it in this documentation for the benefit of others.

The SocketCamera implementation relies on a WebcamBroadcaster to be serving webcam stills from the address & port specified in its constructor.

To run a WebcamBroadcaster you will need JMF installed and you may need to supply the library location to the JVM when you run the application (this depends on how you install it). For example, on my machine (currently Windows XP) I use:

java "-Djava.library.path=C:\Program Files\JMF2.1.1e\lib" WebcamBroadcaster

You can pass the following combination of parameters to the application, all of which are strictly positive integers (all dimensions in pixels):

  • WebcamBroadcaster port
  • WebcamBroadcaster width height
  • WebcamBroadcaster width height port

Alternatively, you may provide no parameters, in which case the defaults are width: 320, height: 240 and port: 9889.

Notes

  • I am not able to provide support/advice relating to JMF. Sorry, but the library is old and the documentation stale. I am using it here because its the quickest option, not necessarily the best. You can reimplement the WebcamBroadcaster application using any language/library you choose, so long as it emulates the extremely simple behaviour of the WebcamBroadcaster class. For an easy life I recommend using the HttpCamera implementation.
  • The SocketCamera implementation can be expected to outperform the HttpCamera implementation significantly.
  • Obviously performance is poor, every frame needs to be compressed, sent over a network and then decompressed. This is not a useful long term implementation. Nevertheless, performance isn't so bad that the code is unusable. On my machine, capturing a frame using SocketCamera takes about 100-150ms, HttpCamera is typically two to three times slower.
  • Android currently features a very significant bug that disregards the connect timeout setting for URL connections. Until that bug is fixed, the HttpCamera implementation will hang the first time it fails to connect to the webcam server. I believe this bug was resolved in the m5 emulator releases, but have not confirmed it.
  • When capturing a sequence of stills, JMF has a habit of 'freezing' on a single frame. If this happens, just stop and start the WebcamBroadcaster application. You do not need to restart your Android application.
  • I don't recommend using "localhost" when specifying an address to which the camera should connect. The Android device will probably treat this as the loopback on the emulated device itself. Instead use the IP address of the machine which is hosting the webcam (or WebcamBroadcaster).

[文档]Adobe Flex3 SDK说明文档

mikel阅读(1101)

此文档包含Adobe® Flex® 3 SDK的发布说明和安装说明。
           • 关于Flex 3 SDK
           • 新特性
           • 安装说明
           • 兼容性问题
           • 已知问题
           • Flex Builder 3发行说明
           • Flex 3文档

关于Flex 3 SDK
      Flex 3 SDK包括Flex框架(也称为Flex类库)、Flex命令行编译器、Flex调试器、ASDoc实用工具和调试器版本的Flash Player。使用Flex SDK可以开发、编译和部署Flex应用程序,这些应用程序将连接到XML和SOAP Web服务,或者连接到各种服务器技术,比如使用诸如BlazeDS之类的服务器技术的PHP、ColdFusion、Java和.NET。

新特性

       本节将列出Flex 3 SDK的一些主要新特性和更改。有关新特性的更多信息,请访问 Flex开发人员中心
       Adobe® AIR™的本机支持——Flex 3增加了对Adobe AIR的支持,后者允许开发人员在HTML、AJAX、Flash和Flex中使用现有Web技术构建RIA并将其部署到桌面系统中。Flex 3引入了一些新组件,并将Adobe AIR开发工具囊括到SDK和Flex Builder中。
持久性框架缓存——在对Adobe平台组件利用新的Flash Player缓存时,可使Flex 3应用程序的大小减少到50K。
Advanced DataGrid组件——Advanced DataGrid是一个新组件,通常用于将请求的特性添加到DataGrid中,比如对分层数据的支持和基本透视表功能。只可与Flex Builder Professional一起使用。
OLAP DataGrid组件——An OLAP(在线分析处理)网格数据允许以紧凑格式聚合数据,并用由行和列组成的二维网格显示这些数据聚合。只可与Flex Builder Professional一起使用。
Enhanced Constraints布局机制——Enhanced Constraints构建在已有的基于约束的布局机制之上,允许使用兄妹关系约束(在Flex 2中只可以定义父子约束)创建复杂的、可重新调整大小的布局。
Flex Charting包增强——Flex 3通过许多增强改进了Charting包。坐标系统现在只可以支持几个轴,DateTimeAxis允许执行工作周过滤。新的面向数据的图形API允许绘 制数据坐标,用图表呈现适当屏幕位置上的一切内容。对于现有所有图表,还有一些新格式选项和新添加的交互功能。只可与Flex Builder Professional一起使用。
Flex Component Kit for Flash CS3——Flex Component Kit for Flash CS3提供了用于创建可无缝集成到Flex应用程序中的Flash内容的完整工作流。Flash用户现在可以使用熟悉的Flash时间轴模型开发组件,然 后通过使用少许简单的模式使Flex开发人员能够引入这些组件,而无需添加额外代码。Flex Component Kit for Flash CS3可从Adobe 网站获得。
Flex Ajax Bridge库——Flex 3现在包括Flex Ajax Bridge (FABridge)、一个可插入Flex应用程序的小型代码库、一个Flex组件或一个空SWF文件(可以导出该文件实现浏览器中的脚本编写)。使用 FABridge可以使ActionScript类可用于JavaScript,无需编写任何额外编码。在插入库之后,就可以使用JavaScript实 现用ActionScript实现的任何操作。
Flex转向开源——Adobe Flex现在是开源的,包含用于框架、编译器、调试器以及更多可在Mozilla Public License下使用的工具的源代码。更多信息请访问 http://opensource.adobe.com/flex

安装说明

         Flex SDK安装是以ZIP文件形式提供的,其中包含Flex框架、Adobe AIR框架和命令行工具,比如mxmlc命令行实用工具、Adobe AIR命令行实用工具、ASDoc实用工具、Flex命令行调试器和调试器版本的Flash Player。
卸载当前的Flash Player

         应该让Flex SDK与最新版本的调试Flash Player一起使用,因此,在安装Flex SDK之前,应该卸载当前的Flash Player。
基于Windows插件的浏览器
          运行从此 技术说明 获得的适当卸载工具。
Macintosh
          运行从此 技术说明 获得的适当卸载工具。
Linux
手动移除(对于已通过Install脚本安装了插件的用户):
        • 删除libflashplayer.so二进制文件和目录
           /home/<user>/.mozilla/plugins/中的flashplayer.xpt文件
RPM移除:
       1. 在根目录下输入以下命令:
           # rpm -e flash-plugin
       2. 单击回车键并按照提示进行操作。
安装Flex SDK
        1. 从 Adobe网站 下载Flex SDK ZIP文件。
        2. 创建用于包含Flex SDK的目录。
        3. 将Flex SDK ZIP文件解压缩至此目录中。Flex SDK包含以下目录:
                o  /ant — 包含Flex Ant Tasks。
                o  /asdoc — 包含ASDoc工具的帮助文件,该工具根据MXML和ActionScript源代码创
                   建HTML文档。
                o  /bin — 包含mxmlc、compc、asdoc和fdb实用工具。bin目录也包含jvm.config文件,
                   该文件指定了可修改的Java设置(如果需要的话)。
                o  /frameworks — 包含已编译的框架类、配置文件和框架源代码。
                o  /lib — 包含供实用工具使用的JAR文件。
                o  /runtimes — 包含air目录中AIR运行库的安装程序,以及player目录中调试版
                    Flash Player 9的安装程序。
                o  /samples — 包含示例应用程序。
                o   /templates — 包含用于Flash Player检测和浏览器集成的HTML模板,在air文件夹
                   中,还有一个示例Adobe AIR application.xml文件。
         4. 确保计算机上已安装Java Runtime Environment(JRE),并且系统路径中已经定义了java_home/bin目录。要求使用JRE 1.4、1.5或1.6。对于1.4,则需要JRE 1.4.2_06或更高的版本。
         5. 从install_root/runtimes/player/platform目录安装适当的调试Flash Player。
         6. (可选)完成Flash Player安装之后,重新启动计算机,确保激活已更新的Flash Player浏览器。
         7. 查看浏览器示例,继续后面的操作。要运行浏览器示例,必须先运行install_root/samples/explorer/build.bat (Windows)或install_root/samples/explorer/build.sh(UNIX和Mac OS X)文件对其进行编译。有关Flex编译器的更多信息,请参阅《Building and Deploying Flex Applications》手册中的"Using the Flex Compilers"一章。

兼容性问题

向后兼容性编译器参数——有许多Flex SDK后向兼容性更改,其中包括可以使用新兼容性参数-compatibility-version将行为返回给Flex 2.0.1。要获得完整的细节描述,请参阅 Flex 3: Backwards Compatibility。
-compatibility-version参数不支持的向后兼容性问题——一些向后兼容性问题可能会影响在Flex 2.0.1中构建的应用程序。这些问题涉及以下组件的行为和配置设置:
           • flashType——flashType已过时
           • ComboBox ItemRenderer——paddingLeft配置方式的更改
           • DataGrid——DataGrid行为兼容性问题包括verticalScrollBar、rowCount、
              lockedRowCount、verticalSeperatorSkin和headerStyle。
           • 列表——选择对应于null项的基于列表的组件。
           • 按钮——使用自定义selectedUpSkin、selectedDownSkin和selectedOverSkin的按钮无法
             正确调整大小。
           • UITextField——过去受到保护的UITextField现在是类型IUITextField。
           • TileList——在使用pageDown键滚动项的时候,TileList具有不同的行为。
           • keep-as3-metadata——已从flex-config.xml中移除keep-as3-metadata。
           • 语言环境——语言环境现在包含在frameworks.swc中,在指定语言环境时将引发其他相关
             问题。
关于这些兼容性问题的详细信息,请参阅 Changes Not Supported By The Backwards Compatibility Flag,它是 Flex 3: Backwards Compatibility 文档中的一节。

已知问题
         本节包含选定的已知问题。有关Flex Builder问题及其状态的完整列表,请参阅 公共bug库。公共bug库允许搜索已知问题、关于它们的评论并添加新bug。
提示:可以使用Filters自定义您的搜索。
http://bugs.adobe.com/jira/browse/SDK-14289——深层链接无法与SSL一起使用
http://bugs.adobe.com/jira/browse/SDK-14440——无法打开已关闭的窗口。
http://bugs.adobe.com/jira/browse/SDK-12150——即使在application.xml中设置visible=false,WindowedApplication也仍然可见
http://bugs.adobe.com/jira/browse/SDK-873——启动Module中的PopUps可能会造成运行时错误(RTE)。
http://bugs.adobe.com/jira/browse/SDK-14298——在与Window组件中的容器一起使用creationPolicy=”queued”时,会导致异常
http://bugs.adobe.com/jira/browse/SDK-12787——在使用历史管理器时,无法存储第一个历史。
http://bugs.adobe.com/jira/browse/SDK-12694——无法在WindowedApplication中使用PrintDataGrid,除非明确指定宽度和高度。
http://bugs.adobe.com/jira/browse/SDK-10970——尝试使用SWFLoader加载远程swf时会在AIR中造成安全错误。
http://bugs.adobe.com/jira/browse/SDK-9421—— 分析器UI中缺少后向引用。在某些情况下,分析器可能不显示任何针对闲散对象的后向引用。这种情况多数发生于非堆(non-heap)对象,比如ABC解 码期间创建的String。要研究没有后向引用的闲散对象,请参阅配置追踪文件,该文件必须通过Launch Dialog激活。
http://bugs.adobe.com/jira/browse/SDK-14615——将Window或WindowedApplication的可见属性设置为false后,hideEffect仍不起作用。