CN1869923B - 系统数据接口及相关体系结构 - Google Patents
系统数据接口及相关体系结构 Download PDFInfo
- Publication number
- CN1869923B CN1869923B CN2006100037957A CN200610003795A CN1869923B CN 1869923 B CN1869923 B CN 1869923B CN 2006100037957 A CN2006100037957 A CN 2006100037957A CN 200610003795 A CN200610003795 A CN 200610003795A CN 1869923 B CN1869923 B CN 1869923B
- Authority
- CN
- China
- Prior art keywords
- interface
- server
- data
- client
- hresult
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Expired - Fee Related
Links
- 238000013499 data model Methods 0.000 claims abstract description 9
- 238000000034 method Methods 0.000 claims description 221
- 238000012545 processing Methods 0.000 claims description 94
- 230000009471 action Effects 0.000 claims description 88
- 230000004044 response Effects 0.000 claims description 10
- 230000011514 reflex Effects 0.000 claims description 4
- 239000011800 void material Substances 0.000 description 103
- 230000008859 change Effects 0.000 description 66
- 238000013507 mapping Methods 0.000 description 63
- 230000007246 mechanism Effects 0.000 description 62
- 238000003860 storage Methods 0.000 description 55
- 230000006870 function Effects 0.000 description 32
- 230000000875 corresponding effect Effects 0.000 description 30
- 230000008569 process Effects 0.000 description 20
- 238000010586 diagram Methods 0.000 description 18
- 230000006399 behavior Effects 0.000 description 15
- 230000027455 binding Effects 0.000 description 14
- 238000009739 binding Methods 0.000 description 14
- 230000002085 persistent effect Effects 0.000 description 14
- 230000008901 benefit Effects 0.000 description 13
- 238000004891 communication Methods 0.000 description 13
- 238000007726 management method Methods 0.000 description 13
- 230000005540 biological transmission Effects 0.000 description 12
- 230000015654 memory Effects 0.000 description 12
- 230000001360 synchronised effect Effects 0.000 description 12
- 230000015572 biosynthetic process Effects 0.000 description 10
- 238000005457 optimization Methods 0.000 description 9
- 238000007639 printing Methods 0.000 description 9
- 230000000694 effects Effects 0.000 description 8
- 235000014510 cooky Nutrition 0.000 description 7
- 230000002688 persistence Effects 0.000 description 7
- 244000035744 Hura crepitans Species 0.000 description 6
- 238000012217 deletion Methods 0.000 description 6
- 230000037430 deletion Effects 0.000 description 6
- 238000013461 design Methods 0.000 description 6
- 230000002829 reductive effect Effects 0.000 description 6
- 238000006243 chemical reaction Methods 0.000 description 5
- 238000003780 insertion Methods 0.000 description 5
- 238000012423 maintenance Methods 0.000 description 5
- 230000014759 maintenance of location Effects 0.000 description 5
- 238000004458 analytical method Methods 0.000 description 4
- 239000003795 chemical substances by application Substances 0.000 description 4
- 230000008676 import Effects 0.000 description 4
- 230000037431 insertion Effects 0.000 description 4
- 238000007689 inspection Methods 0.000 description 4
- 229940004975 interceptor Drugs 0.000 description 4
- 230000004224 protection Effects 0.000 description 4
- 230000000712 assembly Effects 0.000 description 3
- 238000000429 assembly Methods 0.000 description 3
- 238000005516 engineering process Methods 0.000 description 3
- 244000144992 flock Species 0.000 description 3
- 230000002441 reversible effect Effects 0.000 description 3
- 239000000344 soap Substances 0.000 description 3
- 230000003068 static effect Effects 0.000 description 3
- DSCFFEYYQKSRSV-KLJZZCKASA-N D-pinitol Chemical compound CO[C@@H]1[C@@H](O)[C@@H](O)[C@H](O)[C@H](O)[C@H]1O DSCFFEYYQKSRSV-KLJZZCKASA-N 0.000 description 2
- 241001269238 Data Species 0.000 description 2
- 239000008186 active pharmaceutical agent Substances 0.000 description 2
- 230000006378 damage Effects 0.000 description 2
- 230000003247 decreasing effect Effects 0.000 description 2
- 238000007667 floating Methods 0.000 description 2
- 239000000463 material Substances 0.000 description 2
- 238000012856 packing Methods 0.000 description 2
- 230000002093 peripheral effect Effects 0.000 description 2
- 230000000644 propagated effect Effects 0.000 description 2
- 230000000717 retained effect Effects 0.000 description 2
- 238000007789 sealing Methods 0.000 description 2
- 206010000117 Abnormal behaviour Diseases 0.000 description 1
- 235000007926 Craterellus fallax Nutrition 0.000 description 1
- 240000007175 Datura inoxia Species 0.000 description 1
- 241000196324 Embryophyta Species 0.000 description 1
- 238000009825 accumulation Methods 0.000 description 1
- 238000013475 authorization Methods 0.000 description 1
- 230000033228 biological regulation Effects 0.000 description 1
- 230000000903 blocking effect Effects 0.000 description 1
- 230000003139 buffering effect Effects 0.000 description 1
- 238000009933 burial Methods 0.000 description 1
- 238000004364 calculation method Methods 0.000 description 1
- 238000010367 cloning Methods 0.000 description 1
- 239000012141 concentrate Substances 0.000 description 1
- 230000002596 correlated effect Effects 0.000 description 1
- 230000008878 coupling Effects 0.000 description 1
- 238000010168 coupling process Methods 0.000 description 1
- 238000005859 coupling reaction Methods 0.000 description 1
- 230000001934 delay Effects 0.000 description 1
- 230000003292 diminished effect Effects 0.000 description 1
- 238000009826 distribution Methods 0.000 description 1
- 230000005059 dormancy Effects 0.000 description 1
- 230000009977 dual effect Effects 0.000 description 1
- 238000005538 encapsulation Methods 0.000 description 1
- 238000004880 explosion Methods 0.000 description 1
- 230000002349 favourable effect Effects 0.000 description 1
- 239000012634 fragment Substances 0.000 description 1
- 239000003292 glue Substances 0.000 description 1
- 230000006872 improvement Effects 0.000 description 1
- 230000003993 interaction Effects 0.000 description 1
- 230000002452 interceptive effect Effects 0.000 description 1
- 238000012432 intermediate storage Methods 0.000 description 1
- 238000011835 investigation Methods 0.000 description 1
- 210000003127 knee Anatomy 0.000 description 1
- 230000000670 limiting effect Effects 0.000 description 1
- 230000013011 mating Effects 0.000 description 1
- 230000005055 memory storage Effects 0.000 description 1
- 238000002156 mixing Methods 0.000 description 1
- 238000012986 modification Methods 0.000 description 1
- 230000004048 modification Effects 0.000 description 1
- 239000003607 modifier Substances 0.000 description 1
- 238000003032 molecular docking Methods 0.000 description 1
- 238000012544 monitoring process Methods 0.000 description 1
- 238000002360 preparation method Methods 0.000 description 1
- 230000001902 propagating effect Effects 0.000 description 1
- 238000013138 pruning Methods 0.000 description 1
- 238000012797 qualification Methods 0.000 description 1
- 230000011218 segmentation Effects 0.000 description 1
- 230000007958 sleep Effects 0.000 description 1
- 238000000638 solvent extraction Methods 0.000 description 1
- 230000001052 transient effect Effects 0.000 description 1
Images
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/46—Multiprogramming arrangements
- G06F9/54—Interprogram communication
- G06F9/547—Remote procedure calls [RPC]; Web services
-
- A—HUMAN NECESSITIES
- A61—MEDICAL OR VETERINARY SCIENCE; HYGIENE
- A61H—PHYSICAL THERAPY APPARATUS, e.g. DEVICES FOR LOCATING OR STIMULATING REFLEX POINTS IN THE BODY; ARTIFICIAL RESPIRATION; MASSAGE; BATHING DEVICES FOR SPECIAL THERAPEUTIC OR HYGIENIC PURPOSES OR SPECIFIC PARTS OF THE BODY
- A61H39/00—Devices for locating or stimulating specific reflex points of the body for physical therapy, e.g. acupuncture
- A61H39/06—Devices for heating or cooling such points within cell-life limits
-
- A—HUMAN NECESSITIES
- A61—MEDICAL OR VETERINARY SCIENCE; HYGIENE
- A61K—PREPARATIONS FOR MEDICAL, DENTAL OR TOILETRY PURPOSES
- A61K36/00—Medicinal preparations of undetermined constitution containing material from algae, lichens, fungi or plants, or derivatives thereof, e.g. traditional herbal medicines
- A61K36/18—Magnoliophyta (angiosperms)
- A61K36/185—Magnoliopsida (dicotyledons)
- A61K36/28—Asteraceae or Compositae (Aster or Sunflower family), e.g. chamomile, feverfew, yarrow or echinacea
- A61K36/282—Artemisia, e.g. wormwood or sagebrush
-
- A—HUMAN NECESSITIES
- A61—MEDICAL OR VETERINARY SCIENCE; HYGIENE
- A61H—PHYSICAL THERAPY APPARATUS, e.g. DEVICES FOR LOCATING OR STIMULATING REFLEX POINTS IN THE BODY; ARTIFICIAL RESPIRATION; MASSAGE; BATHING DEVICES FOR SPECIAL THERAPEUTIC OR HYGIENIC PURPOSES OR SPECIFIC PARTS OF THE BODY
- A61H2201/00—Characteristics of apparatus not provided for in the preceding codes
- A61H2201/01—Constructive details
- A61H2201/0165—Damping, vibration related features
- A61H2201/0169—Noise reduction
-
- A—HUMAN NECESSITIES
- A61—MEDICAL OR VETERINARY SCIENCE; HYGIENE
- A61H—PHYSICAL THERAPY APPARATUS, e.g. DEVICES FOR LOCATING OR STIMULATING REFLEX POINTS IN THE BODY; ARTIFICIAL RESPIRATION; MASSAGE; BATHING DEVICES FOR SPECIAL THERAPEUTIC OR HYGIENIC PURPOSES OR SPECIFIC PARTS OF THE BODY
- A61H2201/00—Characteristics of apparatus not provided for in the preceding codes
- A61H2201/02—Characteristics of apparatus not provided for in the preceding codes heated or cooled
- A61H2201/0221—Mechanism for heating or cooling
- A61H2201/025—Mechanism for heating or cooling by direct air flow on the patient's body
-
- A—HUMAN NECESSITIES
- A61—MEDICAL OR VETERINARY SCIENCE; HYGIENE
- A61H—PHYSICAL THERAPY APPARATUS, e.g. DEVICES FOR LOCATING OR STIMULATING REFLEX POINTS IN THE BODY; ARTIFICIAL RESPIRATION; MASSAGE; BATHING DEVICES FOR SPECIAL THERAPEUTIC OR HYGIENIC PURPOSES OR SPECIFIC PARTS OF THE BODY
- A61H2201/00—Characteristics of apparatus not provided for in the preceding codes
- A61H2201/02—Characteristics of apparatus not provided for in the preceding codes heated or cooled
- A61H2201/0221—Mechanism for heating or cooling
- A61H2201/0278—Mechanism for heating or cooling by chemical reaction
-
- A—HUMAN NECESSITIES
- A61—MEDICAL OR VETERINARY SCIENCE; HYGIENE
- A61H—PHYSICAL THERAPY APPARATUS, e.g. DEVICES FOR LOCATING OR STIMULATING REFLEX POINTS IN THE BODY; ARTIFICIAL RESPIRATION; MASSAGE; BATHING DEVICES FOR SPECIAL THERAPEUTIC OR HYGIENIC PURPOSES OR SPECIFIC PARTS OF THE BODY
- A61H2201/00—Characteristics of apparatus not provided for in the preceding codes
- A61H2201/50—Control means thereof
- A61H2201/5058—Sensors or detectors
- A61H2201/5082—Temperature sensors
Landscapes
- Health & Medical Sciences (AREA)
- Engineering & Computer Science (AREA)
- Natural Medicines & Medicinal Plants (AREA)
- Theoretical Computer Science (AREA)
- Software Systems (AREA)
- Life Sciences & Earth Sciences (AREA)
- Animal Behavior & Ethology (AREA)
- Physics & Mathematics (AREA)
- General Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- Rehabilitation Therapy (AREA)
- Veterinary Medicine (AREA)
- Public Health (AREA)
- Epidemiology (AREA)
- General Health & Medical Sciences (AREA)
- Alternative & Traditional Medicine (AREA)
- Biotechnology (AREA)
- Mycology (AREA)
- Microbiology (AREA)
- Pain & Pain Management (AREA)
- Physical Education & Sports Medicine (AREA)
- Pharmacology & Pharmacy (AREA)
- Botany (AREA)
- Chemical & Material Sciences (AREA)
- Medical Informatics (AREA)
- Medicinal Chemistry (AREA)
- Computer And Data Communications (AREA)
- Accessory Devices And Overall Control Thereof (AREA)
- Stored Programmes (AREA)
Abstract
本文描述了一种系统数据接口和相关的体系结构。各个实施例可提供以下能力中的一个或多个:通用数据模型、异步客户机和服务器调度、取消、批处理、事务式调用、并行调用、截取、或者反射。在一个实施例中,该系统数据接口在打印系统的上下文中被使用。
Description
技术领域
本发明涉及系统数据接口和相关体系结构,并且在特定实施例中涉及打印系统数据接口和相关体系结构。
背景技术
一些系统可包括处理数据并与各类客户机通信的服务器。一类特别的系统是打印系统,它可包括提供对作业、设备、逻辑服务器的访问,并从各个客户机构成数据。诸如打印系统等许多当前的系统具有不灵活的底层网络接口,每当需要支持新的数据类时该接口就必须被修改。此外,一些接口所要求的通信比可能需要的通信多得多,并且能在服务器上创建上下文,无论在什么上下文中使用诸如打印系统等服务器,这两种情况都可能限制服务器的性能。
其它困扰许多系统的问题只要是协议专属的,就可能导致不灵活性、难以扩展性以及局限性。
由此,本发明是出于与提供包括改良的数据接口和相关体系结构的改良系统相关联的考虑。
发明内容
本文描述了一种系统数据接口和相关体系结构。各实施例可提供以下各能力中的一种或数种:通用数据模型、异步客户机和服务器调度、取消、批处理、事务式调用、并行调用、截取或反射。
在一个实施例中,是在打印系统的上下文中使用该系统数据接口。
附图说明
图1是示出根据一个实施例的数据接口的各个组件的高级框图。
图2是根据一个实施例的打印数据访问接口的高级框图。
图3是示出根据一个实施例的进程外通信的方面的框图。
图4是示出根据一个实施例的安全模型的概貌的高级框图。
图5是示出根据一个实施例的类型映射机制的框图。
图6是根据一个实施例的公共数据接口对象访问接口的框图。
图7是根据一个实施例的动态类型映射的框图。
图8是示出根据一个实施例的对象创建和克隆的框图。
图9是示出根据一个实施例的抽象分层结构的框图。
图10是示出根据一个实施例的类分层结构和安全的框图。
图11是示出根据一个实施例从对象检索的元数据的框图。
图12是根据一个实施例的公共数据接口的示例性组件的框图。
图13是根据一个实施例的插件模型的框图。
图14是根据一个实施例由集合适配器服务使用的对象模型的框图。
图15是示出根据一个实施例的框架提供的集合的框图。
图16是示出根据一个实施例的托管与非托管对象的互操作性的框图。
图17是示出可被用来实现一个或多个实施例的计算设备的示例性组件的框图。
具体实施方式
概述
在以下讨论中,提供了一种解决现有系统的许多缺点的新颖系统。在一个实施例中,在打印系统的上下文中描述该系统、其数据结构和相关体系结构。但是应当意识到并理解,可在除打印系统以外的其它系统中使用以下所描述的发明特征,而不会偏离要求保护的主题的精神和范围。
尽管所描述的打印系统实现许多功能,但是基本上所描述的打印系统实现两个主要任务。第一,该打印系统管理包括一组对象及其属性在内的数据。第二,该打印系统调度打印任务以首先提交打印作业,然后将打印作业发送到适当的打印设备进行打印。提交文档的过程可通过从指定调用哪些组件来处理该作业的数据接口检索配置信息来实现。因此,打印系统表示数据的方式对其操作而言可能是根本的。
为实现这些主要任务,本发明的打印系统使用特定接口和相关组件。与现有打印系统相比,此接口以及此接口作为其部分的打印系统可提供许多优点。在以下讨论中,将描述各种优点以提供对该打印系统和接口的初步理解。此讨论之后,题为“示例性实施例”的章节讨论该打印系统尤其是该数据接口的具体实现示例。
下文中所描述的数据接口支持以下能力,其中每个能力都在其自己的标题下出现并被讨论:通用数据模型、异步客户机调度、异步服务器调度、取消、批处理、事务式调用、并行调用、截取和反射。
通用数据模型
所描述的数据接口支持并可结合可被视为通用数据模型的数据模型使用。该数据模型可支持具有以下能力的对象类:
·属性 - 任何对象都可具有任意的一组属性。客户机可指定要从任何对象检索的任何一组属性。仅将检索客户机所关注的属性。
·命令 - 任何对象都可支持具有任意的一组参数的一组命令。
·无需修改线格式即能任意地扩展客户机可从服务器使用的类、命令和属性。
异步客户机调度
异步客户机调度是指数据接口的应用程序接口(API)允许客户机或客户机应用程序开始一立即将控制返回给客户机线程的数据请求的能力,如本领域技术人员将会理解的那样。当该操作的结果是完成时,客户机经由回调或被通知的系统事件得到通知,然后它可检索数据的结果。在所示出和描述的实施例中,并不是将此能力作为旋转(spin)一同步阻塞的线程并允许客户机继续处理的无关紧要的包装(wrapper)来提供的。相反,异步调度被下延至设备级。在较低的层次上,调用的结果是网卡驱动的中断。使用这一模型简化了在从服务器检索数据的同时保持响应状态的客户机用户接口的设计。它还减少了客户机上所需的线程数。这在客户机系统是对另一个打印系统起到桥梁作用的打印系统时特别有益。
异步服务器调度
在耦合了客户机异步地向服务器调度请求的能力的情况下,服务器可异步地服务来自客户机的请求。如果客户机请求服务器执行的动作是IO绑定的(例如,它需要将数据写到盘中,或从另一个服务器请求数据),则插件组件可发布另一个异步调用,将控制返回给服务器方的数据接口,然后在IO完成时完成该次调用。此机制可大大减少服务器上运行的线程数,并可确保所有线程都在充分利用系统CPU。
系统上执行的每个线程都从该系统占取大量“非分页池”(非分页池是在物理存储器变得有限时不能被写出到盘中的存储器)。系统中运行的每个获得系统锁的线程还在系统中创建大量“争用”(这是在执行线程之间切换所需的时间量和CPU资源)。因此,减少系统中运行的线程数是提高系统性能的重要机制。
取消
在以下所描述的实施例中,服务器上正在进行中的调用可由客户机在任何时候取消。这帮助客户机向调用者提供交互式用户界面。
批处理
批处理是指客户机使用该数据接口来构建任意的动作序列、并使该动作序列作为一个单元被发送给服务器的能力。此序列随后被处理并在单个传输响应中返回给客户机。这些动作可包括任何类型的动作,诸如获取和设置属性、查询一组属性、对服务器对象发布命令、以及为关于服务器对象属性的改变的通知进行注册。
事务式调用
事务式调用是指被赋予该批次必须完整地执行、否则不改变服务器状态的语义的批次。
并行调用
并行调用是指被赋予该批次中的所有项目必须并行执行的语义的批次。这允许服务器并行地执行长期运行的动作,它还提供该批次将执行所有动作而无论其它动作失败情况如何的语义。
截取
因为该系统可支持的操作和属性是由纯数据传输表示的,所以能够监视、同步响应于及修改该系统的行为(称为截取)的其它组件可被插入该系统中。这允许监视软件被插入到该系统中,并允许其被从该系统中移除。这还允许独立硬件供应商(IHV)扩展系统行为。例如,如果一队列被停止,则相关联的服务可能也需要被停止。对该队列的“停止”命令可被IHV截取,它们随即可确保在允许该停止操作完成以前该服务已被停止。截取机制还可提供事务式语义。
反射
反射是指系统所提供的检索哪些属性受给定对象类的支持、以及与该对象相关联的其它信息的机制。使用此机制可检索的信息包括,但不限于:
·每个属性的类型名、字段名和数据类型;
·对属性的用法的人类可读的描述;
·对象所支持的命令、以及该命令所支持的输入和输出参数。每个命令都有对该命令的用法的人类可读的描述。对于每个参数,以下数据可被检索:该参数的名称和类型,以及对该参数的人类可读的描述。
在所示出并描述的实施例中,该系统的反射能力是协议不可知的。此外,反射能力可被用于服务器插件的本机代码和托管代码实现,并可从这两者使用。此外,反射能力提供通过网络接口执行反射、并且不要求在客户机上存在服务器方对象的实现的能力。
这些及其它能力将从以下描述变得明确。
示例性实施例
在以下讨论中,结合图1提供对本发明的接口的高级讨论。这一讨论之后,提供一实现示例,它包含实现专属的信息。应当意识到并理解,提供该实现专属的示例只是作为如何实现包括上述能力的打印系统的一个示例。因此,可使用其它实现而不会偏离所要求保护的主题的精神和范围。其它实现可在也可不在打印系统的上下文中使用,如前文所提及。
图1一般地在100处示出一种包括公共数据接口102、批处理路由器104的系统,其中批处理路由器104包括插件表106和截取表108。系统100还包括消息插件110、消息服务112、集合114、各种对象116、系统扩展118以及所谓的“其它协作”120,其中每一个都将在以下讨论。
公共数据接口(CDI)
公共数据接口(CDI)是到批处理路由器104的接口,它允许消息被构建并被调度到批处理路由器。CDI还负责将响应发送到客户机。
批处理路由器
批处理路由器104接收由CDI102打包并传入该系统的消息。每个消息可包括目的地为若干插件的若干操作。这些消息被异步地调度,结果进而由批处理路由器104检索。消息是基于标识应将该消息发送到哪个集合的无岐义路径被路由的。从客户机的角度出发,单个消息可能有多个目的地。
插件表
插件表106跟踪所有负责给定对象集合的消息处理插件。每个集合都由一个全局唯一标识符(GUID)标识。在将消息向下传递给对象以前,到该对象的路径被检查并在插件表中被查找。
消息插件
正确的集合一经标识,该组消息即被传递给消息插件110。消息插件110可仅仅将这些消息通过线路远程地向外发送到另一个机器。但是,更加典型的情况是,消息插件110将解释这些消息并适当响应。在所示出并描述的实施例中,第三方可提供消息插件。但是,当第三方提供消息插件时,对第三方而言由消息服务提供的服务是不可用的。这将使得这一层处的插入困难得多。作为消息插件的一个主要优点是这样将使得原始消息的形式可用。这对允许整个消息被插件集合中继给远程机器可能是很有用的。此外,这在独立硬件供应商也具有支持批处理的远程系统,并且他们希望能够在所接收的消息格式和他们自己的消息格式之间转换的情况下对他们而言是一个优点。
消息服务
因为基于消息的系统中一个主要问题是难以维护消息调用上的状态,所以提供消息服务112这一组件,以将消息分解,并将它们转换为集合接口上较简单的调用序列。作为示例而非限制,在所示出并描述的实施例中,消息服务可执行以下任务:
·将消息分配给线程;
·允许在多个延迟调用中响应消息;
·从集合中的对象检索适当的数据来填充消息;
·正确处理操作取消;
·随时间推移高速缓存对象实例;
·对象的透明锁定;以及
·针对集合中所维护的对象的反射服务。
集合
集合114维护一组同类的对象。该系统提供允许对象容易地将它们自身持久化的集合。使用集合的一个优点是它允许独立硬件供应商用任意对象容易地扩展该系统。在所示出并描述的实施例中,集合被实现为从动态链接库(DLL)检索出来的COM接口。在全局程序集高速缓存中查找该DLL,并且对DllGetClassObject进行直接调用,这就允许人们规避COM注册,如本领域技术人员将会理解的那样。对象
上文和下文中所描述的系统的一个目的是允许独立硬件供应商及其它开发者在有了对其实现语言的直接支持的情况下,很大程度上能够在类的层次上进行编码。该目的是将尽可能多的代码并入集合中,以减少独立硬件供应商及其它开发者必须编写的代码总量。对象116是集合所维护的逻辑结构。消息服务112提供一个层,在该层这些对象直接对应于C++类。
截取表
截取表108向打印系统提供一种一般的、通用的扩展机制。这里的目的是允许扩展能够截取并修改目标为系统中的任何对象、特定类的对象、或特定对象实例的消息。
系统扩展
因为系统中绝大多数事物源自中央消息系统,并由消息表示,所以系统扩展118允许该系统被扩展,特别是被第三方以其认为合适的任何方式监视。这些扩展还提供由假脱机程序团队本身所进行的有用的监视扩展。
其它协作
可以理解,不是所有系统行为都可被表示为数据驱动的消息通信系统。因此,创建了机器中的其它子系统的对象之间已有并还将会有其它协作120。这些可包括例如管道和调度器。这里的目的是令所有这些协作尽可能的灵活,以允许他方被插 入到该系统中。
这些其它子系统与该系统的CDI视图保持一致的方法是通过CDI调用工厂对象,它们或是直接创建对象,或是返回适当的数据以允许对象被实例化。使用此模式的结果是系统扩展可截取这些对工厂对象的调用,并且它们可实现该工厂并包装原始接口。这意味着系统扩展可监视或修改该系统的任何方面。这对于允许可插入的监视组件在任意点处被插入到系统中是非常有用的。
现在提供了对本发明的接口的高级讨论后,以下章节描述包含实现专属信息的实现示例。如上文中所提及,应当意识到并理解,提供实现专属的示例只是作为如何实现根据本文中所描述的发明原理的打印系统的一个例子。因此,可使用其它实现而不会偏离所要求保护的主题的精神和范围。
实现示例
作为预备知识,贯穿此后的讨论将使用以下术语和缩写词汇表:
·动作 - 见批次。
·访问适配器 - 见数据访问适配器。
·访问器 - 一种用来从对象检索数据的方法。.Net属性是访问器的一个例子。
·批次 - 在被累积以后在一个时间点被执行的一系列动作。一个批次通常会导致一个网络调用。动作可以是获取、设置、查询、命令和通知请求。
·批处理集合 - 插入批处理路由器中的最高级的接口。它接收被适当地路由的要执行的动作批次。
·批处理路由器 - CDI中选择将批次中的动作传递给一组集合中的哪一个的元素。
·规范名称 - 在时间和空间中唯一标识对象的名称。在CDI中这将是集合GUID和对象GUID。CDI只基于规范名称进行路由。应用程序在与该系统通信时应当在任何可能之处使用规范名称。见友好名称。
·CDI - 见公共数据接口。
·类 - 在CDI中是一种对象。类可以是打印机、作业或服务器、或者任何其它逻辑划分。类包含类型。
·客户机集合 - 在客户机上维护的对象集合。CDI基于对象的类型映射在客户机集合中填充对象。
·集合 - 由一段逻辑代码提供的一组异类的对象。CDI基于规范名称将请求路由到多个集合。
·集合适配器服务 - 向批处理路由器公开批处理集合接口、并实现允许比较容易地公开一组对象的服务的服务。
·命令 - 一种批处理动作,它在该批次最终被发送到服务器时使对象上的方法被执行。
·公共数据接口 - 允许经由规范名称访问对象的组件。它还为将调用一起批处理以及异步或同步访问对象提供支持。
·数据访问适配器 - 数据访问适配器插入到CDI中,并以某种方式转换其能力。这可以是将CDI所公开的接口变换为另一个接口(进程内(In-proc)适配器),或者可以是将CDI远程化,在此情形中它是远程访问适配器。
·显示名称 - 见友好名称。
·嵌入类型 - 集合中被用来动态扩展另一个集合中的另一个对象所支持的属性的对象。
·字段 - 一段命名的数据。
·友好名称 - 也称为显示名称。友好名称是用户将其与对象(Fred的打印机)相关联的名称,它与系统用来标识对象实例的规范名称相对。为了允许友好名称被转换为规范名称,CDI提供名称解析管道。
·分层结构 - 在CDI中它是父和子对象之间的任意关系,该关系可通过从父对象查询链接来获得。
·进程内适配器 - 与应用程序中运行的CDI实例进程内运行的数据访问适配器的一种形式。这些通常仅仅是以某种方式变换数据。例如,通过提供访问数据的API。
·链接 - 用于查询对象之间的分层结构关系的一个特殊的保留类。
·元数据 - 勿与CLR中的反射混淆。可从任何对象查询元数据以发现其所支持的类型、字段、和命令。无论客户机上是否有对应的程序集可用,它都可被检索。
·方法 - 在调用一对象时该对象上获执行的实际代码段。稍有不同的概念请参见命令。
·名称解析管道 - 在应用程序空间中运行以将友好名称转换为规范名称的一系列称为解析器的元素。
·优化的类型映射 - 要对两个对象执行以将一组字段从一个对象转移到另一个对象的一系列获取和设置。这是通过组合客户机对象的类型映射和服务器对象的类型映射的字段来构建的。
·持久对象集合服务 - 插入到集合适配器服务中的允许对象被持久化到数据库中的服务。
·查询 - 在CDI的上下文中,用可任选的过滤器与可任选的查询基对给定类的一组对象的请求。
·查询基 - 查询开始的概念点。例如,基可以是本地机器或给定的服务器。
·远程访问适配器 - 远程访问适配器允许CDI所公开的接口被远程化于两个机器之间。它通过对一个CDI表现为对象集合,而对被远程化的CDI表现为数据适配器来实现此目的。
·解析器 - 名称解析管道中的一个元素。每个解析器都与一个集合相关联,并且知道如何标识其内部的元素。
·类型映射 - 一张各字段及其相关访问器的表,它描述如何从对象检索数据或如何将其应用于对象。类型映射可以是动态或静态的。通过比较字段来产生优化的类型映射,两个类型映射可被合并。
·类型 - 类似于接口。类型是总是必须被完整实现的字段和命令的逻辑分组。
公共数据接口
公共数据接口(CDI)提供包括根据名称(友好名称,或较佳的是规范名称)来定位对象,从该对象获得数据或将数据应用于该对象,支持由对象改变触发的通知并向对象发布命令在内的功能。CDI解决并克服各种现有体系结构的许多限制,包括但不限于,同步接口的使用,缺少可扩展性,基于名称的路由和缺少批处理,等等。
CDI通过允许任意个数的可被唯一地标识的集合被插入到该系统中。这些集合可支持其所希望的任何种类的对象。该接口本身具有相当的复杂性以支持异步操作和批处理,但它提供各种服务并允许能更容易地编写被插入的集合。
路由器体系结构调整
现有的假脱机程序中大量基本问题都来自于路由器。这包括同步API集的使用,在启动时加载其所有提供程序(和监视器)的必要性,不能够重命名对象,不能够卸载假脱机程序的任何组件,以及不能够关掉系统。这一节描述本发明的打印系统中的路由器的替换体系结构。
以下讨论是基于图2中所示的概览图。在此例中,路由器被远比其灵活的数据访问机制,公共数据接口(CDI)所代替。CDI基本上是访问适配器和集合之间的路由和服务层。它提供经由多个协议在任何系统上定位打印对象的能力,它还提供一组允许所有对象具有相同语义的服务。这些语义是检索和设置对象数据的子集的能力,查询所有对象的状态的能力,向对象发布命令的能力,以及从系统中的所有对象一致地发送改变通知的能力。数据访问适配器被分为进程内适配器和远程访问适配器。
在所示出并描述的实施例中,所有内部组件和应用程序(除了集合提供程序与访问适配器以外)都仅与进程内适配器相接。对于跨越进程边界的通信以及客户机/服务器通信,使用COM/DCOM远程访问适配器。对于基于web服务的情形,使用SOAP适配器。各适配器进而表现为其它进程空间或其它机器上的集合。这 允许任何能够完全支持公共数据接口的访问适配器总是可通过进程内适配器来访问。图3中示出此连接方案的概览。
下级和上级协议访问
上级适配器是任何能够完整封装整个公共数据接口的适配器——唯一的完全进程内适配器将会是基于属性的托管代码适配器。到该系统的托管API将仅代表该系统能力的有用应用程序子集。有两种类型的完全远程访问适配器,包括用于本地机器上以及基于客户机-服务器的情形中的通信的进程外COM适配器,以及经由web服务提供对数据的访问的SOAP远程访问适配器。
适配器的其它候选有能使用公共数据接口的所有能力的适配器,它们本身仅公开有限的数据类型,但这些有限的数据类型能以完全数据驱动的方式被映射。例如,可使MOF文件数据类型和公共数据接口数据类型之间的映射成为完全数据驱动的映射。MOF文件是被管理规范(WMI)系统用来描述系统对象的。
其它灵活性较差的协议很可能使用进程内适配器来与打印系统组件通信,例如,RPC客户机将经由C++模板库与新的打印系统通信。
通过提供存储器内集合并允许用户编写托管类和对象适配器来向系统提供数据,可简化对下级提供程序的支持。下级提供程序将必须支持类型的某个有限子集以使其可供系统使用。
公共数据接口对象模型
在所示出并描述的实施例中,公共数据接口(CDI)具有如下属性。CDI支持在对象上获取与设置单个属性。它还支持基于查询过滤器和要从每个对象检索的一组属性来查询对象组。CDI支持要求对象执行命令,将一组参数传递给对象,并从其接收一组返回参数。此外,CDI支持请求对象改变的通知。该通知包括过滤器以及调用者想要被通知的一组属性。此外,CDI是仅为进程内的,而将接口远程化的能力是由适当的插件适配器提供的。CDI使用回调来进行通知;通知带来了一些困难的权衡,因为由客户机维护的连接显著地降低服务器的可伸缩性。为解决这一问题,可使用两类通知:第一,管理通知可使用异步接口维护到服务器的连接。这些通知将被用于倾向于具有管理目的的频繁改变的数据,例如查看逻辑队列中的作业;第二,状态改变通知可使用TTL方案和消息通信系统(例如,MSMQ)来发送具有传递保证的不那么频繁的通知。因为该通知机制将支持服务器方的查询,所 以可通过指定服务器方查询并使用有保证的传递机制来实现通常所需的用户通知。
此外,CDI是基于访问器的。它并不公开字典接口。相反,它提供查询机制用于获取数据,并提供了检索对象元数据用于仿真字典接口的能力。CDI还将若干对象集合聚集在一起。上级集合被用来提供完全查询支持。下级集合被用来提供枚举支持,因为所有打印集合看上去都应该是相同的;查询是通过枚举所有对象并对它们应用过滤器来构建的。任何不是CPU绑定的方法都可被异步地调用。
公共数据接口允许对对象集合的访问。所有CDI对象都是通过集合来访问的。每个集合允许对一组对象类的访问。对象类标识例如逻辑设备、协议适配器、逻辑服务器等对象的类。对象类是用编程名称来标识的。编程名称必须是<Company>.<Class>[.<Version>]的形式。可在任何区域设置中使用此名称来标识对象。该串可被实现为Unicode串,尽管在其它实现中它可由英文标识符组成。
在所示出并描述的实施例中,一类特定的对象将总是由在系统的整个生命期上都相同的编程名称来标识的,包括服务器任何先前的版本,或表示下级服务器的任何集合。
给定的对象类包含若干类型。类型是以标识对象类的相同方式由编程名称标识的。类型包含若干个字段——每个字段由程序字段名和字段类型标识。类型中的诸字段在操作系统的所有版本上、以及在任何平台上都必须是不变的。类型除字段外还封装命令。命令是由串标识的,它取若干有序的输入和输出参数。
CDI允许对由第三方通过CDI发送的消息的截取和扩展。这将允许这些第三方监视和扩展对象能力。对象还将被允许将某些调用重定向到被包含的对象。
对象命名
在所示出并描述的实施例中,对象总是具有唯一的规范名称,它准确地标识该对象的实例——此规则唯一的例外是对于表示下级服务器上的对象的集合。
对象是由对象路径标识的。对象路径总是以它被包含在其中的集合实例的GUID开始,因此:{XXXXXXX}\{YYYYYY}是指集合{XXXXX}中GUID为{YYYYY}的对象。对于上级服务器上的对象,路径将会是:{WWWWW}\<server>\{XXXXX}\{YYYYY},其中{WWWW}是远程集合GUID,而{XXXXX}是对象{YYYYY}位于其中的远程集合。
每个CDI实例都支持默认集合的概念,默认集合类似于文件系统中的当前路径。因此,寄宿在应用程序空间中的CDI可将其默认集合设为本地机器上的假脱 机程序,正如所有卫星沙箱(satellite sandbox)进程和应用程序域所能够的那样。任何不带完全限定路径的对象规范名称将在默认集合中被自动搜索。如果在应用程序空间(例如,绕过本地服务的对服务器的直接网络访问)中实现的集合要被访问,则应当使用完全限定路径(即,以‘\’开头的路径)。
在所示出并描述的实施例中,以下是对象路径中的保留字符:‘\’、‘:’、‘”’、‘^’和‘.’。
脱字符(^)被用来将接下来的一个字符转义,并允许串中可表示任何字符。下表中示出有效的转义。
因此,为了分离出在路径中必须包含‘\’的对象名,‘\’可由‘^\’转义。
友好名称和名称解析管道
还可任选地给予对象友好名称(或显示名称)。总是应当使用以下机制来定位对象。
·为显示目的,应对服务进行对象类的无基查询。所有匹配这个类的本地对象将被返回。UI从该时起应使用被返回的对象的规范名称,并显示这个类的显示名称。
·对于可被直接输入到用户界面中的名称(包括远程服务器UNC名称),可提供一系列称为名称解析器的可插入组件。应用程序调用这些组件以将“友好名称”解析为规范名称。现有的API将使用名称解析器来将诸如OpenPrinter和ClosePrinter等基于友好名称的调用转换为规范名称形式(因为名称解析很可能是缓慢的,所以必须引入高速缓冲层)。
·名称解析器的顺序将表示给定的名称映射的优先级。例如,当远程UNC名称被升级到连接时,同一个名称将解析到本地集合中的逻辑队列对象,而不是表示远程队列的队列对象。
·应用程序可选择是仅使最完整特征化的名称绑定被返回给它,还是使对应于友好名称的所有名称绑定被返回给它。返回所有的名称绑定将会是成本更高的,因为它可能需要加载许多集合来进行解析。
·有了名称解析元素可防止不必要地加载整个集合,这和现有的路由器体系结构不同。每个想要为其对象支持友好名称的集合也必须实现名 称解析元素。
·应用程序在执行名称解析时还将被允许指定意图。例如,管理应用程序可指定它只想要未经高速缓存的信息。在此情形中,未经高速缓存的对象将被返回,即使它的能力低于已被缓存的版本。
安全
在所示出并描述的实施例中,安全被密切地联系到将由系统提供的服务层。但是在这里给出安全将如何起效的概述,因为它是重要的主题,并且在讨论实现以前,对该模型的全局概述是合乎需要的。
图4示出根据一个实施例的新的假脱机程序安全模型的概念图。这一新的假脱机程序安全模型的一个目的是保持CDI是到对象的轻量级内部接口,因此它不执行任何验证功能。此外,CDI可经由远程集合将数据路由到服务器。然后由服务器执行授权。因此,根据本实施例,CDI路由层将不提供授权功能。最后,CDI还将在既不需要验证也不需要授权的应用程序空间中执行。
因此,验证是由远程访问适配器以与访问传输和协议一致的方式执行的,而授权是由适当的集合服务(或延迟到远程服务器)执行的。此方案的一个后果是CDI以及所有集合都可由未经授权的用户访问。为帮助缓解此问题,逻辑系统对象提供控制对机器的整个打印系统的访问的访问控制列表(ACL)。当远程访问适配器接收到一批命令时,它对逻辑系统对象执行访问检查。这些命令(如获取、设置和查询)只有在访问检查成功的情况下被允许执行。此操作为远程访问适配器接收到的任何批处理命令执行一次。在所示出并描述的实施例中,逻辑系统ACL默认为“每个人”(但不是“匿名的”)。管理员被允许改变逻辑系统许可,以限制对整个打印子系统的访问。
在所示出并描述的实施例中,对逻辑系统对象有远程访问适配器被要求无需授权即通达逻辑机器对象的特殊的保留系统重置命令。逻辑机器对象仅允许管理员执行此命令,并且它将管理员加回到逻辑机器ACL中。此机制防止管理员拒绝他或她自己对逻辑机器对象的许可,此拒绝将导致管理员再也不能重新访问该子系统。
在所示出和描述的实施例中,本地集合中的每个对象都有与之相关联的一个ACL。对对象的访问检查准确地包含对照其ACL检查访问。每个对象实例都具有一个类对象,该类对象将为该类的新对象提供默认的可继承的ACL,而CDI维护类对象的集合。管理员可自由修改类ACL,类ACL将为给定类的任何新对象提供 默认的ACL。这允许管理员将对对象的创建权委托给另一个用户,但在对象被创建时仍将默认的ACL应用于该对象。
在所示出并描述的实施例中,CDI提供允许尽可能容易地编写本地对象集合的服务层。该服务层向任何对象实现提供该安全基础结构供其免费使用。
图4中没有示出许可代理,它在许可改变时将新的ACL递归地应用于所有参与的类。此代理负责将对类对象的改变传播到类的实例,它还负责将任何管理分层结构改变传播到对象实例。
CDI访问器模型
此接口更加基础的方面之一是访问器模型。此机制允许公共数据接口和集合填充调用者的数据结构。在所示出并描述的实施例中,CDI访问器模型是非托管的,因为它预期与之协同操作的打印假脱机程序包含非托管的核心服务。因为该打印系统的一些组件将会是托管的,并需要对打印系统中的数据的完全访问,所以其中也有托管代码访问层。
CDI访问器模型后面的想法是CDI是一个客户机对象集合与多个服务器对象集合之间的代理。它提供一种高效的机制,使客户机和服务器能仅使用每一方想要传送的字段来交换此信息。
例如,考虑图5,该图示出在服务器集合、客户机集合和CDI的上下文中,根据一个实施例将如何实现此功能的诸方面。
在此例中,服务器和客户机都描述它们想要经由相同的机制——类型映射来公开或检索的数据。类型映射描述每个对象所支持的各种子类型和字段。对于每个字段,提供了知道如何获取或设置其所描述的类的每个实例的给定属性的接口。因此,给定了类型映射,类实例的所有属性就都可被访问。
给定对客户机和服务器类的描述,CDI可执行很好的优化。特别地,CDI可匹配来自客户机类型映射和服务器类型映射的每个字段和类型,并创建仅包含访问接口的优化类型映射。当对两个对象实例执行此优化类型映射时,所有被请求的数据在无需任何中间存储或任何数据查找的情况下在两个对象之间传送。优化类型映射的目的是利用目标对象具有规则结构这一事实。对于给定集合,服务器方对象具有规则的结构。对于给定的查询,一般希望从系统中所有对象获得相同的数据。因此,特定源对象类和特定目标对象类之间的绑定总是相同的。此外,因为源和目标对象最终是系统组件,并且它们本身是规则的结构,所以每个对象实例都能以轻量 级的方式来存储。
进一步考虑,在仅有一个服务器对象可供从其检索数据的情况下,这将是足够的。但是,在实践中,可能有兼容的服务器对象的许多实现,且每种实现都具有一种类型映射。因此,当客户机向CDI注册其类型映射时,CDI为优化类型映射创建可根据GUID查找的存储空间。服务器方随即按需存储每个优化映射。目的是客户机在应用程序启动时注册其映射。然后该系统在客户机开始检索数据时围绕该特定客户机类型构建一组优化。
模板派生的类型映射
为类实例创建访问对象可能导致许多代码要被编写,因为每个接口后的每个实例都只知道如何访问一个属性。通过允许每个实例使用数据来访问服务器和客户机中的属性(例如,字段偏移量可被用来访问许多对象上普遍具有的字段),可省去大量工作。这样做大大减少了必须被编码的访问对象实现的个数。
在所示出并描述的实施例中,CDI还提供模板库,它允许用户定义类,创建若干方法或字段,然后编写一张公开他们想要定义的任何字段或方法的表。该模板机制从类字段类型或方法签名中直接提取类型信息,并自动构建访问对象实例。这允许客户机(或服务器)在无需编写IDL的情况下公开对象。然后该对象在该打印系统所支持的任何传输上受到支持,并将自动获得异步调用的益处。
以下代码节选示出定义客户机想要从服务器检索的结构的最简单的机制,其中省略了出错处理。
#include<iatl.h>
struct Clientprinter
{
ULONG Status;
BSTR Name;
BSTR Location;
BSTR Comment;
};
IMG_ATTR_TABLE_BEGIN(ClientPrinter,TypeMap)
Type(″Micrsoft.printer.Basic″),
Field(IMG_ATTR_FIEL(Status)),
Field(IMG_ATTR_FIELD(Name)),
Field(IMG_ATTR_FIELD(Location)),
Field(IMG_ATTR_FIELD(Comment)),
IMG_ATTR_TABLE_END
void
InitializeTypeMap(
Void
)
{
IImgCommonData *pICDI=NULL;
IImgTypeMap *pITypeMap=NULL;
CoCreateInstance(CLSID_ImgCommonData,
NULL,
CLSCTX_INPROC_SERVER,
IID_IImgCommonData,
Reinterpret_cast<void **>(&pICDI));
Img::iatl::RegisterTypeMap(pICDI,IMG_ATTR_TABLE(ClientPrinter,TypeMap), &pITypeMap);
//
// Do stuff with the type map.
//
pICDI->Release();
pITypeMap->Release();
return 0;
}
类型映射机制也允许调用者指定方法。以下代码节选示出在此情形中方法可被如何定义,其中省略了出错处理。
Class ServerClass
{
IMG_ATTR_TABLEFRIEND(ServerClass,TypeMap);
private:
HRESULT
SetComment(
BSTR newComment
)
{
BSTR tempComment=SysAllocString(newComment);
if (tempComment)
{
SysFreeString(Comment);
Comment=tempComment;
Return S_OK;
}
return E_OUTOFMEMORY;
}
BSTR
GetComment(
Void
)
{
return Comment;
}
BSTR Comment;
};
IMG_ATTR_TABLE_BEGIN(ServerClass,TypeMap)
Type(″Microsoft.Printer.Basic″),
Field(IMG_ATTR_METHOD(ServerClass::SetComment),″Comment″,gGetMethod),
Field(IMG_ATTR_METHOD(ServerClass::GetComment),″Comment″,gSetMethod),
\........../
IMG_ATTR_TABLE_END
在所示出并描述的实施例中,模板库支持一组从CDI类型到C++类型的核心映射。该库可由第三方扩展,从而新的类型可在任何时候被引入或改进,而根本无需改变模板库的任何部分。
使用公共数据接口
此节中给出的素材扩充了以上所描述的素材,但前者在更加低的等级进行描述。本文档的其余部分专供对根据一个实施例的CDI的使用和实现的低级描述。
CDI类型
CDI类型系统被设计成支持该系统提供保证的许多标准类型(例如,它们在该系统所支持的任何协议上起效,并且其中大多数可被用于查询)。CDI类型系统还提供在设计时创建新类型并在运行时在系统中使用这些新类型的机制。
为此目的,如在以下代码节选中所示地定义了ImgVariant类型。和系统Variant相似,它具有类型和未命名的联合。但是它支持一组与系统Variant非常不同的基本类型,如下表所示。
//
//这是复制者的基本变量类型。仅在两个对象之间的转换中使用。
//
typedef struct_tagImgVariant
{
ImgType type;
union
{
ULONG uLongVal;
ULONGLONG uLongLongVal;
BSTR bstrVal;
IImgImutableString *refStrVal;
DOUBLE doubleVal;
IStream *pXMLStreamType;
IImgCanonicalName *pINameVal;
IImgMultiValuedName *pIMultiNameVal;
ImgMultiString multiStringVal;
//
//这两个类型允许系统的其它用户在ImgVariant中存储他们自己的数据。保证支持最多至128位的任何
//值类型,或者指针。
//
void *potherVal;
unsigned char space[16];
};
} ImgVariant;
另一个不同之处是ImgVariant类型是可扩展的。这是通过不将ImgType定义为联合,而将其定义为指针来实现的。此声明在以下代码节选中示出。
//
//用来保留类型实例的结构。
//
typedef struct
{
ULONG dummy;
)ImgTypeReservation;
//
//类型被描述为指向保留的存储器段的指针
//
typedef ImgTypeReservation*ImgType;
为了保留新类型的枚举,就定义ImgTypeReservation全局变量,且其地址成为所定义的类型的有保证的唯一标识符。类似地,系统将定义其自己的类型为全局唯一的指针。这使用加载器来保证这些类型在任何地址空间上都不会冲突。
在所示出并描述的实施例中,该打印系统提供以下操纵Variant的方法。
interface IImgCommonData:IUnknown
{
HRESULT
VariantInitialize(
IN OUT ImgVariant *pImgVariant
);
HRESULT
VariantCopy(
[in,out] ImgVariant *pVariantDest,
[in] const ImgVariant *pVariantSource
);
HRESULT
VariantClear(
IN OUT ImgVariant *pImgVariant
);
HRESULT
VariantConvert(
[in,out] ImgVariant *pVariantDest,
[in] constImgVariant *pVariantSource,
[in] ImgType desiredType
);
};
新的CDI原子类型
CDI ImgVariant类型本身可包含由CDI定义的一些新的类型。按照顺序,这些是:
IImgImutableString
这是引用计数的串。此类型将被CDI自由转换为BSTR或从BSTR转换,且其提供对串的高效操纵。它的接口和创建函数在以下代码节选中示出。
typedef enum
{
FreeThreaded,
SingleThreaded
} EImgThreading;
[local]
interface IImgImutableString:IUnknown
{
const wchar_t*
Value(
void
);
HRESULT
NewInterface(
[in] EImgThreading clientType,
[out] IImgImutableString **ppINewString
);
};
interface IImgCommonData:IUnknown
{
HRESULT
ImgCreateString(
IN const wchar_t *string,
OUT IImgImutableString **ppIString
);
}
Value方法返回指向在不可变串内所维护的串的指针。调用者不能修改该值,但可以自由读取该值。它的地址不会改变,并且在该串引用被维护时,它不会被释放或修改。
NewInterface方法允许调用者请求到同一个串的新接口。这对隔离引用计数问题是有用的。调用者可请求到该串的单线程接口。在此情形中,对新接口的引用计 数不会被互锁。如果调用者知道它将在单线程上下文中对该串进行大量操纵,则这可允许它们提高其性能。由ImgCreateString创建的初始串总是自由线程的。
IImgCanonicalName
此类型由插件内部使用以提供对其它类型的规范名称引用。此类型在以下代码节选中示出。
typedef enum
{
AbsolutePath,
RelativePath,
ObjectRelative,
CollectionRelative,
ServerRelative
} EImgpathType;
[local]
interface IImgCanonicalName:IUnknown
{
ULONG
PathFieldCount(
void
);
HRESULT
PathField(
[in] ULONG cElem,
[out] IImgImutableString **ppIString
);
HRESULT
Path(
[out] BSTR *pbstrpath
);
EImgPathType
PathType(
void
);
HRESULT
NewInterface(
[in] EImgThreading clientType,
[out] IImgCanonicalName **pp工NewCanonicalName
);
};
interface IImgCommonData:IUnknown
{
HRESULT
CreateCanonicalName(
[in] const wchar_t *path,
[out]IImgCanonicalName **ppICanonicalName
);
HRESULT
CreateCanonicalNameFromStrings(
[in] EImgPathTy pepathType,
[in] ULONG cElems,
[in] IImgImutableString **paString,
[out] IImgCanonicalName **ppICanonicalName
);
}
规范名称包含对象路径的经语法分析的元素。每个元素都作为不可变串被存储。规范名称或可从路径创建,或可从一组不可变串直接构造。例如,对于路径“\{GUID}\abc^\def”,规范名称将包含两个串:“{GUID}”和“abc\def”。该接口还允许调用者从规范名称的子串构造路径,例如,它们可用串“ab\\cd”、“efg”创建规范名称,然后获得路径“ab^\^\cd\efg”。
和不可变串一样,规范名称是不可变的,并且可为线程或引用计数目的从其获得新的别名接口。
IImgMultiValuedName
多值名称被用来将用规范名称的引用返回给数个不同的对象。它被用来表示两个对象类之间的1-N或N-N关系。其接口在以下代码节选中示出。
typedef struct
{
ULONG cNames;
[size_is(cNames)] BSTR *abstrNames;
} ImgMultistring;
[local]
interface IImgMultiValuedName:IUnknown
{
ULONG
NameCount(
void
);
HRESULT
NameField(
[in] ULONG cElem,
[out] IImgCanonicalName **ppIName
);
HRESULT
GetNamesAsStrings(
[out] ImgMultiString *MultiString
);
HRESULT
NewInterface(
[in] EImgThreading clientType,
[out] IImgMultiValuedName **ppINewMultivaluedName
);
};
interface IImgCommonData:IUnknown
{
HRESULT
CreateMultiValuedName(
[in] ULONG cNames,
[in] IImgCanonicalName **ppINames,
[out] IImgMultiValuedName **ppIMultiValuedNames
);
HRESULT
FreeMultistring(
[in] ImgMultiString *String
);
HRESULT
CreateMultiValuedNameFromMultiString(
[in] const ImgMultiString *Strings,
[out] IImgMultiValuedName **ppIMultiValuedNames
);
}
多值名称可从一组规范名称构造,并且每个规范名称都可被检索。和不可变串及规范名称接口一样,它也是不可变的,并且可为引用计数或线程原因获得到它的新接口。
因为导航这些接口对调用者而言较为复杂,所以多值名称提供一种通过GetNamesAsStrings接口获取整个封闭的规范名称作为BSTR路径数组的机制。为了释放所返回的多串,ImgFreeMultiString调用被使用。此外,调用者可从路径的多串直接得到多名。这对于从一组静态路径构造多值名称特别有用。
注册新的Variant类型
标准Variant将总是在线路上正确封送,并且在系统所使用的查询语言中全部都有支持。但是,特别是对于进程内情形而言,扩展Variant类型将会是非常有用的。这允许创建诸如点等新的值类型、或是无需被转换为串的可打印区域。或者,它允许定义可作为命令的一部分被检索和操纵的接口。为此目的,CDI提供一种扩展可由VariantCopy、VariantClear和VariantConvert处理的Variant的机制。
此接口在以下代码节选中示出。
interface IImgVariantExtender:IUnknown
{
HRESULT
VariantCopy(
[in,out] ImgVariant *pDest,
[in] const ImgVariant *pSrc
);
HRESULT
VariantClear(
[in] ImgVariant *pVariant
);
HRESULT
VariantConvert(
[in,out] ImgVariant *pDest,
[in] constImgVariant *pSource,
[in] ImgType desiredType
);
}
typedef struct
{
ImgType inputType;
ImgType outputType;
} ImgVariantTypeConversion;
typedef struct
{
ULONG cImgVariantTypes;
[size_is(cImgVariantTypes)]const ImgType *aTypes;
ULONG cImgVariantConversions;
[Size_is(cImgVariantConversions)] const ImgVariantTypeConversion *aTypeConversions;
} ImgVariantTypeExtensionData;
interfaceIImgVariantExtensionRegistration:IUnknown
{
};
interface IImgCommonData:IUnknown
{
HRESULT
RegisterVariantExtension(
[in] constImgVariantTypeExtensionData *ExtensionData,
[in] IImgVariantExtender *pIExtender,
[out] IImgVariantExtensionRegistration **ppIRegistration
);
}
在此,需要在IImgVariantExtender接口中提供知道如何对所注册的类型执行所有这些操作。然后还要提供该接口所支持的一组类型、以及该接口将执行的一组转换。然后该系统将把它对Variant类型的处理扩展为包括为已被指定的类型调用这些接口。
如果提供了到标准Variant类型和从标准Variant类型的转换,则远程化层也将在线路上正确封送适当的数据。这允许在和服务器对象相同的进程内或在线路上透明地使用类型。
注册类型映射
客户机类型映射一经构造,它就被注册到CDI,并且一表示该类型映射注册的接口被返回给客户机。此对象聚集用来绑定到各个集合类的优化类型映射。目的是允许进程预先注册所有它打算使用的类型,然后从那时起便能够使用给定的类型映射。当优化类型映射被构建时,从对象查询数据所需的时间就变得很少,因为无需比较任何字段。用于注册类型映射的完整接口在以下代码节选中示出。
interface IImgAccessor;
typedef enum
{
//
//Bind-time discoverable errors,
//
SourceTypeDoesNotExist = 0x00000001,
SourceFieldDoesNotExist = 0x00000002,
SourceFieldTypeIncompatible = 0x00000004,
//
//Dynamic errors and properties.
//
SourceDataDoesNotExist = 0x00010000,
Private = 0x00020000,
Modified = 0x00040000,
CollectHistory = 0x00080000
} EImgCopyFlags;
typedef struct
{
EImgCopyFlags flags;
} ImgExtraCopyData;
typedef struct
{
[string] const wchar_t *type;
[string] const wchar_t *field;
ImgType fieldType;
IImgAccessor *pIAccessor;
[string] const wchar_t *description;
int_ptr tag;
} ImgFieldAccess;
typedef struct
{
ULONG cAccessors;
[size_is(cAccessors)] ImgFieldAccess *aAccessors;
} ImgFieldAccessors;
typedef struct
{
ImgFieldAccessors inputFields;
ImgFieldAccessors outputFields;
ImgCommandsDescription commands;
}ImgClassDescription;
[local]
interface IImgAccessor:IUnknown
{
HRESULT
Function(
[in] void *pobject,
[in,out] ImgVariant *pData,
[in,out] ImgExtraCopyData *pExtra
);
};
[local]
interface IImgTypeMap:IUnknown
{
};
[local]
interface IImgCommonData:IUnknown
{
HRESULT
RegisterTypeMap(
[in] ImgClassDescription *ClassDescription,
[out] IImgTypeMap **ppITypeMap
);
};
因为此接口使用了若干类型,所以以下考察其中每一个类型。
EImgCopyFlags
这些标志与复制操作相关联,它让客户机了解在复制数据时遇到的任何问题。其中大多数标志是意义自明的。其中一些较值得关注的标志有:
·Private - 该数据不应被复制到系统以外。被视为该系统的一个部分的其它进程可接收该数据。该数据将永远不会在线路上发送。
·NotModified - 指示该数据仍是与服务器上的版本一致而未被修改。这对优化一组操作而言可能是有用的。
·CollectHistory - 这个标志向CDI指示对此字段的改变的历史应被收集。默认行为是折叠字段的历史数据。
ImgExtraCopyData
这被传递给访问器以允许标志被访问器修改或插入。它还被用来在执行设置时将改变处理器传递给访问器,这允许改变处理器在属性值改变的情况下发送改变。
ImgFieldAccess
这指定一个字段。大多数结构字段是意义自明的。并非必须在客户机上指定该描述。在服务器上,此字段可被用于反射。此标记在服务器上被用来允许以低开销引用特定字段。传播该结构的任何事物都有责任保持该标记唯一。
ImgFieldAccessors
这指定一组字段访问器。
ImgClassDescription
这描述一个类,指定获取访问器和设置访问器。
IImgAccessor
此接口允许对特定字段的访问。ImgVariant临时存储该数据,并允许传递许多不同类型的数据。
IImgTypeMaps
此接口可由客户机释放。进而,在注册时被传递的所有访问器接口将被释放。
IImgCommonData
这是可被用来注册类型映射的中心接口。此接口可被释放,而类型映射注册将仍保持有效。
批处理接口
其余子章节(即,对象查询、对象命令和通知)以大量细节讨论数据访问接口。此节讨论什么是对象以及客户机如何获取、设置和查询对象。
客户机用来访问这些对象的接口在以下代码节选中示出。
typedef enum
{
Serial,
Parallel,
Transactional,
} EImgBatchSemantics;
interface IImgAsyncResult;
interface IImgCallCompletion;
interface IImgBatch;
interface IImgCommonData;
interface IImgClientCollection;
typedef enum
{
ActionCompleted,
ActionPartiallyCompleted,
ActionFailed,
ActionDidNotExecute,
ActionBatchDidNotExecute
} EImgCompletionStatus;
[local]
interface IImgAsyncResult:IUnknown
{
void*
GetCookie(
void
);
void
SetCookie(
[in] void *cookie
);
HRESULT
GetWaitHandle(
[out] HANDLE *pWaitHandle
);
BOOL
CompletedSynchronously(
void
);
BOOL
DidComplete(
void
);
}
[local]
interface IImgCallCompletion:IUnknown
{
HRESULT
Done(
[in] IImgAsyncResult *pIResult
);
};
[local]
interface IImgBatch:IUnknown
{
HRESULT
GetObjectData(
[in,string] constwchar_t *objectPath,
[in] IImgTypeMap *pITypeMap,
[in,out] void *pobject,
[out,unique] ULONG *pulActionIndex
);
HRESULT
SetobjectData(
[in,string] constwchar_t *objectpath,
[in] IImgTypeMap *pITypeMap,
[in] void *pobject,
[out,unique] ULONG *pulActionIndex
);
HRESULT
IssueCommandToObject(
[in,string] const wchar_t *objectpath,
[in,string] const wchar_t *pType,
[in,string] const wchar_t *pCommand,
[in] ULONG cparams.
[in,size_is(cparams)] ImgVariant *aimgVariant,
[out,unique] ULONG *pulActionIndex
);
HRESULT
QueryObjectData(
[in,string] const wchar_t *objectBase,
[in,string] const wchar_t *objectClass,
[in,string] const wchar_t *queryString,
[in] IImgClientCollection *pIClientCollection,
[out,unique] ULONG *pulActionIndex
);
HRESULT
Execute(
void
);
HRESULT
BeginExecute(
[in,unique] IImgCallCompletion *pICallCompletion,
[out,unique] IImgAsyncResult **ppIAsyncResult
);
HRESULT
EndExecute(
[out] EImgCompletionStatus *pCompletion
);
//
//调用这些方法以从每个调用检索额外的输出信息。
//
HRESULT
ResultGetObjectData(
[in] ULONG ulIndex,
[out] EImgCompletionStatus *pCompletion
);
HRESULT
ResultSetObjectData(
[in] ULONG ulIndex,
[out] EImgCompletionStatus *pCompletion
);
HRESULT
ResultIssueCommand(
[in] ULONG ulIndex,
[out] EImgCompletionStatus *pCompletion,
[out,unique] ImgReturnParams *pParams
);
HRESULT
ResultQueryObjectData(
[in] ULONG ulIndex,
[out] EImgCompletionStatus *pCompletion
);
HRESULT
ExtendedErrorResult(
[in] ULONG ulIndex,
[out] IErrorInfo **ppIErrorInfo
);
//
//取消批次上任何未决操作的方法。
//
HRESULT
Cancel(
[out] EImgCompletionStatus *pCompletion
);
};
[local]
interface IImgCommonData:IUnknown
{
HRESULT
GetDataBatch(
[in] EImgBatchSemantics semantica,
[out] IImgBatch **ppIBatch
);
};
[local]
interface IImgClientCollection:IUnknown
{
HRESULT
AllocateObject(
[out] void **ppObject
);
void
FreeObject(
[in] void *pObject
);
};
此访问接口公开新的概念,作为示例而非限制,这些新的概念包括:
·批处理接口(IImgBatch)
·异步编程机制(IImgAsyncResult)
·客户机集合接口(IImgClientCollection)
首先将抽象地讨论其中每一个接口,然后将示出可能的调用序列的示例以使这些概念更加具体化。
向数据访问接口发布的所有动作都被批处理。批处理接口从对IImgCommonData::GetDataBatch()的调用返回,然后向批处理接口发布一组动作,最后该批次被执行。如果调用者想要发布单个动作,则他们只要创建一个动作的批处理请求。
在Execute方法被调用以前没有任何动作被执行。Execute可被同步或异步调用(取决于调用了Execute还是BeginExecute)。调用者可传入完成接口,或可使用从IImgAsyncResult接口返回的等待句柄。规则是,如果调用者的确传入了完成接口,则它们不能检索等待句柄。调用者可通过cookie接口将相关联的额外数据与调用相关联。CDI保证在调用完成接口中将会调用Done方法以允许cookie在需要的情况下被释放。调用者必须调用EndExecute调用来检索批处理调用的结果。
调用者可将批次作为串行、并行或事务式批次打开。非事务式批次可能会有部分成功返回,而事务式批次则不会。不幸的是,不是所有集合都支持事务(它们可能会与不支持事务的下级系统通信),并且如果该批次的任何动作与非事务式集合相交,则整个批次都将失败。因此,根据一个实施例,事务式批处理主要可在系统内部执行,或仅在服务器版本已被肯定地标识的情况下被执行。
对于一些如“暂停所有打印机”等可批处理的动作而言,进行事务式处理是没有意义的,因为在一个队列未能暂停的情况下,人们会宁愿使一半队列被暂停而不是没有一个队列被暂停。如果批次的语义是串行的,则可保证该批次中的动作被依次执行。如果批次的语义是并行的,则系统可在有充分资源的情况下,或在这是最优方案的情况下并行地执行动作。这意味着对于并行批次语义而言,任何动作可按任何顺序失败。事务式批次也蕴含顺序语义。
批次中的每个都作返回递增的索引。调用者如果无需检索批次调用(可以是事务式批次,且该批次的状态是该动作的状态)的结果则它们可以忽略索引。每个调用的结果可通过调用批处理接口中对应的“Result”方法来检索。如果调用报告出错,则可从批次返回经扩展的出错信息。
同步和异步形式的执行除了在异步情形中,返回状态是从EndExecute调用返回以外其它都是相同的。因为批处理命令可并行执行,所以批次可以有部分失败结果。因此在调用者期望的情况下,可查询每个索引来准确地确定哪个调用失败,以及失败的原因是什么。
根据一个实施例,批处理接口上的方法概述如下:
·GetObjectData - 此方法使用给定类型映射和调用者所指定的对象从给定对象名检索数据。
·SetObjectData - 此方法使用要进行写的给定类型映射(客户机集合和服务器集合之间的访问器被颠倒)和要从其检索数据的对象来将数据写到给定对象。注意,如果数据正被发送到远程目的地,则这些内容将被提前从对象复制出来。如果是对本地对象设置该数据,则这些内容将在稍后当实际的设置发生时被复制出来。
·QueryObjectData - 此方法发布对某个对象类的查询。查询将在以下更加详细地讨论。除了将从集合分配许多对象而不只是一个对象以满足查询这一点以外,查询在概念上非常类似于Get命令。
·IssueCommandToObject - 此方法向对象发布命令。命令将在以下更加详细地讨论。命令是向给定对象上的特定类型发布的。命令本身是unicode串,它接收输入参数的有序列表。输出参数可由调用者通过ResultIssueCommand调用检索。
·Execute - 此方法使迄今要被批处理的的所有命令被执行。
·Cancel - 此方法取消在Execute调用以后目前正在进行中的任何动作。它还在该调用被执行以前刷新来自批处理接口的任何命令。
批处理接口只可在Cancel调用返回以后,或在同步Execute调用完成或异步EndExecute调用返回以后被重用。
图6示出批次调用命令的图示。此例假定IImgDataBatch接口构建要被执行的命令的列表。
查询、命令和通知在后续章节中被详细覆盖。由此,以下示出获取对象的状态、然后改变对象的名称和注释、并再次应用这些改变的示例性代码片段。该代码是以异步回调形式编写以说明异步批处理接口,但是实际上它并不需要此复杂性。
struct ClientPrinter
{
ULONG Status;
BSTR Name;
BSTR Location;
BSTR Comment;
Clientprinter(
void
)
{
ZeroMemory(this,sizeof(*this));
}
~Clientprinter(
void
)
{
SysFreeString(Name);
SysFreeString(Location);
SysFreeString(Comment);
}
};
IMG_ATTR_TABLE_BEGIN(Clientprinter,TypeMap)
Type(″Micrsoft.Printer.Basic″),
Field(IMGA_TTR_FIELD(Status)),
Field(IMG_ATTR_FIELD(Name)),
Field(IMG_ATTR_FIELD(Location)),
Field(IMG_ATTR_FIELD(Comment)),
IMG_ATTR_TABLE_END
class Operations:public IImgCallCompletion
{
public:
Operations(
IN IImgDataBatch *pIBatch,
IN IImgTypeMap *pITypeMap
)
{
m_pIBatch=pIBatch;
m_pITypeMap=pITypeMap;
m_pIBatch->AddRef();
m_pITypeMap->AddRef();
}
~Operations(
void
)
{
m_pIBatch->Release();
m_pITypeMap->Release();
}
//
//在此插入你最喜欢的Iuknown实现。
//
void
StartOperation(
Void
)
{
//
//通常我们将通过查询获取此对象规范名称。
//
m_pIBatch->GetObjectData(L″{4810742c-c8d9-44c3-81bb-c3ff5f83d762}\″
L″{f5ddca93-06f9-40c3-8c7f-a61c3e390fae}″,
m_pITypeMap,
&m_clientPrinter,
NULL);
//
//我们不需要异步结果,我们只需将我们自己的接口传入到批次中。
//
m_pIBatch->BeginExecute(this,NULL);
}
//
//IImgCallCompletion实现。
//
STDMETHODIMP
Done(
IN IImgAsyncResult *pIResult
)
{
m_pIBatch->EndExecute();
//
//改变名称和注释。
//
SysFreeString(m_clientprinter.Name);
SysFreeString(m_clientprinter.Comment);
m_clientprinter.Name=SysAllocString(L″New Name″);
m_clientprinter.Comment=SysAllocString(L″There is a commenthere.″);
//
//应用该改变,这次是同步地。
//
m_pIBatch->SetObjectData(L″{4810742c-c8d9-44c3-81bb-c3ff5f83d762}\″
L″{f5ddca93-06f9-40c3-8c7f-a61c3e390fae}″,
m_pITypeMap,
&m_clientprinter,
NULL);
m_pIBatch->Execute();
}
private:
IImgDataBatch *m_pIBatch;
IImgTypeMap *m_pITypeMap;
Clientprinter m_clientPrinter;
}
int main(void)
{
IImgCommonData *pICDI=NULL;
IImgTypeMap *pITypeMap=NULL;
CoCreateInstance(CLSID_ImgCommonData,
NULL,
CLSCTX_INpROC_SERVER,
IID_IImgCommonData,
Reintpret_cast<void**>(&pICDI));
Img::iatl::RegisterTypeMap(pICDI,IMGATTR_TABLE(ClientPrinter,TypeMap),&pITypeMap);
IImgDataBatch *pIBatch=NULL;
pICD->GetDataBatch(NonTransactional,&pIBatch);
Operations*pOperations=newOperations(pIBatch,pITypeMap);
pOperations->StartOperation();
//
//休眠10秒以允许进行获取和设置。
//
Sleep(10000);
pOperations->Release();
pIBatch->Release();
pICDI->Release();
pITypeMap->Release();
return 0;
}
对象查询
这一节描述对象查询。由IDataAccessBatch公开的接口在以下示出。
[local]
interface IImgBatch:IUnknown
{
HRESULT
QueryObjectData(
[in,string] const wchar_t *objectPath,
[in,string] const wchar_t *objectBase,
[in,string] const wchar_t *objectBaseClass,
[in,string] const wcbar_t *desiredObjectClass,
[in,string] const wchar_t *queryString,
[in] IImgClientCollection *pIClientCollection,
[out,unique] ULONG *pulActionIndex
);
HRESULT
ResultQueryObjectData(
[in] ULONG ulIndex,
[out] EImgCompletionStatus *pCompletion
);
};
typeMap和clientCollection参数已经讨论过。queryString参数控制查询。如果它是null,则该查询请求如查询基所指定的给定类型的所有对象。如果它不为null,则它为查询指定过滤器。查询包含查询基、查询类和查询串。查询串将在稍后讨论。查询基是查询的根对象,即,它是可认为其它对象存在于其下的那个对象(作业枚举的查询基可以是打印机或服务器对象)。查询基关系通常不是分层结构,而是关系型的(即,不能枚举查询基两级以下的对象)。但是,和严格的分层结构不同,对象可被定位在许多不同的查询基下。这反映了底层存储是关系型的这一事实。支持查询基的主要原因是允许查询的基于下级枚举的实现能很容易地找到对应于该枚举的根对象。但是,查询基使得对上级情形的查询的语法分析复杂化。
下表中示出查询和类型的示例性列表。注意,集合中的对象可能并不使用集合的编程名称。它们应当使用友好名称的名称解析机制,然后内部地使用数字的对象名称来引用该对象。允许使用编程名称来进行查询来指定集合,因为串更加可能是由人类装配而成。
注意,不要求远程集合为对本地机器的查询返回任何对象。要它们查询所有服务器效率过于低下。查询串是指定给定对象必须具有的属性的过滤器。字段采取以下形式:
Programmatic.Type.Name.Version:FieldName.
将来的查询可被允许访问嵌入在数据中的XML文档内的数据。这些查询将采取以下形式:
Programatic.Type.Name.Version:FieldName\Node\Node\Property.
下表中示出有效运算符及其优先级。
只可对照常量来比较字段。以下是有效的常量:
·任何整数。整数可用十进制或十六进制形式表达。
·任何浮点数。
·任何以引号在字面上划界的串。如果引号必须是该串的一个部分,则使用BASIC样式的“”。
下表中示出有效的查询。为简化一些经常被访问的对象的语义,可以有允许可与下级服务器更容易地进行相互操作的定义良好的查询基。这些将包括——
·打印队列查询-查询基应为包含该打印队列的服务器对象。
·作业对象查询-查询基应为包含这些作业的队列或服务器对象。
根据一个实施例,以下约束适用于查询:
·如果查询对照数字类型(整数或者浮点)比较字段,则实际的字段必须是数字的(32位整数、64位整数或双精度浮点)。
·如果查询对照串类型比较字段,并且比较运算符不是CONTAINS,则唯一有效的字段类型是BSTR或IImgImutableString。
·CONTAINS运算符仅对串类型生效。对于单值的串,它等于检查相等性。对于规范名称,它等于检查路径是相同的。对于多串,它等于检查多串中的任何串是否相等。对于多值名称,它等于检查由多值名称中的任何规范名称所表达的任何路径是否等于CONTAINS运算符所引用的串。
·按位与运算仅适用于整数类型。
为使此讨论更加具体化,以下代码节选给出一个示例。此例查询一组打印对象,然后枚举它们。此例使用IAsyncResult接口的可等待形式。同样,在此情形中这不是必须的,但它示出了该接口的另一个用法。注意,我们使用模板库中为调用者自动构建IImgClientCollection和枚举器的特征。为简略起见省略了出错处理。
struct ClientJob
{
ULONG Status;
BSTR DocumentName;
ClientJob(
void
)
{
ZeroMemory(this,sizeof(*this));
}
~ClientJob(
void
)
{
SysFreeString(DocumentName);
}
};
IMGATTR_TABLE_BEGIN(ClientJob,TypeMap)
Type(″Micrsoft.Job.Basic″),
Field(IMG_ATTR_FIELD(Status)),
Field(IMG_ATTR_FIELD(DocumentName)),
IMG_ATTR_TABLE_END
int main(void)
{
IImgCommonData *pICDI=NULL;
IImgTypeMap *pITypeMap=NULL;
CoCreateInstance(CLSID_ImgCommonData,
NULL,
CLSCTX_INPROC_SERVER,
IID_IImgCommonData,
reinterpret_cast<void **>(&pICDI));
Img::iatl::RegisterTypeMap(pICDI,IMGATTR_TABLE(ClientJob,TypeMap),&pITypeMap);
Img::iatl::TClientCollection<ClientJob>*pClientCollection=new
Img::iatl::TClientCollection<ClientJob>();
IImgDataBatch *pIBatch=NULL;
pICD->GetDataBatch(NonTransactional,&pIBatch);
//
//查询本地机器上属于Toe Knee Heart且长度超过120kB的所有作业。
//
pIBatch->QueryObjectData(NULL,
L″Microsoft.Job″,
L″Microsoft.Job.Basic:UserName=\″ToeKneeHeart\″AND″
L″Microsoft.Job.Basic:Size>120000″,
pClientCollection,
NULL);
IImgAsyncResult *pIAysncResult=NULL;
pIBatch->BeginExecute(NULL,&pIAsyncResult);
HANDLEhEvent=NULL;
//
//获取可等待的句柄,在数据就绪时它将被通知。
//
pIAsyncResult->GetWaitHandle(&hEvent);
//
//在查询未决时可做任何想做的事。
//
WaitForSingleObject(hEvent,INFINITE);
EImgBatchCompletionStatus status;
pIBatch->EndExecute(&status);
Img::iatl::TClientCollection<ClientJob>::Iterator i(pCollection);
For(i.Init();!i.Done();i.Next())
{
ClientJob *pClientJob=i.Current();
pClientJob->DocumentName,
pClientJob->Status);
}
pIAsyncResult->Release();
pClientCollection->Release();
pIBatch->Release();
pICDI->Release();
pITypeMap->Release();
return 0;
}
对象命令
和对对象集合的查询一样,可向给定对象发布命令。
对对象的命令被绑定到类型,包括该对象可具有的来自其它集合的任何嵌入类型。这允许在每实例的基础上扩展对象的命令集。
根据一个实施例,命令具有以下属性:
·命令永远不被高速缓存,而数据可被高速缓存。
·命令可超越失败异常向调用者返回参数。
·命令具有一组固定的有序输入和输出参数。命令不能被重载或扩展。
命令的语义在系统的新版本上永远不能改变。(命令可能会过时并且最终可能停止支持。)
命令将被用于对象构造和对象删除。对于对象删除,定义了预定义的类型和方法——“Microsoft.GenericObject.1”命令“Delete”。删除命令不需要参数也不返回参数。所有可删除的对象都被要求公开此命令。所有嵌入的对象也被要求公开此命令。当嵌入对象的包含对象被删除时,它将要求所有嵌入对象将它们自己删除。
所有可保护对象将被要求公开的另一个命令是“Microsoft.GenericObject.1”命令“AccessCheck”,此命令取单个参数——许可对象,并返回真或假。此命令被嵌入类型用来确保在它们被通过自己的集合访问时,它们强制执行了和包含对象相同的安全语义。
从命令调用结果返回的参数的生命期和批次的生命期是一样的。当批次被释放、取消,或者对该批次执行了另一个动作,则命令参数将被清除。
最后,以下给出命令接口的示例性用法。此例从已被发现的打印队列请求流 对象。
int Main(void)
{
IImgCommonData *pICDI=NULL;
CoCreateInstance(CLSID_ImgCommonData,
NULL,
CLSCTX_INPROC_SERVER,
IImg_ICommonData,
reinterpret_cast<void**>(&pICDI));
pICDI->GetDataBatch(NonTransactional,&pIBatch);
ULONG ulIndex=0;
ImgReturnParams params;
EImgCompletionStatus completion;
pIBatch->IssueCommandToObject(L″{4810742c-c8d9-44c3-81bb-c3ff5f83d762}\″
L″{f5ddca93-06f9-40c3-8c7f-a61c3e390fae}″,
L″Microsoft.Printer.Basic″,
L″GetJobStream″,
O,NULL,
&ulIndex);
pIBatch->Execute();
pIBatch->ResultIssueCommand(ulIndex,&completion,¶ms);
//
//检查作业参数和类型
//
if(completion==ActionCompleted && params.cParams==1 &&
params.aParams[0].type==CustomTypeJobStream)
{
IJobStream *pIJobStream=(IJobStream)params.aParams[0].potherVal;
pIJobStream->AddRef();
//
//对该作业流执行某些动作
//
pIJobStream->Release();
}
pIBatch->Release();
//
//现在Params将指向无用单元
//
pICDI->Release();
return 0;
}
通知
通知也可从对象、对象类、服务器或集合接收。此接口也被从客户机批处理。
该接口如下所示。
typedef enum
{
NotifyAddNewObject,
NotifyAddMatchedFilter
} EImgNotifyAddReason;
tyPedef enum
{
NotifyRemoveDeletedObject,
NotifyRemoveDoesNotMatchFilter
} EImgNotifyRemoveReason;
typedef enum
{
NotifyUpdatepopulate,
NotifyUpdate
} EImgNotifyUpdateReason;
[local]
interface IImgBatch:IUnknown
{
HRESULT
RegisterNotificationCollection(
[in,string] const wchar_t *objectBase,
[in,string] const wchar_t *objectClass,
[in,string] const wchar_t *queryString,
[in] IImgNotificationCollection *INotificationCollection,
[in] IImgTyPeMap *pITypeMap,
[in,unique] IImgCallCompletion *pICallCompletion,
[out] ULONG *pulActionIndex
);
HRESULT
ResultNotificationCollection(
[in] ULONG ulIndex,
[out] EImgCompletionStatus *pCompletion,
[out] IImgNotificationChannel **ppIChannel
);
};
[local]
interface IImgNotificationChannel:IImgAsyncResult
{
HRESULT
populate(
void
);
HRESULT
Update(
void
);
}
[local]
interface IImgNotificationObject:IUnknown
{
HRESULT
BeginNotifyChanges(
[in] EImgNotifyUpdateReason reason
);
HRESULT
EndNotifyChanges(
void
);
HRESULT
GetRealobjectAddress(
[out] void **ppObject
);
};
[local]
interface IImgNotificationCollection:IUnknown
{
HRESULT
Addobject(
[in] EImgNotifyAddReason reason,
[out] IImgNotificationobject **ppIobject
);
void
Removeobject(
[in] EImgNotifyRemoveReason reason,
[in] IImgNotificationobject *pIobject
);
};
此接口公开若干新的概念,作为示例而非限制,其中包括了通知集合、通知对象、通知过滤器、以及通知通道。此接口用另外两个动作RegisterNotificationCollection和ResultNotificationCollection来扩展批处理接口。
通知集合是具有略为丰富的语义的客户机集合。它是同类客户机对象的集合。每个对象都可用一个类型映射来描述。当发生针对特定对象改变的通知时,或者如果一对象被添加,则该对象被检索,然后被填充。当对象的新数据已被放置于其中时,该对象上的EndNotifyChanges方法被调用以允许一旦对象被更新,实现者即可执行任何必须的处理。
由调用者指定的通知集合将总被串行地更新(即,它可由多个线程调用,但是每次只有一个线程将调用它)。通知集合只有在对通道进行Populate(填充)或Update(更新)调用时才会被更新。因此,如果调用者正在对其对象执行多线程的访问,则调用者可通过在Populate或Update调用周围放置适当的锁来保护其对象。如果调用者对通知指定了回调,则每次只有单个线程被保证在回调中执行。
通知按以下方式工作。当对通道进行Populate调用时,对象将通过Add(添加)方法被从指定的集合分配。然后将用BeginNotifyChanges调用来调用这些对象,而在此时这是更新周期还是填充周期的信息将会被传入对象中。
然后,通过通知通道接收到通知。如果调用者指定了回调,则当接收到新的更新时(或当该通道出错时)回调将被调用。如果调用者没有指定回调,则将会有等待句柄可用,或可用IsCompleted方法轮询该通道。通知是由子系统接收的,但 在对通道调用Update方法以前不被应用于客户机对象。如果通道由于某个原因而中断,则更新将返回适当的错误。
在对Update的调用期间,将用服务器上有所改变的任何属性更新客户机对象。如果在服务器上创建了任何新的对象,或如果它们如今匹配通知过滤器,则集合将接收对Add方法的调用,并将被告知通知的原因是该对象现在匹配过滤器,还是该对象是新的。
类似地,如果任何对象现在的确匹配过滤器,或如果它们已被删除,则集合上的Remove(移除)方法被调用。
对象是通过对其属性的直接调用来更新的。更新将由对BeginNotifyChanges和EndNotifyChanges方法的调用括在一起。
当调用者想要停止接收通知时,它们释放它们所接收的INotificationChannel接口。
以下示出从集合中的所有本地对象接收对应于两个字段的通知的示例性代码。此示例性代码接收本地集合中所有打印机的Status(状态)和Name(名称)字段的改变。假定查询的结果是在屏幕上更新打印机。为可读性起见,出错处理被省略。
class MyNotificationobject:public IImgNotificationObject
{
//
//在此处插入您最喜欢的IUnknown实现。
//
STDMETHODIMP
BeginNotifyChanges(
INEImgNotifyUpdateReason reason
)
{
return S_OK;
}
STDMETHODIMP
EndNotifyChanges(
void
)
{
//
//将我的对象状态写出到屏幕。
//
return S_OK;
}
STDMETHODIMP
GetRealObjectAddress(
OUT void **ppvObject
)
{
*ppvObject=this;
return S_OK;
}
IMG_ATTR_TABLE_FRIEND(MyNotificationObject,TypeMap);
private:
BSTR Name;
ULONG Status;
};
IMGATTR_TABLE_BEGIN(ClientJob,TypeMap)
Type(″Micrsoft.Printer.Basic″),
Field(IMG_ATTR_FIELD(Name)),
Field(IMG_ATTR_FIELD(Status)),
IMG_ATTR_TABLE_END
class MyNotificationCollection:public IImgNotificationCollection
{
public:
//
//在此处插入您最喜欢的IUnknown实现。
//
STDMETHODIMp
AddObject(
IN EmgNotifyAddReason addReason,
OUT IImgNotificationObject **ppIObject
)
{
MyNotificationObject *pNotifyObject=new MyNotificationObject;
//
//第一次在UI中显示通知对象
//
*ppIObhect=pNotifyObject;
return S_OK;
}
STDMETHODIMP_(void)
Remove(
IN EImgNotifyRemoveReason remoteReason,
IN IImgNotificationObject *pINotifyObject
)
{
//
//将通知对象从uI远程化。并移除对其的任何引用。
//
pINotifyObject->Release();
}
}
int main(void)
{
IImgCommonData *pICDI=NULL;
IImgTypeMap *pITypeMap=NULL;
ImgGetDataInterface(&pICDI);
Img::iatl::RegisterTypeMap(pICDI,IMG_ATTR_TABLE(MyNotificationObject,TypeMap),&pITypeMap);
IImgDataBatch *pIBatch=NULL;
MyNotificationCollection *pMyCollection=new MyNotificationCollection();
pICDI->GetDataBatch(NonTransactional,&pIBatch);
ULONG ulIndex=0;
//
//找出关于所有本地打印机的信息,不使用过滤器。
//
pIBatch->RegisterNotificationCollection(NULL,
″Microsoft.printers″,
NULL,
pMyCollection,
pITypeMap,
NULL,
&ulIndex);
pIBatch->Execute();
IImgNotificationChannel *pIChannel=NULL;
EImgCompletionStatus status;
HANDLE hEvent=NULL;
pIBatch->ResultNotificationCollection(uLIndex,&status,&pIChannel);
//
//从通知通道获取等待句柄。
//
pIChannel->GetwaitHandle(&hEvent);
//
//填充信道,在这个时间点集合将获取填充信道所需的所有回调。
//
pIChannel->populate();
do
{
//
//任何时候一有改变这就会被通知。
//
waitForSingleObject(hEvent,INFINITE);
//
//我们知道在我们调用更新以前通知集合和对象不会被触及。在此调用上任何错误都将被返回。
//
pIChannel->Update();
} while(1);
pIChannel->Release();
pMyCollection->Release();
pIBatch->Release();
pICDI->Release();
pITypeMap->Release();
return 0;
}
客户机集合
CDI接口的一个方面,即填充客户机集合和客户机对象而不是将数据写入某种中间数据对象并传播该数据集这一选择带有一些优点。
例如,这样做允许以非常相似的方式对待通知和数据填充。从客户机的角度来看,这意味着可非常容易地在这两种情形之间重用客户机对象。此外,这样做允许客户机代码变得极为高效。特别地,一旦数据被集合到客户机对象中,它即可作 为结构内的偏移量被本机地引用。如果数据被存储在中间集合中,则或是客户机不得不进而将该数据复制到某些客户机对象中以操纵该数据,或是每次都必须从集合检索该数据。
此外,填充客户机集合和客户机对象将客户机代码中的失败条件限制于该数据被填充的时候,而不是从集合复制该数据的时候。这就有实质上降低客户机代码复杂性的潜在可能。当使用中间集合时,只要集合中的数据被访问,就有失败的可能。
此外,填充客户机集合和客户机对象允许使用多种中间集合。本质上,此机制封装完全灵活的构建器模式。这意味着通用的“客户机”可动态地构建类型映射,并将其映射到其所希望的任何一种中间集合。这可被用来为托管数据提供程序构建数据集对象。或者,它可被用来构建数据的XML视图。这可在没有因中间数据集的插入所引起的任何保真度或性能损失的情况下实现。此外,一相关属性是填充客户机集合和客户机对象允许客户机集合实际上成为以可被容易地远程化的形式准备数据的访问适配器。但是,在消极方面,它可能强制客户机对象为它想要检索的每个属性公开访问器。
动态类型映射
所示出并描述的实施例可被用来解决当用户想要有一个对象实例,但是想要能够根据调用条件从服务器对象动态地检索不同的字段时的情况。有两种可能发生此问题的情形——其一是,当有具有许多属性的具体对象,但调用者想要在给定调用中传播的实际属性是动态的时候;以及,另一情形是当调用者真的想要完全动态地处理数据的时候。在所示出并描述的体系结构中,每种情形都具有解决方案。
为解决第一个问题,所示出并描述的实施例使用与每个属性相关联的标记来从该类构建子集动态类型映射。这些标记也可被指定为模板库的一个部分。模板库将检索只匹配所指定的标记的部分类型映射。此解决方案在以下代码节选中示出。
struct Clientprinter
{
enum FieldTags
{
Status,
Name,
Location,
Comment
};
ULONG Status;
BSTR Name;
BSTR Location;
BSTR Comment;
};
IMG_ATTR_TABLE_BEGIN(ClientPrinter,TypeMap)
Type(″Micrsoft.printer.Basic″),
Field(IMG_ATTR_FIELD(Status), ClientPrinter.FieldTags.Status),
Field(IMG_ATTR_FIELD(Name), Clientprinter.FieldTags.Name),
Field(IMG_ATTR_FIELD(Location), ClientPrinter.FieldTags.Location),
Field(IMG_ATTR_FIELD(Comment), ClientPrinter.FieldTags.Comment),
IMG_ATTR_TABLE_END
void
InitializeTypeMap(
Void
)
{
IImgCommonData *pICDI=NULL;
IImgTypeMap *pITypeMap=NULL;
int_ptr Tags[]={ ClientPrinter.FieldTags.Name,
Clientprinter.FieldTags.Comment};
ImgGetDataInterface(&pICD);
Img::iatl::RegisterTypeMap(pICDI,
IMG_ATTR_TABLE(ClientPrinter,TypeMap),
tags,
&pITypeMap);
//
//对类型映射进行操作
//
pICDI->Release();
pITypeMap->Release();
}
允许从远程服务器检索完全是运行时确定的一组完全随机的属性还可通过类型映射接口来实现。但是在此情形中,不能仅令一组属性绑定到类。在此情形中,实际上起作用的是低级类型映射接口的能力和灵活性。在此情形中,调用者可利用每个接口也是一对象实例这一事实,并可直接使用Variant类型。此概念在图7中示出。
图中,每个接口实际上指向一个对象而不是静态方法或字段。每个对象维护关于它应如何操纵最终目标对象的某种状态。在此例中,它维护目标对象所维护的对象数组中的索引。目标对象的数组大小是可变的,且委托对象和类型映射可被动态构建。因此,此机制允许调用者绑定到任何源对象,并允许即时创建任何源对象。
在所示出并描述的实施例中,此机制实际上完全是通用的。没有特定理由让这些接口不能参与构建XML文档、创建数据集或将数据写到屏幕。它还可被用来以任何形式构建对象集合。这在桥接到长角系统(longhorn)API或其它数据访问API时非常有用。
以下示出实现此方案的代码,包括通过批处理接口访问一个对象(出错处理被省略)
class DestinationObject
{
public:
DestinationObject(
int arraySize
)
{
m_apVariant=new ImgVariant[arraySize];
m_apSize=arraySize;
}
~DestinationObject(
void
)
{
for(int i=0;I<m_apSize;i++)
{
ImgVariantClear(&m_apVariant[i]);
}
delete[]m_apVariant;
}
private:
friend class ObjectAccessor;
ImgVariant *m_apVariant;
int m_apSize;
};
class ObjectAccessor:publicIImgAccessor
{
public:
ObjectAccessor(
Int index,
IImgCommonData *pICDI
):m_index(index),
m_pICDI(pICDI)
{
m_pICDI->AddRef();
}
-ObjectAccessor(
)
{
m_pICDI->Release();
}
//
//首选的标准IUnknown实现
//
//
// IImgAccessor
//
STDMETHODIMp
Function(
IN void *pObject,
IN OUT ImgVariant *pData,
IN OUT ImgExtraCopyData *pExtra
)
{
DestinationObject*object=reinterpret_cast<DestinationObject*>(pObject);
return m_pICDI->VariantCopy(&object->m_apVariant[m_index]);
}
private:
int m_index;
IImgCommonData *m_pICDI;
};
int main(void)
{
IImgCommonData *pICD=NULL;
CoCreateInstance(CLSID_ImgCommonData,
NULL,
CLSCTX_INPROC_SERVER,
IImgCommonData,
reinterpret_cast<void**>(pICDI));
//
//构建一种访问Microsoft.Printer.Basic:Location、注释和状态的机制。
//
ImgFieldAccessor Accessors[]=
{
{″Microsoft.Printer.Basic″,″Location″,ImgVariantType,new ObjectAccessor(0,pICDI)},
{″Microsoft.Printer.Basic″,″Comment″,ImgVariantType,new ObjectAccessor(1,pICDI)},
{″Microsoft.Printer.Basic″,″Status″,ImgVariantType,new ObjectAccessor(2,pCDI)},
};
ImgClassDescription ClassDescription=
{
{ COUNTOF(Accessors),Accessors},
{ 0 },
{ 0 },
};
IImgTypeMap *pITypeMap=NULL;
IImgBatch *pIBatch=NULL;
ImgGetDataInterface(&pICD);
pICD->RegisterTypeMap(&ClassDescription,&pITypeMap);
//
//现在我们可对目标对象使用该类型映射
//
pICD->GetBatch(&pIBatch);
DestinationObject destObj(3);
pIBatch->GetObjectData(L″{8e677748-cd3e-440f-ae30-eecec8c8017f}\62756091-4744-4896-b077-73ad0974d923}
pITypeMap,&destObj,NULL);
pIBatch->Execute();
//
//现在...destobj中将有位置、状态和注释。
//
pICD->Release();
pITypeMap->Release();
pIBatch->Release();
Accessors[0]->pIAccessor->Release();
Accessors[1]->pIAccessor->Release();
Accessors[2]->pIAccessor->Release();
return 0;
}
属性模板库和继承
模板库值得关注的方面之一是它支持对象之间的继承(包括多继承)。这在客户机上没有像在服务器中那么有用。在服务器上,这允许公共功能以及对应的字段和方法被存储在基类中,并在需要的情况下被带入派生类中。
除了支持继承以外,该库还正确地处理虚方法。即,可在基类类型映射中引用基类中的虚方法,然后在调用派生类型映射中将正确地调用派生类。以下代码节选中示出一组起效的类型的示例。此代码仅示出诸类的结构——为简略起见任何实现均被省略。
struct TBaseClass
{
BSTR
Name(
void
);
HRESULT
set_Name(
IN BSTR bstrName
);
virtual
ULONG
cJobs(
void
);
virtual
void
set_cJobs(
IN ULONG cJobs
);
ULONG m_Status;
};
IMG_ATTR_TABLE_BEGIN(TBaseClass,Img::iatl::TypeMap)
Type(L″BaseClass″),
Field(IMG_ATTR_FIELD(m_Status),L″Status″),
Field(IMG_ATTR_METHOD(TBaseClass::Name),gGet),
Field(IMG_ATTR_METHOD(TBaseClass::set_Name),L″Name″,gSet),
Field(IMG_ATTR_METHOD(TBaseClass::cJobs),gGet),
Field(IMG_ATTR_METHOD(TBaseClass::set_cJobs),L″cJobs″,gSet),
IMG_ATTR_TABLE_END
class TBaseClass2
{
public:
IMG_ATTR_TABLE_FRIEND(TBaseClass2,Img::iatl::TypeMap);
protected:
BSTR
get_Location(
void
);
void
set_Location(
IN BSTR location
);
virtual
HRESULT
get_Comment(
IN OUT BSTR *pComment
)=0;
virtual
HRESULT
set_Comment(
IN BSTR Comment
)=0;
private:
ULONG ExtraStatus;
};
IMG_ATTR_TABLE_BEGIN(TBaseClass2,Img::iatl::TypeMap)
Type(L″BaseClass2″),
Field(IMG_ATTR_FIELD(ExtraStatus)),
Field(IMG_ATTR_METHOD(TBaseClass2::get_Location),L″Location″,gGet),
Field(IMG_ATTR_METHOD(TBaseClass2::set_Location),L″Location″,gSet),
Field(IMG_ATTR_METHOD(TBaseClass2::get_Comment),L″Comment″,gGet),
Field(IMG_ATTR_METHOD(TBaseClass2::set_Comment),L″Comment″,gSet),
IMG_ATTR_TABLE_END
classTDerived:publicTBaseClass,public TBaseClass2
{
public:
IMG_ATTRTABLE_FRIEND(TDerived,Img::iatl::TypeMap);
//
//覆盖set_cJobs的实现。
//
void
set_cJobs(
IN ULONG cJobs
);
protected:
//
//实现获取和设置的注释。
//
HRESULT
get_Comment(
IN OUTBSTR *pComment
);
virtual
HRESULT
set_Comment(
IN BSTR Comment
);
ULONG ChainedJobs;
ULONG Attributes;
};
IMG_ATTR_TABLE_BEGIN(TDerived,Img::iatl::TypeMap)
Type(L″Derived″),
Field(IMG_ATTR_FIELD(ChainedJobs)),
Inherits(IMG_ATTR_INHERIT_TABLE(TBaseClass)),
Field(IMG_ATTR_FIELD(Attributes)),
Inherits(IMG_ATTR_INHERIT_TABLE(TBaseClass2)),
IMG_ATTR_TABLE_END
在此例中,派生类覆盖一个虚方法,并实现两个纯方法。其它所有字段和方 法被从基类中带入。即使表的定义实际上是从基类的中所定义的表带入的,派生类的方法仍被调用。
派生表带入了基类表的定义,其表中有“Inherits”(继承)字段。对基类和基类表的任何扩展将被立即反映在派生类的表中。因此,可示出这些表实现真正的多继承。
游标
游标是允许调用者以一次一块而不是以单个请求的形式从服务器检索数据的接口。这在服务器上有大量对象需被枚举时特别有用。这减少了一次调用中必须通过网络返回的数据量,并且它缩减了服务器方的工作集。对于非常大的对象集合,它还可允许客户机避免将所有对象存储在存储器中。相反,客户机可在表中维护游标,并按需检索更多的行。在此特定实现示例中,当前没有在CDI中实现游标,这是由于以下原因:
·服务器上所维护的对象个数与典型的数据库中所存储的对象个数不是相同的数量级。客户机没有足够存储器来存储其数据副本是非常不可能的。
·服务器上的许多对象必须是活动的,因为大多数队列将会接收作业。因此,与在数据库中相比,工作集不是那么需要考虑的问题。
·通过在两次操作中进行查询,网络通信量可被任意地减少,这两次操作是,检索每个对象的规范名称的初始查询,然后是检索每个对象的数据的第二组GetObjectData调用。因为GetObjectData调用可被任意地分块到一起,所以无需网络往返也可从每个对象检索数据。
·因为调用者可指定准确的查询过滤器,所以可使数据集的大小大大变小。例如,客户机假脱机程序可在属于给定用户的作业上进行枚举,而不是必须枚举所有作业然后过滤掉不属于给定用户的作业。
·因为调用者可准确地指定它们想要检索哪些字段,所以可以大大减少数据量,而优于具有不灵活的信息等级系统的当前系统。例如,现在要检索队列中的作业数,调用者必须指定PRINTERINFO2,它还包含默认的DEVMODE和安全描述符。
·除了通知以外,该接口当前在线路级是无状态的。游标可能导致更多的服务器状态。维护游标所需的状态的额外开销可能超过从其得到的好处,特别是在给定了缓解的个数的情况下。
然而,在某个时间点在系统中实现游标可能会是合乎需要的,特别是在打印系统被调整为执行文档归档,或在可使很大的打印服务器来处理其中少量队列处于 活动状态的非常大量的队列(在此情形中,避免将对象不必要地拖入存储器中变得非常重要)的情况下。这一节描述一种将导致用于查询的开销相当低的仅前向的游标的机制。
就通知而言,考虑通知不要求对客户机接口的任何改变。线路接口将把经填充的数据以分块形式发送到客户机,然后将开始更新客户机对象。为实现最优性能,可将更新与原始填充相互交织。
就客户机游标而言,考虑以下情况。所示出并描述的系统的一个目的是尽可能地维护无状态线路协议。因此,我们定义一组什么对象被游标检索,然后提供达到这些目的的实现。游标合理的语义如下:
·游标仅前向移动。
·将被游标检索的一组对象是当游标被创建时匹配查询的那些对象减去接下来被删除的对象。它不包括在游标起初被创建以后被创建的任何对象。这是为了防止相对于具有一组迅速改变的对象的服务器的很慢的客户机永不终止。
所描述的解决方案是为随每个对象保持一个恒增的顺序计数。当游标被建立时,当前最大的顺序计数号被客户机记住。一组对象被返回,并且最后一个对象的最大顺序计数被记住。当下一组对象被检索时,它等于此查询:检索满足Timestamp(时间戳)>last_max且Timestamp<initial_max的下一个CHUNKSIZE(分块大小)对象。
可能最后事实表明为服务器上的每个请求执行此查询的额外开销超过维护必要的连接以在服务器上维护游标的上下文的平均额外开销。一种折衷的解决方案是在由GUID标识的服务器上保持游标的高速缓存。客户机将时间戳和GUID提交给服务器。如果服务器方的游标仍然存在于高速缓存中,则即使用该状态。否则,通过执行时间戳查询并将其重新插入到高速缓存中来恢复游标。这允许服务器以很低的成本丢弃对应于很慢的客户机的状态。
如果假定主要目的是缩小单个网络请求的大小和缩减服务器上查询所需的工作集,则CDI接口不一定要求任何改变,远程访问适配器和本地访问适配器将在客户机发布查询时即透明地使用到服务器方的游标。
对于非常庞大的数据集,客户机可能想要自己操纵游标,以使其不必一次将其所有状态都保持在存储器中。在此情形中,可从CDI接口检索表示游标的接口。 不一定要使此调用被批处理,因为通过蕴含,单个游标可检索大量数据。
友好名称解析
已经在不同地方讨论了将友好名称转换为规范名称的概念。友好名称是对象实例的人类可读版本,例如,有称为server.mydomain.org的服务器的概念就是友好名称。规范名称是标识用来与服务器(即逻辑服务器寄宿于其上的物理服务器)通信的协议的完全无岐义的名称,并且是对逻辑服务器对象实例完全无岐义的引用。例如,以上友好名称可对应于以下规范名称:“{63315ca9-bef6-4cc5-9152-05e369d3d691}\www.realhost.net\{a4b6e956-dee0-46d0-b82c-7ffc8f814e95}\{f091b5a1-ad2a-4dfe-9d37-9592blae2512}”。规范名称具有完全无岐义这一优点,这对计算机而言是极好的。但是它无法由人类容易地输入。
给定规范名称,要确定对象的友好名称(如果这是相关的)是很容易的。对象只需具有诸如“Object::Name”等可从对象检索的属性。但是,如果系统仅具有友好名称,则它必须能够确定规范名称。在此节中讨论此接口的应用程序可调用方。实现名称解析器在以下题为“友好名称解析插件”一节中讨论。以下根据一个实施例示出客户机友好名称解析接口。
interface IImgCommonData:IUnknown
{
HRESULT
GetFriendlyNameResolver(
[out] IImgFriendlyNameResolver **ppINameResolver
);
}
interface IImgFriendlyNameResolver:IUnknown
{
HRESULT
ResolveName(
[in,string] const wchar_t *pszName,
[in,string] const wchar_t *pszClass,
[out] IImgCanonicalNameIterator **ppIIterator
);
HRESULT
BeginResolveName(
[in,string] const wchar_t *pszName,
[in,string] const wchar_t *pszClass,
[in,unique] IImgCallCompletion *pICallCompletion,
[in] void *cookie,
[out,unique] IImgAsyncResult **ppIAsyncResult
);
HRESULT
EndResolveName(
[in] IImgAsyncResult *pAsyncRes,
[out] IImgCanonicalNameIterator **ppIterator
);
HRESULT
RemoveName(
[in,string] const wchart *pszName,
[in,string] const wcbar_t *pszClass
)
}
interface IImgCanonicalNameIterator:IUnknown
{
HRESULT
Reset(
void
);
void
Next(
void
);
BOOL
IsDone(
void
);
IImgCanonicalName*
Current(
void
);
}
当调用者想要获得友好名称解析器时,它们调用IImgCommonData接口上的GetFriendlyNameResolver方法。友好名称仅公开两个逻辑方法(并有对应于其中一个的异步调用模式)。
ResolveName
给定要解析的名称(例如“server.mydomain.org”)以及该名称的类(例如,“Server”),则名称解析接口调用友好名称解析器插件,并将这些插件所返回的所有有效结果作为IImgCanonicalNameIterator接口返回。该名称迭代器允许调用者检索所有对应于该友好名称的规范名称。允许多个规范名称返回的原因是,同一个对象可能是经由不同路径可见的。例如,同一服务器可经由SOAP和RPC访问。
ResolveName方法可能要花很长的时间,因为它可能必须查询多个协议来查看如何能访问特定对象。因此,该接口还以BeginResolveName和EndResolveName方法形式提供异步调用模式。这些方法使用与批处理BeginExecute和EndExecute方法所使用的相同的异步调用模式。调用者或可指定回调接口,或可获取经由IImgAsyncResult返回所返回的系统可等待句柄。当解析了所有对应的规范名称时,它们将受到通知。
RemoveName
名称解析器维护到友好名称的经解析名称的高速缓存,因为名称解析可能是非常缓慢并且成本很高的。该高速缓存将随时间推移被自动刷新。并且如果接下来有任何名称解析未能解析和高速缓存中相同的名称,则那些名称关联将被移除。该行为是,在一定量的时间以后,名称被视为是失效的。如果调用者再次请求该名称,则名称解析器返回该失效的名称,但它向名称解析器插件发布另一轮名称解析,如果没有任何插件返回该名称,则然后将从高速缓存中移除该名称。这提供了对名称非常快速的解析,但它可能导致在一段时间里失效的名称绑定被返回。
调用者可解析友好名称,然后因为在经由CDI访问规范名称时失败来独立地确定该名称是失效的。如果它们想要再次请求同一个友好名称,则它们可能取回同一个失效的名称。为了避免此情况,可通过RemoveName方法将失效的名称显式地从高速缓存中移除。如果调用者不执行此方法,则名称最终将被清除,这是一种可任选的优化。
扩展的对象行为
前一节的目的是介绍CDI的接口和基本概念。介绍的目的是主要从用法角度公开该接口。如在前面几节中所给出的接口足以允许任何应用程序编写者获取、设置、查询和接收对应于该打印系统中的对象的通知。这一节的焦点是给出额外的行为,该行为可由对象公开以实现新的安全和发现能力。
对象工厂,对象克隆
这一节讨论可被用来在系统中创建新的对象、将这些对象(如可适用)传送到另一个系统中,以及允许新的对象创建用户界面(UI)被插入的机制。该系统中除了工厂对象以外的所有对象都应支持此机制。在图8中示出此机制,它起到以下讨论的基础的作用。
对象创建和克隆机制假定有能够执行以下功能的驱动程序存储:
1.基于UI程序集强名称向客户机或服务器提供UI程序集。
2.基于集合程序集强名称向服务器方提供集合程序集。
强名称的准确定义以及它如何与版本化相关是另一个议题。但是,为上下文 目的,考虑以下。
强名称是以一个名字既唯一地标识正在使用的程序集的实际实例,又唯一地标识该程序集的发布者的名称。此机制的一个实现是使用公钥加密签署程序集的内容,然后取该签名的加密散列(通常是MD5散列)并将该散列(或该散列的一部分)嵌入到该名称中。实际上此名称不仅被绑定到程序集的内容,而且它还被绑定到程序集的发布者。目前没有已知的技术可以让别人创建具有不同功能的另一个程序集并使用我的程序集的强名称而无需创建非常大量(128位散列需要1038)程序集并在每一个程序集上尝试整个过程。
本质的想法是,每个集合提供一公知的对象实例,该对象实例起到一组对象实例的工厂对象的作用。因为不可能预先知道新对象的构造参数,所以该对象用创建新对象实例的称为Create()的命令实现自定义类型(此例中是Company.Type.1)如果调用者知道工厂对象和工厂类型,则它们可在新的假脱机程序中创建该类的对象。
支持Microsoft.Object.1类型的对象支持克隆。该对象所支持的字段包括集合SN、其创建所使用的工厂对象实例以及三个命令,GetStream、Delete和UpdateFromStream。GetStream将对象的内容检索到流中,Delete删除对象,而UpdateFromStream基于传递给它的流更新对象的状态。该对象可支持任何类型的流,但出于互操作性的原因,理想情况是该流为XML。
当一对象要被克隆时,该对象实例被查询以获得其集合SN和工厂对象实例。这些被存储在流中,接着如流所表示的对象的状态也被存储。
为恢复对象,要从驱动程序存储检索集合并定位工厂对象。然后通过CreateClone命令向工厂对象传递流的其余部分。这使工厂创建完全相同的对象实例。
注意,流中所有的对象都应支持去耦合的UI创建和克隆。但是,为简略起见,不在其余章节中示出工厂对象和克隆接口以简化讨论和附图。
分层结构
分层结构通常实现两个目的。第一,它细分搜索空间以允许对象的高效定位。将CDI分成多个集合、仅在一集合支持给定类的情况下加载该集合的能力、以及将一组动作定向到给定服务器的能力已经实现此目的。第二,它通过允许系统或管理员将对象分组到逻辑分层结构中来提供异类对象的可管理性与发现。分层结构允 许发现,因为每个对象都被定位在逻辑分层结构中的某个地方。因此可构建允许用户进而向下钻入每个对象、直至系统中所有对象已被发现的浏览器。分层结构还可通过允许通过一个管理动作将安全改变应用于对象的子树来提供系统的安全视图。此机制类似于文件系统实现安全的机制。
分层结构对于示出对象之间的关系而言通常不是很有用。纯分层结构只允许一个对象被定位在恰好一个其它对象之下。因此,一个作业不能同时属于打印机和服务器。分层结构还不能高效地示出对象之间的多对一关系。关系型模型在指示对象关系上要强大得多。CDI通过批处理接口上的Query(查询)动作的QueryBase(查询基)机制(它返回逻辑上可被视为被另一个对象包含的对象)有效地允许此功能。
因为分层结构的第一个目的已由CDI和远程访问适配器路由机制实现,并且因为从任何观点来看CDI的关系型机制在表示对象关系上更为强大,所以我们只需要一种支持系统中异类对象的管理和发现的方法。注意,因为现有的模型足以应付大部分情形,所以并非所有对象都必须支持分层结构。由服务层提供的默认的可持久化存储将自动支持分层结构。因此,本地对象最简单的实现将自动支持分层结构。会有我们支持可发现的分层结构、但不支持可修改的分层结构这样的情形。例如,支持当前假脱机程序RPC接口的远程适配器可允许客户机发现服务器下的打印机以及打印机下的作业,但不会允许该组织结构被改变。
分层结构可通过引入称为Link(链接)类的新类来表达,该类具有一个类型,即带有一个属性Object(对象)的链接类型,Object是可被视为从某个角度来看在当前对象“之下”的对象的规范名称。当想要找出哪些对象实例可从当前类以分层结构方式遍历时,即可用正从其进行遍历的对象实例作为查询基来查询Link类。图9中示出在分层结构中建立的数个对象的示例。这不包括逻辑系统对象,它们是每个机器上的根对象。
链接类查询的实现将由持久对象集合服务自动提供。但是,任何想要公开可发现的分层结构的集合可填充链接查询。例如,公开DS对象的集合可枚举每个DS对象的子对象,然后在当父对象被枚举时将每个对象的特异名称填充到链接表中。
安全和分层结构
分层结构提供可发现性和安全。CDI提供一种安全代理,当对象的安全描述 符被改变时,该安全代理将遍历子对象以强制执行安全继承规则。安全将由持久对象集合服务自动处理,且安全代理将在此集合中的对象上自动运行。
将提供称为逻辑分组的特殊对象,管理员可将任何一组对象放在其下。这允许管理员改变逻辑分组上的ACL,并令它们自动应用于该逻辑分组下的所有对象。这允许管理员对其服务器应用其觉得有用的管理分层结构,然后将安全规则应用于该分层结构。
安全和类混合插入
除了用分层结构控制安全以外,该系统还将允许用类来控制安全。这允许诸如提供对在该系统上创建的所有作业的创建者/所有者管理访问等特征。在当前系统中,类规则被硬编码到系统中;将来,任何类都将有混合插入可用。
如图10中所示,类继承是通过在安全分层结构中公开可编辑的类对象来实现的。这些类对象每一个都将初始包含在创建时应用于每个类的默认安全描述符。和所有其它对象一样,它们将从作为整个系统的基对象使用的逻辑系统对象继承其描述符。当适当类的对象被创建,父对象和该类对象都被用来推导其安全描述符。图10也示出逻辑分组对分层结构的作用。这里,管理员创建了两个逻辑分组,一个能够控制对任何群集服务器的访问,而另一个能够控制对本地服务器对象上的打印机的访问。尽管这里每个情形中仅示出一个对象,但是在每个逻辑分组下可以放置任何数量的对象。
元数据
在所示出并描述的实施例中,CDI提供将任何对象绑定到远程对象的能力,但是调用者在将对象绑定到远程对象以前必须知道该对象支持的字段和命令。大多数时候,客户机知道服务器对象以及它们所支持的接口。如果客户机不知道,则它将不能正确地工作,因为它需要服务器对象的先验知识来进行工作。该接口被适应于优化此行为,而准确地知道它们将在其中被调用的上下文的类不需要实现任何元数据机制。
但是,也有客户机不具有关于其正操纵的类的先验知识的情形。例如,客户机可能是将CDI调用转换到托管数据提供程序接口的访问适配器。在此情形中,其客户机所请求的数据不能被先验地知道,而其正与之通信的服务器对象也不能被先验地知道。或者,客户机可以是允许客户机或服务器上所有对象都被浏览和操纵 而无论对象类型是什么的通用管理UI。
为此目的,所示出并描述的实施例提供允许调用者查询对象实例以获得其元数据的标准系统类型。这些类型是:Type(类型)、Property(属性)、Command(命令)和Parameter(参数)类型。使用集合适配器服务实现的类将免费自动获得完全元数据支持。这将从它们将为其每一个类提供的服务器对象类型映射检索到。
图11中示出可用对象作为基来查询以检索元数据的类型。
元数据是通过首先用对象作为查询的基来查询各Type类型来检索的。Type类型提供逻辑对象实例所支持的所有类型的列表。因为将来系统允许对象被嵌入到其它对象中或扩展其它对象是可能的,所以这些类型将包括对应于该对象实例的所有聚集的类型,而不仅仅是底层的基本对象。然后进而可查询每个Type类型所支持的命令或属性。然后,可查询每个命令所支持的参数。
查询基
查询基是不寻常的设计方面,没有它系统将是非分层结构的系统。这一节讨论为什么要实现它们,以及它们如何映射到关系型查询。
查询基指定源对象,从某种角度来看可认为正被查询的类的示例在源对象“之下”。提供此设计有以下原因。首先,它允许对要构造的子元素进行枚举,否则构造者将无从得知如何将关系表达为查询的一个部分。其次,它很好地映射到基于枚举的下级系统。查询的基很自然地变成枚举中的父对象。因此,对于下级对象而言,查询基和对象状态上的过滤器是实现查询的自然方式。第三,对于具有高度可变组成的对象而言(例如由对象存储的元数据),将查询作为从父对象出发的一系列枚举是更加合乎逻辑的。
但是,查询基需要一些操纵才能映射到关系型查询。好在相对而言这很容易实现。
[1646] 为说明起见,上表仅示出打印队列中的数个作业。有两个字段(在底层数据库中实现为外来关键字)存储作业与之相关联的对象的规范名称。引用远程对象的每个列都知道远程对象类。
当有对特定基对象的查询时,该对象的类被相关到该对象中的一逻辑字段,然后该查询被扩展以包括这一具有正确值的字段。
例如,如果有对于Base(基)=“{SSSS}”、Base Class(基类)==“Server”(服务器)、并带查询串“Jobs:Size<150KB”的查询,则这将被转换为以下查询:
Jobs:Server=”{SSSS}”AND(Jobs:Size<150KB).
这将返回正确的结果,即Fred的作业。此转换将在集合适配器服务中被自动执行。在服务器对象类型映射中它将需要稍多一些元数据,因为我们需要知道哪些字段可起到查询基的作用,以及它们对应于哪些类。
CDI实现
前一节描述了希望从对象获得的行为,并描述了向客户公开的接口。这一节描述服务器方的CDI实现。它描述CDI所提供的服务以及插件模型。
图12示出CDI的主要组件,以及被插入到该系统中的各种插件。首先,将提供对其中每个主要组件的描述,然后将提供对CDI盒本身中的组件的描述。集合适配器服务由系统提供,但是它被视为是由插件承载的单独的服务,而不是CDI本身的一个部分。集合适配器服务在下一节讨论。
应用程序
到应用程序的接口是前几节的主要焦点。应用程序从CDI请求批处理接口,记录数个动作然后执行它们。当执行完成时,应用程序可获得结果。
路由器
执行这些动作导致批次被路由器路由并被传递给插件。路由器在一次调用中找出批次中被定址到同一插件的连续范围,并将那些范围传递给插件。因此,插件本身仍可保持批处理行为。取决于应用程序所调用的语义,这些部分可被并行地、串行地传递给插件,或可将事务对象与批次相关联以允许插件协调事务。
插件
插件是由DLL结合DLL清单和配置信息公开的接口。单个DLL可公开一个或多个插件接口。在所示出并描述的实施例中,插件接口包括带有一个方法的一个工厂接口,和仅带有两个方法——AsyncProcessRequest和Shutdown的插件接口(IImgBatchCollection)。插件接口仍按批次形式接受其操作。因此它是用于远程化到其它也支持批次的系统的逻辑接口。为此目的,在所示出并描述的实施例中,提供了以下插件:本地访问适配器、远程访问适配器、沙箱适配器、以及自适应插件,其中每一个都在以下单独讨论。
本地访问适配器提供对本地服务或每用户服务的访问。目前此插件使用异步COM,但没有任何特殊理由不能使用任何其它远程化机制。
远程访问适配器提供对远程机器的访问,并将很大程度上使用和本地访问适配器相同的机制,仅有一些差异用于减少服务器上的每客户机状态。
沙箱适配器被用来在将请求分组到批次中的范围内保持应用程序的工作。这也意味着同一个通用插件模型可被进程内或进程外组件使用,如果希望的话,我们甚至能用沙箱法构造系统组件。系统中处CDI以外的所有部分将作为插件公开。
自适应插件的形式极其简单,但它要求插件在一次异步调用中解释排队的批处理操作,这可能会很复杂。为此原因,提供了集合适配器服务(CAS)。集合适配器服务允许对象(IImgObject)的多个对象集合(IImgObjectCollection)被插入到其中,而它进而解释被批处理的调用,并将这些调用转换为对所提供的集合和对象的调用。集合适配器服务提供对这些接口的同步和异步实现的高效处理。集合接口足够宽泛而可被用来访问下级协议。在这些情形中没有性能损失,因为它们通常不支持批处理。
服务
在所示出并描述的实施例中,CDI提供一组服务。其中大多数可从插件访问。这些服务是公开的,并平等地向CAS和任何其它插件公开。这允许觉得CAS过于有限的独立软件供应商或独立硬件供应商自己来实现相同的功能。明确的目的是允许CAS解决大多数情形,所有系统提供的对象将会使用它。CDI所提供的服务包括查询编译器、工作流程、事务、改变范围、Variant和类型映射,其中每一个都在以下单独讨论。
查询编译器能够将应用程序提供的查询编译为语法分析树和过滤器这两种形式中的一种。语法分析树在插件想要将查询转换为另一种形式的查询的情况下是很有用的,这比试图自己来重新进行语法分析要简单,因为括号和运算符优先级已被语法分析器解析,而一些基本的构造良好性检查已被语法分析器执行。过滤器可被绑定到对象,并提供允许调用者检查给定对象的状态是否匹配被传入的查询的方法——“DoesMatch”。
工作流程是每当应用程序执行进入CDI的调用时被实例化的接口。它对应于用户动作的逻辑执行。工作流程可调度工作,并将在工作流程被取消时(通常是因为来自用户的原始调用被取消)通知与其相关联的工作项目。工作流程可跟踪一组令牌以检测并防止递归。当插件因为来自CDI的调用的原因而想要进行进入系统的调用时,它必须使用和发起的调用中相同的工作流程。通过特殊的仅服务器方调用(IImgCommonDataServer::RecurseDataBatch)来实现此目的。
当执行递归时,必须将一令牌插入到流程中,稍后可使用该令牌来检查同一操作是否在同一流程上重复发生,并因此退出递归。工作流程还将跟踪原始调用者的令牌。当插件异步并独立地进入CDI进行调用时,它或可通过客户机接口来实现此功能,或可创建它自己的工作流程并调用RecurseDataBatch。
如果调用者请求事务,则此对象被创建并与批次相关联。事务提供一种将一个事务式集合和一组从属项目与事务相关联的机制。它既提供到事务的同步接口,也提供到事务的异步接口。当批次完成执行时,事务被提交。结果被发送到存储,如果存储正确地更新,则从属项目被运行。为了符合从属项目的资格,项目必须不能使提交请求失败。这被用来使从属于一状态改变的活的在存储器中的对象被传播到存储中。如果插件想要将事务扩展成包括其它对象(例如,为了实现依次删除其它对象的“Delete”命令),则它可在经由RecurseDataBatch进入CDI进行回调时指定同一事务。每个递归上的所有改变都将被保持为未决状态,直至最外围的批次成功地完成。
改变范围涉及服务器方表示每个通道的改变处理器。可在事务上插入改变范围。
Variant已在前面章节讨论。Variant可由客户机方或服务器方使用。
类型映射也已在前面章节讨论。优化的映射仅对服务器方可见。
插件接口
在所示出并描述的实施例中,插件接口是使用类似COM的对象实例化模型来实例化的。它不要求插件在注册表中注册它的类ID。图13中示出实例化插件的过程。
在所示出并描述的实施例中,所有插件都作为CDI配置的一个部分被存储在WMI.Config中。其中一些插件数据将由WMI.Config从插件DLL的XML配置文件合成(这对基于XCOPY的解决方案很有用)。CDI配置包含插件DLL的列表。对于每个DLL,我们列出每一个所支持的集合GUID,以及在每个逻辑集合中所支持的类。每个DLL还有一些相关联的初始化数据。这通常表示DLL所支持的对象将被持久化到并从该处检索的位置。当路由器想要将插件接口实例化时,它检索集合GUID,找出对应的DLL,然后调用DllGetClassObject:
HRESULT
DllGetClassObject(
IN REFCLSID rclsid,
IN REFIID riid,
OUT VOID **ppv
);
然后我们请求CLSID_IImgBatchCollection和IID_IImgBatchCollectionFactory。DLL随即返回一个类工厂,它能够返回该插件所支持的IImgBatchCollection的各种实例。IImgBatchCollectionFactory支持以下接口:
interfaceIImgBatchCollectionFactory:IUnknown
{
HRESULT
LockServer(
[in] BOOL fLock
);
//
//待办:pInit应被基于WMI.Config的更加切合实际的初始化系统取代。
//
HRESULT
CreateInstance(
[in] IImgCommonDataServer *pICommonDataServer,
[in] REFGUID collectionGuid,
[in,string] const wchar_t *pInit,
[in] REFIID riid,
[out] void **ppvObj
);
}
在CreateInstance(创建实例)期间,向工厂传递以下信息:
·IImgCommonDataServer接口。此接口继承自IImgCommonData,并且还包括一些插件专属的访问服务器方的服务的方法。注意:插件不应 调用CoCreateInstance(CLSID_IImgCommonData),因为这将创建客户机接口。当最后一个客户机接口被释放时,系统关闭,如果服务器方插件保留了客户机接口,则系统不关闭。
·集合GUID。这和CDI配置中给出的是相同的GUID。工厂可根据此GUID选择实例化不同的IImgBatchCollection接口。
·初始化数据 - 此数据将从WMI.Config检索。目前这由串表示。插件使用此初始化数据来选择从何处获得其对象。
·Riid - 这是CDI所请求的接口。目前仅IID_IImgBatchCollection被请求,但此处还可请求其它将来的接口。
插件所返回的接口如下:
interface IImgBatchCollection:IUnknown
{
HRESULT
AsyncProcessRequest(
[in] IImgServerItemCompletion *pIItemCompletion,
[in] ULONG StartIndex,
[in] ULONG EndIndex,
[in] IImgBatchArray *pIBatchArray
)
HRESULT
Shutdown(
[in] EImgShutdownReason eReason
);
};
如果有任何来自批次数据的目的地是插件,则AsyncProcessRequest接口被调用。向该集合传递以下数据:
·IImgServerItemCompletion接口。此接口支持单个方法 - “Done”,它在请求被完全处理以后被调用。调用者可立即从AsyncProcessRequest返回。调用者必须调用“Done”除非它们未能通过AsyncProcessRequest调用。未能调用“Done”导致客户机的Execute调用没有完成。
·BatchArray(批数组),此接口提供对客户机所请求的动作的访问。
·批数组的开始和结束索引。这允许路由器创建一个批次,然后该批次被各个插件共享。如果客户机请求并行执行语义,则各插件可被并行执行。
批数组具有以下接口:
typedef struct
{
EImgBatchOptions eItemType;
EImgActionCompletionStatus eCompletionStatus;
HRESULT hrCallResult;
IImgErrorInfo *pErrorInfo;
[switch_is(eItemType)] union
{
[case(BatchGetObjectData)]
ImgBatchGetObjectData ObjectGetData;
[case(BatchSetObjectData)]
ImgBatchSetObjectData ObjectSetData;
[case(BatchObjectCommand)]
ImgBatchObjectCommand ObjectCommand;
[case(BatchObjectQuery)]
ImgBatchObjectQuery ObjectQuery;
[case(BatchNotifyRegistration)]
ImgBatchNotifyRegistration NotifyRegistration;
};
} ImgBatchItem;
interface IImgBatchArray:IUnknown
{
HRESULT
ItemAt(
[in] ULONG Index,
[out] ImgBatchItem **ppBatchItem
);
//
//这些访问器提供到批数组中其它数据的访问。
//
EImgBatchSemantics
GetBatchSemantics(
void
);
IImgBatchTransaction*
GetAliasedBatchTransaction(
void
);
IImgWorkFlow*
GetAliasedWorkFlow(
void
);
};
可从批数组检索批语义、任何相关联的事务和工作流程。并不返回带有递增引用计数的接口,因为它们对于批数组使用别名。ItemAt方法返回给定索引处的批动作。这包含给出项目类型的枚举。它还包含插件可设置以指示项目是否完成以及任何出错信息的字段。它包含一联合,该联合包含由调用者传入的对应动作的参数。
截取
既然已经定义了插件接口和路由器,以下对截取的实现进行讨论。在所示出并描述的实施例中,截取被实现为批处理路由器可向其发送数据的另一个插件接口。但是,和为普通插件存储的配置信息不同,普通插件仅要求集合ID(或用于查询的类)来进行路由,而截取插件指定以下信息段:
·截取动作。截取器可指定它想要俘获获取、设置、查询、命令还是通知。
·截取类。截取器指定它想要因为哪类对象而被调用。该类可被指定为‘*’,在此情形中将为所有的类注册截取器。
·截取集合。截取器指定它想要截取其对象的集合的唯一GUID。此集合可被指定为‘*’,在此情形中将为所有集合注册截取器。
·截取对象。截取器可指定它想要监视(如果它这样做,则它应当截取该对象的Delete命令以移除截取)的对象的唯一对象ID。如果指定了‘*’,则为所有的类调用截取器。
截取表中的每个注册都被分配一个GUID。该截取机制将使用“命令链”模式。批处理路由器所采取的动作如下:
1.在将批次中的给定项目路由到集合以前,路由器首先使用上述字段检查是否为该调用注册了截取器。
2.如果有,按照相同规则找到目标为同一截取器的一组连续的动作。
3.与截取注册相关联的GUID被插入到工作流程中,并且截取器被调用。
在这个时间点上,如向任何其它插件一样向截取器传递批处理动作。它按以下两种方式中的一种改变动作的执行:
1.它对路由器调用RecurseBatchActions(),并再次传入工作流程加上原始的批处理动作。这不导致其中任何动作被修改,但它允许截取器读取这些动作并自己执行其它动作(例如,如果它是同步器,则它将在被高速缓存的数据失效的情况下用这来触发同步动作。)
2.它解释每个批处理动作,然后通过调用RecurseDataBatch来修改它们,并再次传入工作流程。此选项允许截取器改变动作的结果,但它(有意地)更加难以实现。例如,为改变“Get”(获取)的结果,必须实例化一临时代理对象来保持实际对象获取的结果,还必须注册新的类型映射才能写此临时对象。
这些调用中任何一个都将导致进入批处理路由器的回调。除了不进入任何将 其GUID令牌列在工作流程中的截取器进行调用以外,批处理路由器执行和以前完全相同的查找。因此,进而每个截取将被穷举,直至动作被路由到目标对象。同样的机制防止一组行为良好的截取器和对象出现递归,因为路由器在调用出现递归的情况下将自动忽略已被调用的截取器。
因为截取器负责链接调用,所以它可选择在链接以前或以后执行动作。它可改变批次的语义。通常,如果批次不是事务式的,则它可能想要确保截取是事务式的。因为它是被异步调用的,所以它甚至可与被截取的动作并行地执行其截取。
截取的用途
截取对两个目的而言是有用的——系统扩展或方面扩展。截取可被IHV用来扩展批处理动作的行为。例如,当队列被暂停时,可能需要由驱动程序采取另一个动作。只要这些扩展不试图改变原始动作的结果,它们就是相当安全的。为此原因,使RecurseBatchActions方法更容易实现。改变批处理动作的结果将会困难得多,因为它要求截取和修改所有参数,包括如类型映射、客户机对象和客户机对象集合等一些难以处理的参数。还可设想将截取作为一种用于维护兼容性以及用于修补系统的机制。例如,如果对系统的修订导致一插件行为异常,则可创建截取器以将进入其中的调用改变成其所理解的调用。因此,可通过提供截取器(例如,通过在带有过长的串的调用到达目标对象以前截取该调用来修补安全漏洞的截取器)来服务系统。这甚至可被相当一般地实现,例如,可编写拒绝所有大于MAXPATH的串的截取器,或可提供每个字段的适当串长度的表。
截取最有用的是在实现跨越/修剪大量对象的系统的一个方面。例如,可编写将所有符合特定模式(例如,它们因“访问被拒绝”原因而失败)的动作记录在系统中的截取器。
对象命令
对象命令和对象属性不同,原因在于对象命令仅在服务器方被调用。这是因为命令调用是通过将来自客户机的Variant数组传递给服务器并返回来执行的。没有被调用的客户机方代理对象的概念。数据表示如下所示。
typedefstruct
{
ULONG cParams;
[size_is(cParams)] ImgVariant *aParams;
}ImgReturnparams;
interface IImgCommand:IUnknown
{
HRESULT
BeginCommand(
[in] void *pobject,
[in] ULONG cInputParams,
[in,size_is(cInputParams)] ImgVariant *aInputParams,
[in] IImgWorkFlow *pIWorkFlow,
[in] IImgCommonDataServer *pICDIS,
[in] IImgServerItemCompletion *pIComplete,
[out] void **ppContext
);
HRESULT
EndCommand(
[in,unique] void *pContext,
[out] ImgReturnParams *pReturnParams
);
};
//
//定义一结构来描述一参数。
//
typedef struct
{
ImgType type;
[string] const wchar_t *description;
}ImgParameterDescriptions;
//
//定义一结构来描述数个参数。
//
typedef struct
{
ULONG cParams;
[size_is(cParams)] ImgParameterDescriptions *aParams;
} ImgParametersDescription;
//
//定义一结构来保存命令。
//
typedef struct
{
[string] const wchar_t *type;
[string] const wchar_t *command;
IImgCommand *pICommand;
[string] const wchar_t *description;
ImgParametersDescription inputParameters;
ImgParametersDescription outputParameters;
} ImgCommand;
//
//定义若干命令。
//
typedef struct
{
ULONG cCommands;
[size_is(cCommands)] ImgCommand *aImgCommand;
}ImgCommandsDescription;
//
//服务器类描述可包含命令,这与客户机类描述不同。
//
typedef struct
{
ImgClassDescription values;
ImgCommandsDescription commands;
}ImgServerClassDescription;
如从以上代码可以看到,服务器类描述和客户机类描述是相同的,但它还包括对一组命令的描述。命令具有类型、命令和描述。它包含指向命令接口的指针。命令接口和访问属性中所使用的访问器接口以类似方式工作。向命令接口传递它必须对其应用该命令的对象、以及包含对应于该命令的输入参数的ImgVariant数组。每个命令都可被异步执行,这就是接口既有BeginCommand又有EndCommand方法的原因。
每个命令还定义其所有参数的类型,并且还具有对应于每个命令的所有描述的列表。
和属性访问器一样,可在动态类型之上构建命令。但是,因为在基础级它们对应于执行动作(和检索数据相对),并且因为在调用命令时,并非必须为线路封送目的构造动态代理对象,所以这可能不像对属性那么有用。它在经由截取扩展命令的情况下可能有用。
IATL命令
IATL提供一种将CDI命令直接映射到C++类方法调用的机制,正如它提供一种将CDI类型映射属性直接映射到C++字段和方法的机制。
IATL允许调用者将命令实现为在其中为实现者自动构建异步BeginCommand、EndCommand对的单个方法。这在实现者想要实现不进行任何IO的命令的情况下是很有用的。或者,IATL使类提供两个方法,并异步地实现该命令。用来构建IATL的机制在以下代码节选中概述。
namespace Img
{
namespace iatl
{
struct CommandParams
{
IImgWorkFlow *pIWorkFlow;
IImgCommonData *pICDI;
};
struct InCommandParams
{
IImgServerItemCompletion *pIItemCompletion;
IImgWorkFlow *pIWorkFlow;
IImgCommonDataServer *pICDIS;
void **ppContext;
};
struct OutCommandParams
{
void *pContext;
};
}//namespace iatl
}//namespace Img
class ServerprinterCommandBase
{
public:
ServerprinterCommandBase(
void
);
ServerPrinterCommandBase(
const ServerprinterCommandBase &source
);
HRESULT
Print(
IN Img::iatl::CommandParams *pParams,
IN BSTR pszPrintJob
);
};
class ServerPrinter:publicImg::iatl::TIMCserverObject<serverPrinter>,
public ServerPrinterCommandBase
{
public:
HRESULT
Random(
IN Img::iatl::CommandParams *pParams,
OUT ULONG *pRand
);
HRESULT
printAndRandom(
IN Img::iatl::Commandparams *pParams,
IN BSTR pszprint,
OUT DOUBLE *pRand
);
HRESULT
BeginNothing(
IN Img::iatl::InCommandparams *pParams,
IN BSTR pszPrint
);
HRESULT
EndNothing(
IN Img::iatl::OutCommandParams *pParams,
OUT BSTR *pbstrprint
);
HRESULT
StartNotifications(
IN Img::iatl::CommandParams *pParams
);
HRESULIT
BeginDelete(
IN Img::iatl::InCommandparams *pParams
);
HRESULT
EndDelete(
IN Img::iatl::OutCommandParams *pParams
);
};
//
//用于构建ServerPrinterCommandBase的命令调用的IATL表
//
IMG_ATTR_TABLE_BEGIN(ServerprinterCommandBase,Img::iatl::CommandMap)
Type(L″PrinterBase″),
Command(glIn, IMG_ATTR_METHOD(ServerPrinter::Print), L″Print″,L″This prints out
something″),
InDescrip(L″The name of the file to print″),
IMG_ATTR_TABLE_END
//
//用于构建serverPrinter的命令调用的IATL表
//
IMG_ATTR_TABLE_BEGIN(Serverprinter,Img::iatl::CommandMap)
Type(L″PrinterBasic″),
Command(glOut, IMG_ATTR_METHOD(ServerPrinter::Random)),
OutDescrip(L″A random number is returned″),
Command(glInlOut, IMG_ATTR_METHOD(ServerPrinter::PrintAndRandom)),
InDescrip(L″Something that will be output to the debugger″),
OutDescrip(L″A fractional random number″),
Inherits(IMG_ATTR_INHERIT_TABLE(ServerPrinterCommandBase)),
Command(IMG_ATTR_METHOD(ServerPrinter::BeginNothing),
IMG_ATTR_METHOD(ServerPrinter::EndNothing),L″Nothing″),
InDescrip(L″Something that will be output to the debugger″),
OutDescrip(L″Something else that will be returned″),
Command(IMG_ATTR_METHOD(ServerPrinter::BeginDelete),
IMG_ATTR_METHOD(Serverprinter::EndDelete),L″Delete″,L″Deletetheobject″),
Command(IMG_ATTR_METHOD(Serverprinter::StartNotifications)),
Command(glIn,IMG_ATTR_METHOD(ServerPrinter::Clone)),
InDescrip(L″The new name of the printer that is cloned″),
IMG_ATTR_TABLE_END
此节选示出可将来自类的方法作为CDI命令公开的数种不同的方式。
Print(打印)命令在ServerPrinterCommandBase中实现,并且被实现为单个同步方法。所有同步方法接收Img::iatl::CommandParams参数作为其第一个变量。此结构持有与命令相关联的工作流程和公共数据接口。第二个参数映射到第一个命令变量,依此类推。为了消除哪些参数是输入参数以及哪些是输出参数的岐义,调用者必须向Command(命令)函数提供一指示该方法具有多少输入和输出函数的参数。例如,当引用打印命令时:
Command(glIn, IMG_ATTR_METHOD(Serverprinter::Print),L″Print″, L″This prints outsomething″),
glIn参数指示这是具有一个输入参数的命令。任何可作为命令被调用的方法中,输入参数都必须在输出参数以前。
正如属性类型映射,命令类型映射可从基类型继承到派生类型中。这是用Inherits(继承)函数来实现的。
Inherits(IMG_ATTR_INHERIT_TABLE(ServerPrinterCommandBase)),
命令参数的类型将被从方法变量自动推导。但是,在表中可任选的描述字段必须被提供。这是经由InDescrip和OutDescrip函数实现的。例如:
Command(glInlOut,IMG_ATTR_METHOD(Serverprinter::printAndRandom)),
InDescrip(L″something that will be output to the debugger″),
OutDescrip(L″A fractional random number″),
这里Command函数提供命令的基本定义,而InDescrip和OutDescrip函数分别描述第一输入和参数。如果描述了一个以上参数,则可对InDescrip和OutDescrip进行多次调用。
IATL命令映射所示出的其它值得注意的特征是实现异步命令的能力。这由ServerPrinter类上的BeginNothing和EndNothing方法示出:
HRESULT
BeginNothing(
IN Img::iatl::InCommandParams *pParams,
IN BSTR pszPrint
);
HRESULT
EndNothing(
IN Img::iatl::OutCommandParams *pParams,
OUT BSTR *pbstrprint
);
在命令描述中,这被以下代码引用:
Command(IMG_ATTR_METHOD(ServerPrinter::BeginNothing),
IMG_ATTR_METHOD(ServerPrinter::EndNothing),L″Nothing″),
InDescrip(L″Something that will be output to the debugger″),
OutDescrip(L″Something else that will be returned″),
此例中的Command函数无需被告知哪些是输入参数,哪些是输出参数,因为输入参数根据定义是由Begin方法提取,而输出参数根据定义是由End方法返回。在此情形中,Begin方法和End方法对于同步(单个方法)命令采取不同的结构,即:Img::iatl::InCommandParams和Img::iatl::OutCommandParams。InCommandParams包含指示操作完成的回调接口,以及可被保存并与该操作相关 联的上下文信息。向End方法传回该上下文信息,且该方法可返回该命令的结果作为出错代码,或返回一组返回参数。
查询编译器
查询编译器提供一种将CDI查询编译为可对任何具有类描述的对象应用的过滤器或语法分析树。由查询编译器公开的接口在以下代码节选中示出。
typedef struct
{
EImgParseTypes eConstType;
[switch_is(eConstType)] union
{
[case(ParseTypeInteger)]
LONGLONG intval;
[case(ParseTypeFloat)]
DOUBLE dblval;
[case(ParseTypeString)]
[string] const wchar_t *String;
};
}ImgParseConstant;
typedef struct
{
EImgParseIdentTypes eType;
[string] const wchar_t *ptype;
[string] const wchar_t *pfield;
void *pCookie;
}ImgParseIdentifier;
typedef struct
{
ImgParseIdentifier *pIdentifier;
EImgComparisonOperator compOperator;
ImgParseConstant constant;
}ImgParseComparison;
struct_tagImgQueryNode;
typedef struct
{
EImgBooleanOperator boolOperator;
struct_tagImgQueryNode *pLeft;
struct_tagImgQueryNode *pRight;
}ImgBooleanNode;
typedef struct_tagImgQueryNode
{
EImgNodeType eNodeType;
[switch_is(eNodeType)] union
{
[case(ComparisonQueryNode)]
ImgParseComparison comparison;
[case(BooleanQueryNode)]
ImgBooleanNode Node;
};
}ImgQueryNode;
typedef struct_tagImgQueryNode
{
EImgNodeType eNodeType;
[switch_is(eNodeType)] union
{
[case(ComparisonQueryNode)]
ImgParseComparison comparison;
[case(BooleanQueryNode)]
ImgBooleanNode Node;
};
}ImgQueryNode;
interface IImgQueryTree:IUnknown
{
ImgQueryNode*
Root(
void
);
}
interface IImgQueryFilter:IUnknown
{
HRESULT
DoesMatch(
[in] void *ServerClass,
[out] BOOL *pbMatch
);
HRESULT
ClassMapping(
[out] IImgOptimizedMap **ppIOptMap
);
}
interface IImgQueryFilterFactory:IUnknown
{
HRESULT
GetFilter(
[in] const ImgClassDescription *ServerClass,
[in] REFGUID ClassId,
[out] IImgQueryFilter **ppIExec
);
}
interface IImgCommonDataServer:IImgCommonData
{
//
//这些方法被用来编译对服务器对象的查询。
//
HRESULT
CompileQuery(
[in,string] constwchar_t *pQuery,
[out] IImgQueryFilterFactory **ppIQueryFilterFactory
);
HRESULT
CompileQueryTree(
[in,string] const wchar_t *pQuery,
[out] IImgQueryTree **ppIQueryTree
);
}
服务器方CDI实例提供编译查询的机制。如果需要查询过滤器,则使用IImgCommonData服务器接口的CompileQuery方法。如果需要语法分析树,则调 用CompileQueryTree方法。
查询过滤器作为工厂被返回。当特定的类描述被传递给查询过滤器工厂时,则查询过滤器被返回。覆盖之下的查询过滤器对照由该查询动态生成的类构建类型映射。当它被绑定到服务器对象时,它对照服务器对象构建优化映射。此优化映射被用来填充随即将对照其应用该查询的查询对象。
从查询过滤器工厂被返回的查询过滤器由定义绑定到特定服务器类。可对多个服务器类对象实例应用该查询过滤器。它不是线程安全的。如果调用者想要从一不同的线程使用同一个查询,则它们可从同一个查询过滤器工厂获得不同的查询过滤器实例,并在不同的线程中使用该实例。
查询过滤器具有可对支持类描述的任何类应用的优点。但是,对于要对类应用的过滤器而言,该类必须被实例化,并且可能被该过滤器匹配的所有实例必须被评估。这对相对较小的一组对象(对于现代计算机而言可能在10,000数量级)而言这是可以的,但是它对于一大组对象执行效果就极其糟糕。对于一大组对象,应当使用诸如由SQL所使用的查询机制。但是,CDI查询句法不等同于SQL句法。为解决这一问题,可改为编译查询树,然后将该树转换为SQL查询。允许CDI查询编译器运行就允许诸如运算符优先级和括号等问题由CDI编译器与它将如何处理对查询过滤器的相同查询等问题一致地评估。
从CompileQueryTree方法返回的接口通过Root(根)方法返回已编译查询树的别名。被所返回的语法分析树占据的内存在IImgQueryTree接口被释放时将被返回给系统。
在一个实施例中,语法分析树以查询节点为开始;该查询节点或可是比较,或可是布尔节点。如果它是布尔节点,则该节点具有一个运算符,并进而包含两个查询节点。这是允许构建语法分析树的构造。如果是比较节点,则该比较包含语法分析标识符和常量。如果该标识符在同一表达式中出现两次,如以下查询中可见:“Printer.cJobs>10ANDPrinter.cJobs<100”,则相同的ImgParseIdentifier实例将在语法分析树中出现两次。pCookie字段是树中的占位符,它允许调用者将它们的标识符的概念存储在cookie中。例如,如果Printer.cJobs转换为数据库中的NumberOfJobs列,则这可被存储在cookie中。除了提供可扩展性点以外,cookie被忽略。
事务
事务是CDI用来确保操作或是完全成功,或如果失败则不会在机器上存储任何中间状态的机制。处理事务的实际机制被分布在CDI和CAS之间。CDI提供处理事务和工作流程的接口。CAS提供确保事务正确和提供死锁释放锁定策略所需的机制。
每个事务都由恰好一个事务对象控制。每个事务对象都具有一个逻辑存储对象。系统中的每个逻辑存储由GUID应用。存储对象协调处理事务需要协调的任何持久化状态。在存储不是分布式资源管理器(DRM)的情况下,如果考虑系统不能保证对两个事务式存储的两次提交保证成功,则仅一个存储的限制是合理的。在存储是DRM的情形中,则事务将协调地在一个逻辑存储之上,即由分布式事务协调器(DTC)所提供的逻辑存储,如COM+中可找到的。
每个事务还持有若干从属动作。规则是从属动作必须既能够提交又能够反转其操作。从属动作一般被用来将被高速缓存的状态(或锁)耦合到持久存储。例如,CAS在将事务应用于存储以前克隆每个对象,如果存储成功地提交了改变,则被克隆的对象被交换到高速缓存中。事务接口如下所示:
typedef enum
{
TransactionCollectionSet,
TransactionCollectionIncompatible,
TransactionCollectionAlreadySet
) ETransactionSetResult;
typedef enum
{
TransactionOrderFirst,
TransactionOrderLast
}
ETransactionDependentOrder;
[
async_uuid(5200cad2-8198-4c2a-98d8-f2cdfb0ab311),
]
interface IImgTransactionDependentItem:IUnknown
{
HRESULT
Commit(
void
);
HRESULT
Revert(
void
);
}
[
async_uuid(67ea48a1-7853-4a5c-862d-8af843855e23),
]
interface IImgBatchTransaction:IUnknown
{
HRESULT
GetTransactionalCollection(
[out] GUID *pCollectionID,
[out] IUnknown **ppIUnknown
);
HRESULT
SetTransactionalCollection(
[in] IImgTransactionDependentItem *pITransCollection,
[in] REFGUID collectionID,
[out] ETransactionSetResult *peSetResult.
[out] IUnknown **ppIResultingCollection);
HRESULT
InsertDependentAction(
[in] IImgTransactionDependentItem *pIDependent,
[in] ETransactionDependentOrder eTransactionOrder
);
HRESULT
Commit(
void
);
HRESULT
Revert(
void
);
}
注意,如果调用者或实现者想要使用异步调用机制,则所有接口都使用COM异步调用模式。如果不是,则它们仍可对接口进行同步调用,或实现同步事务从属动作。
想要实现存储或事务从属项目就必须实现IImgTransactionDependentItem接口。此接口有两个方法,Commit(提交)或Revert(反转)。存储可以不能提交(但不可以不能反转),而任何其它从属项目必须总能成功执行其Commit和Revert方法。
每个事务可具有恰好一个存储。当前存储及其存储GUID可用GetTransactionalCollection方法检索。
如果调用者想要设置事务式存储,则使用SetTransactionalCollection调用。因为事务是多线程的接口,所以SetTransactionalCollection同时取GUID和要被设置的集合,并且它返回现有的集合(若有)。有三种情形(如ETransactionSetResult返回参数所示)。
·事务当前不具有相关联的存储对象。在此情形中,返回将是TransactionCollectionSet,且传入的集合将变为与该事务相关联的存储。
·事务当前具有存储对象,但它具有和你正在指定的相同的GUID。在此情形中,事务对象将把现有集合返回给调用者。调用者应释放它们先前的集合并用当前在事务中的持久存储来继续该调用。
·事务当前具有存储对象,并且它是不同的存储(它具有不同的存储GUID)。在此情形中,事务对象将返回
TransactionCollectionIncompatible。调用者通常将在这个点上未能通过操作。(这将使事务反转)。
因为事务协调器无法知道到存储对象的接口(它可以是从事务式文件系统到SQL数据库的任何事物),所以这作为它们可经由QueryInterface从其检索实际存储接口的IUnknown被返回给调用者。存储必须实现IImgTransactionDependentItem,以使事务对象可正确地提交或反转对存储的改变。
事务从属项目在两个阶段被提交或反转。这是经由TransactionOrderFirst和TransactionOrderLast参数向InsertDependentAction指定的。依靠CAS进行锁定的事务应仅使用TransactionOrderFirst,因为CAS使用TransactionOrderLast的从属项目来确保对象锁在协调事务被提交或反转以后被释放。
工作流程
CDI接口在相当程度上是异步的。因此,可在单个线程上完成单个操作,或可在多个线程上完成单个操作。较少使用异步编程的系统常可将状态与线程相关联,例如,线程可具有相关联的事务,该事务一旦开始,就总是被蕴含在来自该线程的任何方法问题上。在CDI中,工作流程的概念取代了线程的这个一般概念。工作流程总是准确地对应于用户所提交的批次。用户不创建工作流程。它是在新的批次被发布时由CDI自动创建的。如果出于其自己的目的有所需要的话,服务器插件即可从头创建工作流程。
工作流程还提供对创建新的异步工作项目、以及将其与工作流程相关联、并进而与发起批次相关联的支持。当该批次被取消,工作流程即被取消,进而该工作流程上的所有项目都被要求取消。使用此机制导致CDI无须在每个接口上都支持显式的取消方法,该方法改为接收工作流程。
工作流程接口如下所示。
typedef enum
{
WorkFlowIsRunning,
WorkFlowIsShutdown
} EImgWorkFlowState;
typedef enum
{
ExecuteNormal.
ExecuteLongFunction,
ExecuteIOThread
} EImgworkItemExecutionFlags;
[
object,
uuid(cdeaa3da-a58f-462c-a186-f4e462f0f74c),
local,
helpstring(″Server side item completion interface.″),
pointer_default(ref)
]
interface IImgWorkItemControl:IUnknown
{
HANDLE
WaitHandle(
void
);
}
interface IImgWorkItem:IUnknown
{
HRESULT
Run(
void
);
HRESULT
NotifyCancel(
void
);
}
interface IImgWorkFlow:IUnknown
{
//
//如果请求控制,则可在稍后删除该项目。这导致取消被发送到该工作项目。该工作项目必须
//自发地终止。如果请求工作流程状态,则在该工作流程已被关闭的情况下,该项目将不会被
//排队,而该流程的状态将被返回,否则调用将失败。
//
HRESULT
AddItem(
[in] IImgWorkItem *pIWorkItem,
[in] EImgWorkItemExecutionFlags Flags,
[out,unique] IImgWorkItemControl **ppIItemControl,
[out,unique] EImgWorkFlowstate *peWorkFlowState
);
HRESULT
AddWaitableItem(
[in] IImgWorkItem *pIWorkItem,
[in] EImgworkItemExecutionFlags Flags,
[out] IImgWorkItemControl **ppIItemControl,
[out,unique] EImgWorkFlowState *peWorkFlowState
);
HRESULT
AddDependentItem(
[in] IImgWorkItem *pIWorkItem,
[out] IImgworkItemControl **ppIItemControl,
[out,unique] EImgWorkFlowState *peWorkFlowState
);
HRESULT
Shutdown(
void
);
HRESULT
AddToken(
[in] REFGUID Guid
);
HRESULT
FindToken(
[in] REFGUID Guid,
[out] BOOL *pbFound
);
HRESULT
DeleteToken(
[in] REFGUID Guid
);
HRESULT
CreateNewScope(
[out] IImgWorkFlow **ppIWorkFlow
);
HRESULT
CreateTransaction(
[out] IImgBatchTransaction **ppIBatchTransaction,
[out] EImgBatchTransactionCreation *peBatchTransactionCreation
);
HRESULT
GetBatchTransaction(
[out] IImgBatchTransaction **ppIBatchTransaction
);
HRESULT
InsertTransactionalCollection(
[in] IUnknown *pITransCollection,
[in] REFGUID collectionID,
[out] IUnknown **ppISetTransCollection
);
HRESULT
GetTransactionalCollection(
[out] IUnknown **ppITransCollection,
[out] GUID *pCollectionID
);
}
interface IImgCommonDataServer:IImgCommonData
{
HRESULT
GetNewWorkFlow(
[out] IImgWorkFlow **ppIWorkFlow
);
}
我们将把讨论集中在工作流程所提供的以下服务上:工作项目、令牌、范围以及事务。事务在上文中被独立讨论,但工作流程对它们有一些特殊处理。
工作项目
为了实现工作项目,调用者必须实现IImgWorKItem接口。当工作项目执行时,在该接口上调用Run(运行)方法,而如果工作流程被取消,则Cancel(取消)方法被调用。
有三种基本类型的工作项目:
·普通工作项目,用“AddWorKItem”创建。只要有充分的资源可用, 这种工作项目即会运行。和所有工作项目一样,调用者可通过工作项目标志来指定哪种工作项目正在运行。
·可等待工作项目,用“AddWaitableItem”创建。可等待工作项目将在其相关联的事件被通知时运行。
·从属工作项目,用“AddDependentItem”创建。如果工作流程被取消,则从属工作项目不被运行,但其“Cancel”方法被调用。这允许调用者使用不同的异步方法(例如,它们可调用带有重叠结构的ReadFile),但仍从原始工作流程接收取消通知。
IImgWorkItemControl接口实现两个目的——它允许可等待工作项目返回可被设置以触发该工作项目的事件句柄。它还允许调用者通过释放接口来取消特定工作项目。在此情形中,取消调用总是异步的,即,向工作项目通知取消,但该接口上的Release(释放)调用不等待取消完成。
这与工作流程上的Shutdown(关闭)方法的行为不一样。关闭方法同步地等待工作流程中的所有工作项目被取消。
令牌
令牌被用来标记工作流程上的特定状态。它们旨在被用来防止实现截取时的无穷递归。即,特定类型的截取可将令牌添加到工作流程中,然后防止该类截取再次发生。
令牌是GUID——令牌可被添加到工作流程中,可在工作流程中找到,并可从工作流程中移除。
事务
一个工作流程恰好可具有一个事务。工作流程是可从其创建事务的唯一接口。工作流程提供若干用户处理当前事务的帮助程序方法。
·CreateTransaction创建事务,并将其与当前工作流程相关联。如果事务已经存在,则这被认为是良性的,当前事务被返回(调用者可推论这是通过EImgBatchTransactionCreation返回发生的)。
·GetBatchTransaction返回当前与工作流程相关联的批次事务,若其存在的话。如果不存在,则它返回NULL。
·InsertTransactionalCollection将集合插入到与工作流程相关联的事务中。被插入的集合或现有的集合经由被返回的ppISetTransCollection返回。如果这些集合是不兼容的(它们使用不同的GUID),则调用失 败。
·GetTransactionalCollection检索与和工作流相关联的事务相关联的事务式集合。
范围被界定的工作流程
一工作流程可包含其它工作流程。当一工作流程的范围被界定在另一工作流程内时,它自动从其父工作流程继承所有工作项目和令牌。它还从父工作流程继承正在进行中的任何事务。界定工作流程的范围允许两类主要的功能:
·父工作流程中的令牌不能被删除。这允许工作流程中的令牌集被“锁定”,直至工作流程调用递归退回到调用者。这是有用的,因为它可避免截取器不慎移除它不应移除的令牌。
·来自用户的非事务式请求可要求事务,以便作为实现细节被执行。例如,删除请求可要求若干子对象也被删除。因为原始的批次可能包含不应或不能被事务化的其它项目,所以我们不会向把事务添加到调用者所创建的工作流程中。解决方案是产生范围被界定在第一个工作流程内的工作流程,然后将事务与内部的工作流程相关联。这允许对任何工作项目的取消请求被保持,还允许原始工作流程上的任何令牌被保留,而无需使原始工作流程事务化。
服务器方的通知
CDI提供对插件集合的支持是希望支持通知。这允许通知通道同时从远程集合和本地(进程内或沙箱的)集合检索数据,并且仍然代表客户机一致地处理通知通道。CAS为特定对象上的通知提供附加支持(诸如通过其锁定基础结构确保通知被正确地串行化)。
每个批处理集合都被给予一个IImgNotificationDataServer接口,它被用来将数据推入对应于每个通知通道的客户机集合。CDI本身维护客户机集合以及通知的其它基础结构。
typedef enum
{
ImgNotificationCollectFieldHistory,
ImgNotificationDoNotCollectFieldHistory
} EImgNotificationFieldoptions;
typedef enum
{
NotifyAddNewObject,
NotifyAddMatchedFilter
}EImgNotifyAddReason;
typedef enum
{
NotifyRemoveDeletedObject,
NotifyRemoveDoesNotMatchFiIter
} EImgNotifyRemoveReason;
typedef enum
{
NotifyUpdatePopulate,
NotifyUpdate
} EImgNotifyUpdateReason;
interface IImgNotificationChannelShutdown:IUnknown
{
void
ShutdownChannel(
void
);
}
interface IImgpushNotifyDataThroughChannel:IUnknown
{
HRESULT
SendChangeDataNotify(
[in] EImgNotificationFieldoptions fieldOption,
[in] const ImgVariant *pVariantData,
[in] ULoNG MapIndex,
[in] IImgCanonicalName *objectID
);
HRESULT
SendAddObjectNotify(
[in] EImgNotifyAddReason reason,
[in] IImgCanonicalName *objectID
);
HRESULT
SendRemoveObjectNotify(
[in] EImgNotifyRemoveReason reason,
[in] IImgCanonicalName *objectID
);
HRESULT
SendDone(
[in] EImgNotifyUpdateReason reason
);
}
interface IImgNotificationDataServer:IUnknown
{
HRESULT
RegisterShutdown(
[in] IImgNotificationChannelShutdown *pINotifyChannelShutdown
HRESULT
CreateNotificationObject(
[out] IImgPushNotifyDataThroughChannel **pppushNotifyData
);
void
SendFailure(
[in] HRESULT ErrorCode,
[in,unique] IImgErrorInfo *pIError工nfo
);
}
通知数据服务器结构公开三个方法:
·RegisterShutdown - 此方法允许调用者注册对正被关闭的通道的关注。例如,远程访问适配器可能需要知道要在客户机通知通道被销毁时也要销毁它自己的通知通道。
·CreateNotificationObject - 此方法创建将数据推到通知通道中必须使用的新的通知接口。每IImgPushNotifyDataThroughChannel实例都不是线程安全的。系统提供通过IImgPushNotifyDataThroughChannel实例发送的任何改变被作为一个组发送或全部不被发送的保证。
·SendFailure - 可能发生阻碍通知被通过通道发送的致命错误。在此情形中,SendFailure方法可被调用。它确保将销毁通道。它还将以尽力服务方式将出错信息发送给调用者。
将通知数据推入通道接口具有以下方法:
·SendAddObjectNofity - 此方法告诉通道新的通知对象已被添加。该对象或可因为其刚被创建而被添加,或可具有已改变的状态来匹配查询过滤器。
·SendRemoveObjectNotify - 此方法告诉通道对象真的已被删除,或它不再匹配查询过滤器并因此被从客户机集合中逻辑地移除。
·SendChangeDataNotify - 此方法将单个字段信息沿通道向下发送到客户机。映射索引是客户机经注册的类描述中的字段的索引。所发送的每个改变可具有两个行为中的一个。如果改变被缓冲在系统中的某个地方,且发生对同一字段的另一个改变,则新的字段值起效。这具有将任何被缓冲的通知数据所需的存储最小化的优点。或者,每个改变都可以是显著的,在此情形中,调用者可请求保持每个改变的历史。
·SendDone - 这完成已被发送到IImgPushNotifyData接口的改变。或者通知的初始数据被发送,在此情形中可使用NotifyUpdatePopulate变体,或者这是关于对象状态中的后续改变的通知,在此情形中可指定NotifyUpdate。
友好名称解析插件
插件批处理集合用来插入到规范名称空间中的机制在以上题为“插件接口”的章节中描述。基本上,每个集合都由GUID标识。如果批处理集合还想支持友好名称,则它必须注册友好名称解析处理器。这在可能的情况下将被请求的类的友好名称转换为规范名称。以注册普通插件的相同方式向CDI注册友好名称解析器,不同之处在于使用友好名称类来代替集合GUID,并改为使用不同的类工厂和接口。类工厂和插件接口如下所示。
interface IImgClassNameResolvingHandlerFactory:IUnknown
{
HRESULT
LockServer(
[in] BOOL fLock
);
HRESULT
CreateInstance(
[in] IImgCommonData *pICommonData,
[in,unique] IXMLDOMNode *pXmlInitData,
[in] REFIID riid,
[out] void **ppvObj
);
}
interface IImgClassNameResolvingHandler:IUnknown
{
HRESULT
BeginResolveName(
[in,string] const wchar_t *pszName,
[in,string] const wchar_t *pszClass,
[in,unique] IImgServerItemCompletion *pICompletion,
[out,unique] void **ppContext
);
HRESULT
EndResolveName(
[in] void *pContext.
[out] IImgCanonicalNameIterator **ppIterator
);
}
当客户机请求名称解析时,如果友好名称解析器不能在高速缓存中找到该名称,则对应于该类的每个已注册的插件的名称解析处理器被调用(以并行调用的方式)。每个名称解析器都试图解析该名称,当名称解析结束时,解析器调用IImgServerItemCompletion接口上的Done。接着名称解析器将以BeginResolveName返回的相同上下文调用EndResolveName。然后名称解析器返回IImgCanonicalName迭代器,它包含名称解析器确定为对应于该友好名称的任何规范名称。
注意,名称解析器插件通常将对CDI接口使用获取、查询或命令来执行其名称解析。因此,实现异步接口通常不会有很大问题,因为它将进而被另一个异步接口调用。
为了避免调用者不得不为每个查询集合实现一个IImgCanonicalName迭代器,提供聚集规范名称并可从其返回迭代器实例的集合接口。此接口如下所示。
interface IImgCommonData:IUnknown
{
HRESULT
CreateCanonicalNameCollection(
[out] IImgCanonicalNameCollection **ppINameCollection
);
}
interface IImgCanonicalNameCollection:IUnknown
{
HRESULT
AddCanonicalName(
[in] IImgCanonicalName *pIImgCanonicalName
);
HRESULT
Merge(
[in] IImgCanonicalNameIterator *pIImgCanonicalNameEnum
);
HRESULT
GetIterator(
[out] IImgCanonicalNameIterator **ppIterator
);
}
集合适配器服务
在所示出并描述的实施例中,IIImgBatchCollection接口看似实现起来很复杂。调用者必须遍历每个批次项目,将其解码,并决定如何响应于该项目。一般而言,集合想要访问批次的唯一原因是要保持该批次以进行跨越机器或进程边界的发送。在批次实际上与被加载到持久存储及从持久存储加载的一组对象交互时,这是需要插件处理的很大复杂性。为此原因,提供了集合适配器服务。集合适配器服务提供以下功能:
·它从一组插件集合检索对象。
·它将实例化的对象高速缓存,并在它们没有被使用的时候刷新它们。
·它通过类型映射管理客户机对象到服务器对象的绑定。
·它协调兼容集合之间的事务。
·它结合事务管理对象锁。
·它管理同步和异步对象。
·它与查询编译器交互以实现对象过滤器。
·它通过动态地选择要串行还是并行地执行调用来最好地利用资源。
·它通过最优的锁定方案维护对象的并发。
·它处理对象改变通知。
如果基本CDI是将各插件粘合在一起的胶水,则集合适配器服务负责确保能尽可能简单地实现智能的、异步的、高性能的插件。根据一个实施例,在图14中示出集合适配器服务模型。
给定的CAS实例可有多个对象集合被插入其中。每个对象集合都支持单个类名,例如,“Printers”,且给定对象集合中的所有对象都是同类的。因此,它们可由表达给定服务器对象实现的所有属性和命令的单个类描述来描述。集合适配器 服务使用服务器类描述在客户机和服务器对象之间传输数据和执行对象命令。服务器中的每个对象都经由其IImgObject接口实现某些基本功能。
IImgCollectionAdapter具有以下接口:
interface IImgCollectionAdapter:IImgBatchCollection
{
HRESULT
Initialize(
[in] IImgCommonDataServer *pICommonDataServer
);
HRESULT
RegisterObjectCollection(
[in] IImgObjectCollection *pIObjectCollection
);
}
客户机通过调用其IImgBatchCollectionFactory::CreateInstance方法中的“CoCreateInstance”将集合适配器实例化。它调用IImgCollectionAdapter::Initialize并将向其传递的IImgCommonDataServer接口传递给该方法。然后它通过RegisterObjectCollection调用注册其每一个对象集合。
IImgObjectCollection具有以下方法:
interface IImgObjectCollection:IUnknown
{
//
//如果覆盖之下的此对象不支持事务,则此调用应以ENOTIMPL失败。
//
HRESULT
GetTransactionalCollectionData(
[out] IUnknown **ppITransactionalCollection,
[out] ETransactionSupport *peTransactionSupport,
[out] GUID *pCollectionID
);
HRESULT
GetCollectionData(
[out] IImgImmutableString **ppIObjectClass,
[out] GUID *pObjectID,
[out] ImgServerClassDescription *pServerClassDescription
);
HRESULT
BeginGet(
[in] IImgWorkFlow *pIworkFlow,
[in] IImgServerItemCompletion *pIItemCompletion,
[in] IImgImmutableString *pOIbjectName,
[out] void **ppContext
);
HRESULT
EndGet(
[in,unique] void *pContext,
[out] IImgObject **ppIObject
);
HRESULT
BeginEnum(
[in] IImgWorkFlow *pIWorkFlow,
[in] IImgServerItemCompletion *pIItemCompletion,
[in] IImgCanonicalName *pIObjectBase,
[in] IImgImmutableString *pIObjectBaseClass,
[in] IImgImmutablestring *pIQueryString,
[out] void **ppContext
);
HRESULT
EndEnum(
[in,unique] void *pContext,
[out] IImgObjectIterator **ppIObjects
);
HRESULT
Shutdown(
[in] EImgShutdownReason eReason
);
}
GetTransactionCollectionData调用返回集合如何事务,集合可不支持任何事务,可支持事务作为从属项目(这可由瞬态集合支持),或可通过返回依赖于底层存储系统的自定义事务接口以及唯一地标识事务可成功的范围的ID来支持事务。
GetCollectionData调用返回对象类名、优化的类型映射绑定中使用的ObjectId、以及描述每个对象的服务器类描述。其余调用,BeginGet和EndGet以及BeginEnum/EndEnum允许从集合检索对象。Shutdown(关闭)方法在IImgBatchCollection::Shutdown方法被调用时由CAS调用。
CAS所执行的很可能消耗大量时间的任何调用将表现为Begin/End对的形式。每个Begin调用取IImgServerItemCompletion接口,并允许通过ppContext参数返回上下文。CAS向接口的实现者提供以下保证:
·如果Begin(开始)调用失败,则End(结束)调用将不会被调用。
·如果Begin调用成功,则保证End调用会被调用。
·在IImgServerItemCompletion::Done方法被调用以前End调用将不会被调用。
·在Begin方法返回以前End调用将不会被调用。
·将向End调用传递在Begin调用中所返回的上下文。
这些保证允许Begin方法通过在Beging方法内调用Done来实现同步调用。它所执行的任何IO绑定的操作应或者在另一个线程中被执行(较佳的是与其它操作整合),或应进而被实现为异步调用。当异步项目完成时,则IImgServerItemCompletion::Done方法应被调用。如果Begin方法需要跟踪专属于该 调用的任何状态,则它可在ppContext参数中被返回。因为CAS保证End调用会被执行,所以上下文总是能够被释放。CAS使用以下用于调度调用的机制:
·如果调用是同步的(在Begin方法内调用了Done),且调用者请求并行执行,则假定该方法的执行是CPU绑定的。因此,下一个调用将被串行化在第一个调用上。如果调用失败,则结果被记录,但所有后续调用仍被执行。
·如果调用是异步的,并且客户机请求并行执行,则在原始线程中下一个“Begin”方法被立即调用。
·如果调用是异步的,并且客户机请求串行或事务式语义,则工作的其余部分将在调用IImgServerItemCompletion::Done方法的同一线程中被执行。
这些规则意味着CAS的客户机集合或对象必须确保IO绑定操作是在异步调用模式中执行的,否则它可能会阻碍其它工作项目的并行执行。
对象具有以下接口:
interfaceIImgObject:IUnknown
{
HRESULT
Initialize(
[in] IImgObjectHandler *pIChangeHandler,
[out] ULONG *pCallFilterFlags
);
HRESULT
GetRealObjectAddress(
[out] void **ppObject
);
HRESULT
BeginGet(
[in] IImgWorkFlow *pIWorkFlow,
[in] IImgServerItemCompletion *pICallCompletion,
[in] ULONG cTags,
[in,size_is(cTags)] ULONG_PTR *aTags,
[out] void **ppContext
);
HRESULT
EndGet(
[in,unique] void *pContext
);
HRESULT
CloneObject(
[out] IImgObject **ppIsettableObject
);
HRESULT
BeginSet(
[in] IImgWorkFlow *pIWorkFlow,
[in] IImgServerItemCompletion *pICallCompletion,
[in,unique] IImgBatchTransaction *pIBatchTransaction,
[in,unique] IUnknown *pITransactionalCollection,
[in] ULONG cTags,
[in,size_is(cTags)] ULONG_PTR *aTags,
[out] void **ppContext
);
HRESULT
Endset(
[in,unique] void *pContext
);
}
要被实现的方法如下:
·Initialize(初始化)调用在对象首次从集合被返回给CAS时由CAS调用。它向该对象传递允许该对象将其自身删除、将其自己锁定、与事务交互和向系统的其余部分发送改变通知的处理器接口。它还可返回调用过滤器。调用过滤器指示该对象是否支持部分实例化(在此情形中,在从其读出任何数据以前将对其调用BeginGet/EndGet方法)。
它还通过写出某些字段来指示它是否支持将对象持久化。在此情形中,BeginSet/EndSet方法将被调用,以准确地指定调用者在设置中指定了哪些属性。
·GetRealObjectAddress返回ImgServerClassDescription访问器所相对于的对象地址。这是必要的,因为如果对象是使用多继承来实现的,则IImgObject接口地址不一定和实际的对象地址相同。
·BeginGet/EndGet-这些方法仅在对象在其调用过滤器中指示它支持部分对象的情况下被调用。将向对象传递指示优化映射要读出哪些字段的标记。对象可在其首次从持久存储实例化以后使用此标记来获取重量级字段。如果对象执行此操作并且该调用是IO绑定的(几乎总是这样),则它必须使用异步调用模式。
·CloneObject-CAS假定对象是以不可变的方式实现的。这允许在从对象读取数据的同时,该对象保持不被锁定的状态。它简化了事务,因为可将对象保持在被复制的状态直至事务提交。因此,在设置发生以前,对象将被要求克隆其自身。对象必须以不可变的方式来编码才能与CAS兼容。
·BeginSet/EndSet-在设置中,当对象已被克隆以后这一对方法被调用,并且其访问器被用来改变其状态。对象可在此调用中确认其新状态是有效的。如果在调用过滤器中对象请求该新状态,则它将被告知在设置发生时客户机指定了哪些字段。
对象处理器
对象处理器是由CAS传递给每个对象以允许该对象以各种方式与CAS交互的接口。CAS中每个被高速缓存的对象有恰好一个对象处理器的实例。IImgObjectHandler还公开对应于每个对象的异步锁。此锁被CAS用来逻辑地将就状态改变而对对象的访问串行化,这些状态改变包括事务和改变通知。对象上的数 种动作要求对象被锁定。对象处理器接口强制执行此语义。对象处理器接口如下所示:
interface IImgObjectHandler:IUnknown
{
HRESULT
GetObjectLock(
[out] IImgAsyncLock **ppIObjectLock
);
HRESULT
DeleteObject(
[in] ImgLockContext lockLogicalID
);
HRESULT
CurrentObject(
[in] ImgLockContext lockLogicalID,
[out] IImgObject **ppIObject
);
HRESULT
ReplaceObject(
[in] ImgLockContext lockLogicalID,
[in] IImgObject *pIObject
HRESULT
GetChangeHandler(
[in] ImgLockContext lockLogicalID,
[out] IImgObjectChangeHandler **ppIChangeHandler
);
HRESULT
HoldObjectInCache(
void
);
HRESULT
ReleaseObjectFromCache(
void
);
}
对象异步锁
一个重要的方法是GetObjectLock,它允许调用者检索与对象相关联的锁。所返回的锁是支持事务式锁定的异步锁。锁及相关联的语义由CAS使用,且相同的语义应由其它调用者使用。接口如下所示。
interface IImgLockEntry:IUnknown
{
HRESULT
EnterLock(
[in] INT_PTR entryContext,
[in] ImgLockContext logicalID
);
HRESULT
NotifyCancel(
void
);
}
interface IImgLockSequence:IUnknown
{
//
//如果变量无效,则这只可能失败。一旦获得了序列,即确保能进入对象。序列必须被串行地获得,但不
//必在同一个线程中。
//
HRESULT
AcquireLock(
[in] INT_PTR entryContext
);
HRESULT
TryAcquireLock(
[out] BOOL *pbAcquired,
[out] ImgLockContext *pLogicalID
);
HRESULT
IsCancelled(
[out] BOOL *pbCancelled
);
}
interface IImgAsyncLock:IUnknown
{
HRESULT
GetLockSequence(
[in] IImgWorkFlow *pIWorkFlow,
[in] IImgLockEntry *pIEntryInterface,
[out] IImgLockSequence **ppILocksequence,
[out,unique] EImgWorkFlowState *peWorkFlowstate
);
HRESULT
ReleaseLock(
[in] ImgLockContext logicalID
);
HRESULT
AddTransactionToLock(
[in] IImgBatchTransaction *pIBatchTransaction,
[out] BOOL *pbTransactionAdded
);
HRESULT
WaitForTransactionToFinish(
[in] IImgWorkFlow *pIWorkFlow,
[in] IImgServerItemCompletion *pIItemCompletion,
[out,unique] EImgWorkFlowState *peWorkFlowState
);
};
锁是异步的,即当可获得该锁时它进行回调。这是有意的设计选择,它提供以下能力:
·试图获得锁的工作流程可被取消。因为锁接口是异步的,所以可通知调用者锁获得尝试被取消。
·因为锁被用来将诸事务上的对象访问串行化,并且因为事务可能必须获得许多对象并且通常必须将状态写到存储中,所以对象锁可能要被 保持很长一段时间。因此,任何锁访问都可能等待IO绑定的操作。使用异步锁允许为另一个CPU绑定的操作重用该线程,而不是必须等待IO完成。
注意,CAS对获取/查询和命令不使用对象锁。这意味着尽管事务可能逻辑上持有一操作,但是它仅将设置和通知串行化。如果调用者希望一命令是事务性的,则它们必须自己创建该事务并获得对象锁。
想要获得锁的调用者必须实现IImgLockEntry接口。此接口有两个方法,EnterLock和NotifyCancel。
EnterLock是在调用者已获得锁时被调用的。ImgLockContext被传递给EnterLock函数。这一锁上下文与该锁的特定获得被准确地相关联,并且必须在该锁被释放时被移交给锁接口。这实现两个目的:
·如果另一个调用者错误地试图在没有获得锁的情况下释放锁,则释放无效。
·锁必须被保持这一事实可由其它接口通过请求提供锁上下文而在语义上表达。这还可在执行相关联的动作以前检查锁确实被保持。
此外,如果调用者在其上获得锁的工作流被取消,则其接口上的NotifyCancel方法将被调用。它们随即可决定它们仍必须获得该锁,还是要中止它们对该锁的访问。它们可通过释放被返回的在其上它们调用了AcquireLock的锁序列接口来取消它们对锁的获得。
不希望发生调用者不能保证锁能被获得这样的情况。例如,它们可能想要获得锁,递增引用计数,然后释放该锁。然后它们可对对象执行某些动作,再次获得该锁,并递减引用计数。如果它们不能为第二个操作获得锁,则引用计数将永远无法被正确递减。
调用者确保对锁的访问的能力是由IImgLockSequence接口提供的。一旦从锁返回锁序列,即可保证该锁任何顺序获得和释放都会成功。这能起效是因为作为实现细节,IImgLockSequence接口是由保留足够存储因而总能够获得锁的对象实现的。
锁和事务
事务可能需要依次锁定许多对象。这在一个以上事务之间有任何对锁的循环获得的情况下给系统带来了死锁的机会。两个事务同时持有同一个锁在语义上是不合法的,所以锁提供了对事务的特殊支持。当在设置属性前锁定对象时,这被CAS自动使用,并且它应被想要实现事务式语义的任何对象使用。
一个锁每次只能恰好被一个事务持有。想要获得锁的事务使用AddTransactionToLock调用。如果已有事务持有该锁,则该调用将在pbTransactionAdded参数中返回FALSE。然后在向调用者返回失败以前,事务应被反转(这释放当前该事务所持有的任何锁或资源)并等待现有事务完成。调用者调用WaitForTransactionToFinish来等待任何持有该锁的事务完成(它们将被异步地通知)。如果没有任何事务持有该锁,则它们将立即回调。如果事务被提交或反转,则锁将被自动与该事务解除关联。
调用者应等待现有事务结束的原因是要保证如果调用者重试该操作,它们不会只是再次检索原来的(未被改变的)对象状态,并相对于持有该锁的事务进行“旋转”。
CDI/CAS最优锁定模型
CDI有意地不向客户机公开任何锁定构造。这有以下几个理由:
·每个锁都不得不向服务器添加附加的上下文额外开销,而这可由客户机维护。
·如果客户机进入出错状态并抓住锁不放,则它可能会损害服务器的操作。
·为了处理不释放锁的客户机,必须向服务器添加手动开锁机制。这是不然可被简单地避免的额外的UI和维护。
但是,服务器状态被正确地维护并且“决斗管理员”问题被避免是合乎需要的。如果两个管理员同时试图重命名一打印机,我们可能想要确保一个重命名成功而另一个失败。
系统部分地通过事务用来获得对象锁的机制来维护这些语义。还通过给予每个对象一个“Object:LockId”属性来进行维护。简言之,为了改变对象状态,还必须提供匹配当前对象锁ID的锁ID。这表示在试图改变对象以前是知道最后的对象状态的。如果提供了不匹配的对象ID,则改变状态的尝试将会失败。响应于此, 调用者必须重新获取它们想要改变的属性,并因此重新获取锁ID。良好编写的客户机然后将检查这些属性以确保它们想要实现的改变仍然是有意义的,然后才再次尝试该操作。
对象改变处理器
为了检索对应于对象的改变处理器,必须获得对象锁,然后必须调用该对象处理器上的GetChangeHandler方法。GetChangeHandler方法要求锁上下文。对象可用来获得改变处理器的其它机制是在设置期间将它作为参数被传入到属性访问器。(在此情形中,CAS在为调用者设置任何对象属性以前获得对象锁)。对象改变处理器接口如下所示。
interface IImgObjectChangeHandler:IUnknown
{
HRESULT
NotifyChange(
[in] ULONG_PTR tag
);
HRESULT
NotifyChangeData(
[in] EImgNotificationFieldOptions fieldOptions,
[in] ULONG_PTR tag
[in] ImgVariant *data
);
HRESULT
SendChanges(
void
);
}
CDI改变处理器接口已在上一节讨论。该接口提供将改变沿特定通道向下发送的能力。CAS增加了正确地界定查询范围并处理特定对象中可能被关注的所有通道的能力。对象所必须做的仅仅是指示哪些属性已改变。最简单的机制是调用NotifyChange并传递对应于已经改变的字段的标签。CAS随即将经由属性访问器检索对应于该字段的数据,并将属性改变通知发送给所有关注该改变的通道。
为了节省CAS检索属性的工作量,调用者还可经由NotifyChangeData调用直接指定数据。
最后,当所有改变都已被聚集到改变处理器中时,它们可经由SendChanges方法被发送。如果其中任何改变不能被发送,则CAS将销毁所有可能以该对象为目标的通知通道。
IATL对改变通知的支持
对象不难实现改变通知。为使之更加简单,如果仅通过CDI属性获取或设置改变了对象的属性,并且该属性被实现为数据成员,则IATL将为之自动生成改变通知代码。当指定字段时,gNotify修改器只需在类型映射中被传递给Field(字段)函数。如下所示。
class Job
{
public:
IImgImmutableString *Name;
};
IMG_ATTR_TABLE_BEGIN(Job,Img::iatl::TypeMap)
Type(L″Job.State″),
Field(
IMG_ATTR_FIELD(Name),
gNotify),
IMG_ATTR_TABLE_END
这将为属性自动构建获取和设置访问器。如果该属性改变,则该改变将被发送给由CAS提供给属性访问器的改变处理器。
其余对象处理器函数
Delete Object(删除对象)
此函数从CAS的高速缓存中删除对象。此函数还会向客户机发送改变通知。对象必须被锁定,且锁上下文必须被提供才能删除该对象。
Current Object(当前对象)
CAS使用不可变的对象模型。当对象被修改时,如果其状态被改变,则它被克隆,然后被插入到高速缓存中。如果发生错误,则新对象被丢弃。此设计的值得关注的含义是,如果对象希望将改变通知作为异步事件的结果发送,或者它需要属性获取期间或命令期间对象最后的版本,则它不能知道它当前持有的对象的实例是正确的实例。为处理此情况,对象处理器可检索当前对象实例。因为对象状态改变受到对象锁的保护,所以必须在当前对象可被有意义地检索以前获得锁。
HoldObjectInCache和ReleaseObjectFromCache
CAS通常在对象被丢弃以前将其高速缓存在存储器中大约10秒钟。对象可决 定改为永久留存在高速缓存中,或者在另一个对象被高速缓存的同时保持被高速缓存。为处理此需要,可在对象处理器上调用HoldObjectInCache方法。当被调用时,对象将被保持在高速缓存中,直至进行了对应的ReleaseObjectFromCache调用。HoldObjectInCache可被调用任意多次,只有在当进行了相同次数的对ReleaseObjectFromCache的调用时对象才会被释放。
仅可在对象已因为某些其它操作原因而被活动地保持在高速缓存中的情况下安全地调用HoldObjectInCache。否则,就可能有在正对HoldObjectInCache进行调用的同时该对象正被从高速缓存释放的竞争条件。这不会导致崩溃,但是很明显,在此情形中HoldObjectInCache调用不能被优先对待。保证HoldObjectInCache能成功的时间点是:
·在对该对象所支持的IImgObject接口的初始化调用期间。
·在任何属性获取或设置或命令调用期间。
·或当调用者知道它们先前已经发布过HoldObjectInCache调用时。
框架提供的集合
IImgObjectCollection和IImgObject接口不是特别难以实现,并且会有使用CAS的插件想要或需要同时实现这两者的情形。例如,当编写经由新的数据模型表示下级服务器上的对象的适配器时,会想要提供自己的IImgObjectCollection。但是,有很多情形中可使用标准框架提供的对象集合。这些在图15中示出。
各种框架提供的集合及其函数如下。
存储器内集合提供没有被持久化的对象的动态集合。此集合在由插件提供了要公开的若干实际的不可变对象(诸如过滤器工厂)时是很有用的。在诸如TS打印等情形中为轻量级不可持久化对象提供存储时它也是有用的。
持久对象集合服务是提供在持久存储中将对象持久化的能力的集合。可能有许多存储可在其中将对象持久化,包括注册表、SQL数据库或WinFS。每个存储都具有其自己的持久对象集合服务实例。持久对象集合服务将为把对象状态持久化到适当的存储中提供支持。它将使用服务器类型映射(ImgServerClassDescription)来检索必要的对象状态以进行存储。此外,在可能的情况下,它将把查询直接映射到由底层存储所提供的查询支持。
通知填充程序集合如下工作。在许多情形中,系统将被桥接到对通知提供有 限支持或不支持通知的下级系统。在此情形中,调用者需要枚举所有对象,查看新对象何时到来或离开,并在有任何字段改变的情况下激发合适的通知。因为IImgObjectCollection接口是公开的,并且ImgServerClassDescription允许调用者访问对象上的所有字段,所以将提供把此行为自动化的通用填充程序对象集合。还可为只是不想添加额外数行代码来支持通知的调用者使用此集合。但是,可为在改变时会自动生成通知的字段提供默认实现。
总而言之,该框架将提供若干固定对象集合,这将使大多数人无需实现自己的集合接口。适配器集合接口是可能的例外。提供填充程序集合是为了自动化从下级适配器的事件生成。
IImgObject的IATL实现
IImgObject也不是特别难实现的接口。为使编写标准对象尽可能地简单,IATL提供支持非部分对象实现的IImgObject的标准实现。其所实现的类如下:
·TServerObjectBase - 提供IUnknown、Initialize、BeginGet/EndGet和BeginSet/EndSet的默认实现。获取和设置函数不执行任何操作。
·TServerObject - 此模板通过基类模板化添加GetRealObjectAddress实现。
·TServerDefaultCloneableObject - 此模板添加CloneObject方法。调用者必须在其派生类中提供复制构造函数,并且必须或者不抛出异常、或者在出错情况下抛出异常、或者在对象已被复制以后从其IsValid()方法返回错误。
·TIMCServerObject - 此对象为存储器内集合实现BeginSet/EndSet方法对。
托管对象
IATL被设计成通过提供允许方法和字段通过CDI被表达为属性并允许方法通过CDI被表达为命令的模板库来对非托管的C++类提供自动化支持。保持在非托管空间中有许多好处,但是,系统也会想要为托管对象提供数据驱动的支持,特别是当托管代码在性能、强健性和设计稳定性方面有所提高的情况下。
因为CAS封装大量重要功能,所以有执行同样任务的并行托管实现是不明智的。解决方案是使用托管元数据在非托管空间中创建ImgServerClassDescription,并用其来填充和维护影子非托管对象。
图16中示出根据一个实施例的解决方案。在此,来自托管对象的类元数据被映射到非托管空间中的ImgServerClassDescription。这个类描述使用可操纵影子非托管对象的访问器。非托管对象中的每个属性可被索引,并将对应于托管对象中的一个属性。托管对象将使用改变通知机制将异步改变传播到影子非托管对象。每当在非托管对象上发生设置时,这些属性首先会被应用于托管对象,然后托管对象的状态将被复制回非托管对象。命令将被直接映射到托管对象上的方法调用。
此机制的优点是对象上最常用的操作获取和查询将完全在非托管影子对象上执行。此外,非托管影子对象可由非托管持久对象集合服务存储,并可被放在存储器内集合中。这还规避了原本执行属性获取所需的缓慢的反射机制。对托管对象的改变可被约束到每个批处理动作有一个可相互操作的替换程序。因为这是在CAS之后发生,所以我们不能在整个批次被解释以前对其进行封送。此限制应通过在查询和获取情形中完全避免托管路径来抵消。
示例性客户机设备/打印服务器组件
图17示出一种示例性计算设备,它具有可在客户机设备和打印系统中使用以实现上述实施例的组件。
计算设备1742包括一个或多个处理器或处理单元1744、系统存储器1746、以及将包括系统存储器1746在内的各个系统组件耦合到处理器1744的总线1748。总线1748表示数种总线结构中的任何一种或数种,包括存储器总线或存储器控制器、外围总线、加速图形端口、以及使用各种总线体系结构中的任何一种的处理器或局部总线。系统存储器1746包括只读存储器(ROM)1750和随机存取存储器(RAM)1752。包含诸如在启动期间帮助在计算设备1742的各元件之间传递信息的基本例程的基本输入/输出系统(BIOS)1754被存储在ROM1750中。
计算设备1742还可包括用于读或写硬盘(未示出)的硬盘驱动器1756,用于读或写可移动磁盘1760的磁盘驱动器1758、以及用于读或写诸如CDROM或其它光介质等可移动光盘1764的光盘驱动器1762。硬盘驱动器1756、磁盘驱动器1758和光盘驱动器1762由SCSI接口1766或某种其它适当的接口连接到总线1748。各驱动器及其相关联的计算机可读介质为计算机1742提供计算机可读指令、数据结构、程序模块或其它数据的非易失性存储。尽管这里所描述的示例性环境使用硬盘、可移动磁盘1760和可移动光盘1764,但是本领域技术人员应当认识到,在该示例性操作环境中还可使用可存储可由计算机访问的数据的其它类型的计算 机可读介质,诸如磁带盒、闪存卡、数字视频盘、随机存取存储器(RAM)、只读存储器(ROM)等等。
若干程序模块可被存储在硬盘1756、磁盘1760、光盘1764、ROM1750或RAM1752上,包括操作系统1770、一个或多个应用程序1772(诸如用户代理或浏览器)、其它程序模块1774、以及程序数据1776。用户可通过诸如键盘1778和定位设备1780等输入设备将命令和信息输入到计算机1742中。其它输入设备(未示出)可包括话筒、操纵杆、游戏垫、圆盘式卫星天线、扫描仪等。这些及其它输入设备通过被耦合到总线1748的接口1782连接到处理单元1744。监视器1784或其它类型的显示设备也经由诸如视频适配器1786等接口连接到总线1748。除了监视器以外,个人计算机通常还包括诸如扬声器和打印机等其它外围输出设备(未示出)。
计算机1742通常使用到诸如打印服务器1788等一台或多台远程计算机的逻辑连接在联网环境中操作,该打印服务器1788进而被连接到一台或数台打印机。打印服务器1788可以是另一台个人计算机、服务器、路由器、网络PC、对等设备或其它普通网络节点,并通常包括以上相对于计算机1742所描述的许多或全部元件。图17中所示的逻辑连接包括局域网(LAN)1790和广域网(WAN)1792。此类网络环境常见于办公室、企业范围的计算机网络、内联网以及因特网中。
当在LAN网络环境中使用时,计算机1742通过网络接口或适配器1794被连接到本地网络。当在WAN网络环境中使用时,计算机1742通常包括调制解调器1796或其它用于通过广域网1792(诸如因特网)建立通信的装置。可内置或外置的调制解调器1796经由串行端口接口1768被连接到总线1748。在联网环境中,相对于个人计算机1742所描述的程序模块或其部分可被存储在远程存储器存储设备中。可以认识到,所示网络连接是示例性的,并可使用其它用于在计算机之间建立通信链路的装置。
一般而言,计算机1742的数据处理器是通过在不同时间被存储在计算机的各个计算机可读存储介质中的指令来编程的。程序和操作系统通常被分布在例如软盘或CD-ROM上。它们被从那里安装或加载到计算机的次级存储器中。在执行时,它们至少被部分地加载到计算机的主电子存储器中。当这些及其它各种类型的计算机可读存储介质包含用于结合微处理器或其它数据处理器实现所述的块的指令时,本文中所描述的系统包括此类介质。当根据在此描述的方法和技术编程时,所述系统还可以包括计算机自身。
出于说明目的,本文中将诸如操作系统等程序及其它可执行程序组件示为离散的块,尽管可意识到,此类程序和组件在各个时间驻留在计算机的不同存储组件中,并由计算机的一个或多个数据处理器执行。
结论
上述各个实施例提供一种能允许第三方组件编写者能容易地将新的类插入到系统中的可插入体系结构。提供了一种允许从多个数据提供程序检索数据的路由系统。此外,一种名称解析管道将人类提供的名称解析为内部的规范名称。此外,各个实施例为客户机提供了准确地指定它想要从对象检索的数据的能力。一种用于从对象检索数据的极其高效的机制使用优化的类型映射。一旦类型映射被构建,就无需再执行任何串比较或搜索。还提供了能够支持任何数据的单个可插入接口。这意味着就建立而言,只需有一种类型的可安装对象。其它对象类型可通过集合从工厂对象获得。这可被用来构建例如管道元素。
此外,提供了一组允许系统中的任何对象能容易地支持查询、支持通知——包括经过滤的通知、支持高速缓存和工作调度的服务。
所描述的实施例还通过访问适配器提供隧穿任何协议的能力或可处理一组基本类型的传输。各个实施例还支持提供在下级协议上传输的对象集合、以及允许下级(和上级)协议被动态添加到系统中的能力。
此外,提供了一种异步数据接口。这是很重要的,因为每当出现大量最终为IO绑定的数据写时,同步接口会阻塞服务器。它还简化了UI编程,因为单个UI线程可执行,并且不会对其正在执行的操作停顿。
此外,批处理接口允许对象命令、获取、设置、查询和通知请求的任意分组。这是重要的,因为它使客户机能够支持诸如删除打印机集合等操作。它还是有利的,因为它允许减少网络延迟的作用。例如,当UI想要检索关于特定队列的若干属性时,它可将其所有请求批处理到一个消息,而这一个消息导致一次网络往返,而不是在顺序检索数据的情况下所需要的多次网络往返。
此外,各个实施例可提供几乎完全无状态的接口,唯一的例外是通知。
此外,通过利用客户机对象集合简化了该编程模型。一旦对象被成功的批处理执行填充,即可保证对被检索的数据的所有后续操作都将成功,因为它们被存储在对象状态中。该编程模型还巧妙地使通知和查询客户机语义几乎完全相同。
此外,CDI在后续迭代中或在某些集合中实现以下能力。首先,CDI实现通 过标准类型元数据系统发现新数据类型的能力。它允许诸如通用调试接口和数据查询接口等某些特征。第二,因为所有集合都具有同一接口,所以它们可在另一个进程或应用程序域中被沙箱化。第三,因为所有集合都具有同一接口,所以它允许系统使任何集合处于维护模式,并通过实现调用计数填充程序来卸载该集合。对升级现有组件的设置来说这是极其有用的。第四,通过允许批次也被事务化,事务式支持可被相当容易地添加。最后,因为所有对象都使用同一接口,所以诸如装饰器等模式可被容易地添加到系统中。这提供了使系统能由第三方以非常灵活的方式扩展的可能性。
尽管是以结构化特征和/或方法性步骤专属的语言描述了本发明,但是应当理解,在所附权利要求书中定义的发明不必局限于所描述的具体特征或步骤。相反,这些具体特征和步骤是作为实现要求保护的发明的较佳形式公开的。
Claims (13)
1.一种计算机执行的方法,包括:
提供被配置成提供通用数据模型的接口,所述接口包括指定能够调用哪些组件的配置信息;
提供异步客户机调度,所述异步客户机调度允许客户机或客户机应用程序开始数据请求,所述数据请求立即将控制返回给客户机线程;以及
提供异步服务器调度,其中服务器能异步地服务来自所述客户机的数据请求,
其中,所述客户机经由回调或被通知的系统事件得到通知,且能够检索所述数据请求的结果。
2.如权利要求1所述的计算机执行的方法,其特征在于,还包括提供取消,在所述取消中所述服务器上正在进行中的对数据请求的服务能由所述客户机在任何时候异步地取消。
3.如权利要求1所述的计算机执行的方法,其特征在于,还包括提供批处理,在所述批处理中客户机能构建任意的一系列动作,并使这些动作作为一个单元被发送给所述服务器。
4.如权利要求1所述的计算机执行的方法,其特征在于,还包括提供事务式调用,在所述事务式调用中能向一批动作赋予该批动作必须全部执行或者不改变所述服务器的状态的语义。
5.如权利要求1所述的计算机执行的方法,其特征在于,还包括提供并行调用,在所述并行调用中能向一批动作赋予该批动作中所有项目必须并行执行的语义。
6.如权利要求1所述的计算机执行的方法,其特征在于,还包括提供截取,在所述截取中能执行以下一个或多个动作的组件能被插入到一相关联的系统中:监视所述相关联的系统、同步地响应于所述相关联的系统、或者修改所述相关联的系统的行为。
7.如权利要求1所述的计算机执行的方法,其特征在于,还包括提供反射,通过所述反射,给定的一类对象所支持的属性能被检索。
8.如权利要求1所述的计算机执行的方法,其特征在于,还包括:
提供批处理,在所述批处理中客户机能构建任意的一系列动作,并使这些动 作作为一个单元被发送到所述服务器;以及
提供事务式调用,在所述事务式调用中一批动作能被赋予该批动作必须全部执行或者不改变所述服务器的状态的语义。
9.如权利要求1所述的计算机执行的方法,其特征在于,还包括:
提供批处理,在所述批处理中客户机能构建任意的一系列动作,并使这些动作作为一个单元被发送到所述服务器;以及
提供并行调用,在所述并行调用中能向一批动作赋予该批动作中所有项目必须并行执行的语义。
10.如权利要求1所述的计算机执行的方法,其特征在于,还包括提供:
提供批处理,在所述批处理中客户机能构建任意的一系列动作,并使这些动作作为一个单元被发送到所述服务器;
提供事务式调用,在所述事务式调用中能向一批动作赋予该批动作必须全部执行或者不改变所述服务器的状态的语义;以及
提供并行调用,在所述并行调用中可向一批动作赋予这批动作中所有项目必须并行执行的语义。
11.如权利要求1所述的计算机执行的方法,其特征在于,还包括:
提供批处理,在所述批处理中客户机能构建任意的一系列动作,并使这些动作作为一个单元被发送到所述服务器;以及
提供截取,在所述截取中能执行以下一个或多个动作的组件能被插入到一相关联的系统中:监视所述相关联的系统、同步地响应于所述相关联的系统、或者修改所述相关联的系统的行为。
12.如权利要求1所述的计算机执行的方法,其特征在于,还包括:
提供批处理,在所述批处理中客户机能构建任意的一系列动作,并使这些动作作为一个单元被发送到所述服务器;以及
提供反射,通过所述反射,给定的一类对象所支持的属性能被检索。
13.如权利要求1所述的计算机执行的方法,其特征在于,还包括:
提供批处理,在所述批处理中客户机能构建任意的一系列动作,并使这些动作作为一个单元被发送到所述服务器;
提供反射,通过所述反射,给定的一类对象所支持的属性能被检索;以及
提供截取,在所述截取中能执行以下一个或多个动作的组件能被插入到一相关联的系统中:监视所述相关联的系统、同步地响应于所述相关联的系统、或者修 改所述相关联的系统的行为。
Applications Claiming Priority (2)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
US11/077,514 | 2005-03-10 | ||
US11/077,514 US7962917B2 (en) | 2005-03-10 | 2005-03-10 | System data interfaces, related architectures, print system data interfaces and related print system architectures |
Publications (2)
Publication Number | Publication Date |
---|---|
CN1869923A CN1869923A (zh) | 2006-11-29 |
CN1869923B true CN1869923B (zh) | 2010-12-08 |
Family
ID=36808660
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN2006100037957A Expired - Fee Related CN1869923B (zh) | 2005-03-10 | 2006-02-10 | 系统数据接口及相关体系结构 |
Country Status (5)
Country | Link |
---|---|
US (1) | US7962917B2 (zh) |
EP (1) | EP1701245A3 (zh) |
JP (1) | JP2006252539A (zh) |
KR (1) | KR20060097577A (zh) |
CN (1) | CN1869923B (zh) |
Families Citing this family (41)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US7644403B2 (en) * | 2005-09-12 | 2010-01-05 | Oracle International Corporation | Method and system for automated root-cause analysis for class loading failures in java |
US7954096B2 (en) * | 2005-09-12 | 2011-05-31 | Oracle International Corporation | Shared loader system and method |
US8020156B2 (en) * | 2005-09-12 | 2011-09-13 | Oracle International Corporation | Bulk loading system and method |
US7784043B2 (en) * | 2005-09-12 | 2010-08-24 | Oracle International Corporation | Method and system for automated code-source indexing in Java Virtual Machine environment |
US7814472B2 (en) * | 2005-09-12 | 2010-10-12 | Oracle International Corporation | System and method for shared code-sourcing in a Java Virtual Machine environment |
JP4337824B2 (ja) * | 2006-01-30 | 2009-09-30 | ブラザー工業株式会社 | 仮想デバイス名変更プログラム |
JP4916729B2 (ja) * | 2006-01-30 | 2012-04-18 | ブラザー工業株式会社 | 仮想デバイス名変更プログラム |
JP4696938B2 (ja) * | 2006-01-30 | 2011-06-08 | ブラザー工業株式会社 | 仮想デバイス名変更プログラム |
US20070250499A1 (en) * | 2006-04-21 | 2007-10-25 | Simon Widdowson | Method and system for finding data objects within large data-object libraries |
US8386732B1 (en) * | 2006-06-28 | 2013-02-26 | Emc Corporation | Methods and apparatus for storing collected network management data |
US8744891B1 (en) * | 2007-07-26 | 2014-06-03 | United Services Automobile Association (Usaa) | Systems and methods for dynamic business decision making |
US8112516B2 (en) * | 2007-08-23 | 2012-02-07 | Cisco Technology, Inc. | Selective user notification based on IP flow information |
US8620856B2 (en) * | 2008-01-18 | 2013-12-31 | International Business Machines Corporation | Method and system for providing a data exchange service provider interface |
US20090271765A1 (en) * | 2008-04-29 | 2009-10-29 | Microsoft Corporation | Consumer and producer specific semantics of shared object protocols |
US20090313628A1 (en) * | 2008-06-13 | 2009-12-17 | Microsoft Corporation | Dynamically batching remote object model commands |
US8549090B2 (en) * | 2008-08-13 | 2013-10-01 | Hbc Solutions, Inc. | Messaging tracking system and method |
US8069172B2 (en) * | 2008-11-05 | 2011-11-29 | Oracle International Corporation | Re-executing query objects without affecting transaction data in an application development framework not providing for creation of multiple instances of the same query object |
CN102156705A (zh) * | 2011-01-26 | 2011-08-17 | 北京数码大方科技有限公司 | Cad文件加载方法及装置 |
US9619247B2 (en) * | 2011-07-15 | 2017-04-11 | Microsoft Technology Licensing, Llc | Enabling fast string acquisition in an operating system for efficient interoperations with various language projections |
US8898143B2 (en) * | 2012-09-28 | 2014-11-25 | Sap Se | Database comparison system and method |
WO2014062252A1 (en) * | 2012-10-19 | 2014-04-24 | Mcafee, Inc. | Secure disk access control |
US9191432B2 (en) * | 2013-02-11 | 2015-11-17 | Dell Products L.P. | SAAS network-based backup system |
US9442993B2 (en) | 2013-02-11 | 2016-09-13 | Dell Products L.P. | Metadata manager for analytics system |
US8893155B2 (en) * | 2013-03-14 | 2014-11-18 | Microsoft Corporation | Providing distributed array containers for programming objects |
US9706007B2 (en) * | 2013-10-17 | 2017-07-11 | Blue Syntax Consulting LLC | System and method for querying disparate data sources in real time |
US9531839B1 (en) | 2014-04-10 | 2016-12-27 | Google Inc. | Systems and methods for request isolation protection |
US9678787B2 (en) | 2014-05-23 | 2017-06-13 | Microsoft Technology Licensing, Llc | Framework for authoring data loaders and data savers |
US10698767B1 (en) * | 2014-12-22 | 2020-06-30 | Amazon Technologies, Inc. | Decentralized management of multi-service workflows |
KR20170129114A (ko) * | 2015-01-25 | 2017-11-24 | 이과지오 시스템스 엘티디. | 애플리케이션 중심의 객체 저장 |
CN106250208A (zh) * | 2016-08-02 | 2016-12-21 | 福建升腾资讯有限公司 | 基于Xen虚拟化平台在不同环境下池类型桌面的实现方法 |
CN107678867A (zh) * | 2017-09-26 | 2018-02-09 | 武汉斗鱼网络科技有限公司 | 一种进行远程过程调用的方法及装置 |
CN108009026A (zh) * | 2017-10-27 | 2018-05-08 | 深圳市买买提乐购金融服务有限公司 | 接口调用方法、第三方数据接入平台及计算机可读介质 |
CN110609753B (zh) * | 2018-06-15 | 2023-07-28 | 伊姆西Ip控股有限责任公司 | 用于优化远程调用的方法、设备和计算机程序产品 |
CN109240977A (zh) * | 2018-09-10 | 2019-01-18 | 浙江大学 | 一种基于四相双轨编码协议的异步路由器电路 |
CN111506366B (zh) * | 2020-04-17 | 2023-09-05 | 咪咕文化科技有限公司 | 插件调用方法、装置、电子设备与存储介质 |
CN111752720B (zh) * | 2020-06-27 | 2023-07-07 | 武汉众邦银行股份有限公司 | 一种异步请求伪装同步请求方法 |
JP7276265B2 (ja) * | 2020-06-30 | 2023-05-18 | 株式会社安川電機 | 生産システム、上位制御装置、制御装置、通信方法、及びプログラム |
CN111897572A (zh) * | 2020-08-06 | 2020-11-06 | 杭州有赞科技有限公司 | 一种数据处理方法、系统、计算机设备及可读存储介质 |
CN113051088B (zh) * | 2021-03-31 | 2022-03-08 | 广州锦行网络科技有限公司 | 程序加载方法、装置、设备及计算机可读介质 |
CN115269060B (zh) * | 2022-06-15 | 2023-06-20 | 知学云(北京)科技股份有限公司 | 一种基于aPaaS平台的服务执行前后置处理方法 |
US20240061851A1 (en) * | 2022-08-22 | 2024-02-22 | Sap Se | Explanation of Computation Result Using Challenge Function |
Family Cites Families (12)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US6253252B1 (en) | 1996-07-11 | 2001-06-26 | Andrew Schofield | Method and apparatus for asynchronously calling and implementing objects |
US6901596B1 (en) * | 1998-05-07 | 2005-05-31 | Hewlett-Packard Development Company, L.P. | Method of communicating asynchronous events to remote procedure call clients |
US7468802B1 (en) * | 2000-04-17 | 2008-12-23 | International Business Machines Corporation | Method and apparatus for processing print jobs via parallel spooling and despooling operations |
US7206843B1 (en) * | 2000-04-21 | 2007-04-17 | Sun Microsystems, Inc. | Thread-safe portable management interface |
US7324220B1 (en) * | 2001-07-09 | 2008-01-29 | Lexmark International, Inc. | Print performance under the windows® operating system |
JP3634783B2 (ja) * | 2001-09-14 | 2005-03-30 | キヤノン株式会社 | 印刷システム及び印刷データ処理方法 |
US20040194087A1 (en) * | 2002-04-11 | 2004-09-30 | International Business Machines Corporation | Batch processing of requests in a data processing network |
US7327482B2 (en) * | 2002-10-15 | 2008-02-05 | Sharp Laboratories Of America, Inc. | Integrated printer monitoring |
US7206807B2 (en) * | 2003-01-21 | 2007-04-17 | Bea Systems, Inc. | Asynchronous invoking a remote web service on a server by a client who passes on a received invoke request from application code residing on the client |
US7178150B1 (en) * | 2003-01-29 | 2007-02-13 | Sprint Communications Company L.P. | Serialization method for transmitting data via CORBA interceptors |
US7460260B2 (en) * | 2003-07-24 | 2008-12-02 | Toshiba Corporation | Method of providing continuous feedback |
US20050179936A1 (en) * | 2004-02-13 | 2005-08-18 | Microsoft Corporation | Scalable print spooler |
-
2005
- 2005-03-10 US US11/077,514 patent/US7962917B2/en not_active Expired - Fee Related
-
2006
- 2006-01-09 EP EP06000310A patent/EP1701245A3/en not_active Ceased
- 2006-01-27 KR KR1020060009054A patent/KR20060097577A/ko not_active Application Discontinuation
- 2006-02-09 JP JP2006032952A patent/JP2006252539A/ja not_active Withdrawn
- 2006-02-10 CN CN2006100037957A patent/CN1869923B/zh not_active Expired - Fee Related
Non-Patent Citations (1)
Title |
---|
A.L.Ananda etc..ASTRA-An Asynchronous Remote Procedure Call Facility.IEEE.1991,172-179. * |
Also Published As
Publication number | Publication date |
---|---|
US7962917B2 (en) | 2011-06-14 |
CN1869923A (zh) | 2006-11-29 |
EP1701245A3 (en) | 2008-02-20 |
EP1701245A2 (en) | 2006-09-13 |
KR20060097577A (ko) | 2006-09-14 |
US20060206903A1 (en) | 2006-09-14 |
JP2006252539A (ja) | 2006-09-21 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN1869923B (zh) | 系统数据接口及相关体系结构 | |
US7702725B2 (en) | Digital object repositories, models, protocol, apparatus, methods and software and data structures, relating thereto | |
US7555497B2 (en) | Systems and methods for separating units of information manageable by a hardware/software interface system from their physical organization | |
US7428546B2 (en) | Systems and methods for data modeling in an item-based storage platform | |
US7483915B2 (en) | Systems and method for representing relationships between units of information manageable by a hardware/software interface system | |
US8131739B2 (en) | Systems and methods for interfacing application programs with an item-based storage platform | |
US7739316B2 (en) | Systems and methods for the implementation of base schema for organizing units of information manageable by a hardware/software interface system | |
US6704803B2 (en) | Method and system for distributing data events over an information bus | |
JP4394643B2 (ja) | アイテムベースのストレージプラットフォームにおけるデータモデリングのためのシステムおよび方法 | |
EP1696352A2 (en) | Platform for data services across disparate application frameworks | |
US20050055354A1 (en) | Systems and methods for representing units of information manageable by a hardware/software interface system but independent of physical representation | |
US7761670B2 (en) | Modified machine architecture with advanced synchronization | |
JP2007521533A (ja) | アプリケーションプログラムをアイテムベースのストレージプラットフォームとインターフェースするためのシステムおよび方法 | |
JP2007515695A (ja) | ハードウェア/ソフトウェアインターフェースシステムにより管理可能な情報のユニットに対する関係および階層の同期サービスを実現するシステムおよび方法 | |
US7770159B2 (en) | Virtual types | |
TWI337310B (en) | Systems and methods for extensions and inheritance for units of information manageable by a hardware/software interface system | |
US20060101444A1 (en) | Global object system | |
JP4394644B2 (ja) | データの編成、検索、および共有のためのストレージプラットフォーム | |
RU2371757C2 (ru) | Системы и способы моделирования данных в основанной на предметах платформе хранения | |
Alanen et al. | Version control of software models | |
Specification | Data distribution service for real-time systems version 1.2 | |
Tian | Extending a multi-tenant aware ESB solution with evolution management | |
Rajasekar et al. | iRODS Micro-services | |
Dmckerl et al. | A C++/Linda Model for Distributed Objects | |
May et al. | Oracle Fusion Middleware User's Guide for Technology Adapters, 11g Release 1 (11.1. 1.6. 3) E10231-12 |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
C10 | Entry into substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
C14 | Grant of patent or utility model | ||
GR01 | Patent grant | ||
ASS | Succession or assignment of patent right |
Owner name: MICROSOFT TECHNOLOGY LICENSING LLC Free format text: FORMER OWNER: MICROSOFT CORP. Effective date: 20150428 |
|
C41 | Transfer of patent application or patent right or utility model | ||
TR01 | Transfer of patent right |
Effective date of registration: 20150428 Address after: Washington State Patentee after: MICROSOFT TECHNOLOGY LICENSING, LLC Address before: Washington State Patentee before: Microsoft Corp. |
|
CF01 | Termination of patent right due to non-payment of annual fee | ||
CF01 | Termination of patent right due to non-payment of annual fee |
Granted publication date: 20101208 |