Web服务贡献ID消歧

时间:2013-03-01 23:24:48

标签: wsdl xsd

我使用Web服务API,它可以提供通用类型的Result,它们都提供某些基本信息,最明显的是唯一ID。该唯一ID往往是 - 但不是必须 - 发件人定义的UUID,并不总是同一个人(但ID在整个系统中是唯一的)。

从根本上说,API会产生类似的东西(用Java编写,但语言应该是无关紧要的),只有基本接口代表共同的细节:

interface Result
{
    String getId();
}

class Result1 implements Result
{
    public String getId() { return uniqueValueForInstance; }
    public OtherType1 getField1() { /* ... */ }
    public OtherType2 getField2() { /* ... */ }
}

class Result2 implements Result
{
    public String getId() { return uniqueValueForInstance; }
    public OtherType3 getField3() { /* ... */ }
}

重要的是要注意每种Result类型可能代表完全不同类型的信息。其中一些不能与其他Result相关联,其中一些可以,无论它们是否具有相同的类型(例如,Result1都可以与Result2相关联,并且因此反之亦然,但可能存在一些无法相关的ResultX,因为它代表不同的信息。)

我们目前正在实现一个系统,它接收其中一些Result并在可能的情况下将它们关联起来,这会生成一个不同的Result对象,该对象是它关联在一起的容器:

class ContainerResult implements Result
{
    public String getId() { return uniqueValueForInstance; }
    public Collection<Result> getResults() { return containedResultsList; }
    public OtherType4 getField4() { /* ... */ }
}

class IdContainerResult implements Result
{
    public String getId() { return uniqueValueForInstance; }
    public Collection<String> getIds() { return containedIdsList; }
    public OtherType4 getField4() { /* ... */ }
}

这是两个容器,它们呈现不同的用例。第一个ContainerResult允许某人接收相关详细信息以及实际完整的相关数据。第二个IdContainerResult仅通过发送相关ID来牺牲完整列表以支持带宽。执行关联的系统不一定与客户端相同,并且客户端可以接收这些ID所代表的Result,这旨在允许它们通过简单地接收ID来显示其系统上的相关性。 / p>

现在,我的问题对某些人来说可能并不明显,对其他人来说可能是显而易见的:如果我只将{ID}作为IdContainerResult的一部分发送,那么客户如何知道如何匹配{ {1}}如果他们没有单一的ID商店?每个Result实现实际表示的数据类型有助于在无法关联时进行隔离,这意味着在大多数情况下,单个ID存储不太可能不会造成内存或存储负担。

我们提出的当前解决方案需要创建一种新类型的ID,我们将其称为Result,它将每个TypedId的XML名称空间和XML名称与{{{ 1}}的ID。

该解决方案的主要问题是,它需要维护一个可变的类型集合,这些类型在发现时会更新,或者需要事先了解所有类型,以便可以在任何客户端系统上正确关联ID。不幸的是,我无法提出更好的解决方案,但目前的解决方案感觉不对。

是否有人遇到类似情况,他们希望将原型Result与原始类型相关联,特别是考虑到WSDL的限制,并以更清洁的方式解决它?

1 个答案:

答案 0 :(得分:1)

这是我的建议:

  1. 您希望“客户知道如何在结束时匹配结果”。因此,在您的响应中包含一个额外的鉴别器字段,称为“RequestType”,一个字符串。

  2. 您希望避免“维护可识别的类型集合,这些类型会在发现时更新,或者先前了解所有类型,以便可以在任何客户端的系统上正确关联ID”。显然,每个客户端请求调用都知道结果将涉及哪个处理区域。因此,您可以让客户端在请求中传递“RequestType”字符串。只要RequestType是每种不同类型的客户端请求的唯一字符串,您的服务就可以处理和关联它,而无需对任何知识进行硬编码。

  3. 以下是请求和响应消息的java类的一个可能示例(即不是实际的服务端点):

    interface Request {
        String getId();
        String getRequestType();
        // anything else ...
    }
    
    interface Result {
        String getId();
        String getRequestType();
    }
    
    class Result1 implements Result {
        public String getId() { return uniqueValueForInstance; }
        public OtherType1 getField1() { /* ... */ }
        public OtherType2 getField2() { /* ... */ }
    }
    
    class Result2 implements Result {
        public String getId() { return uniqueValueForInstance; }
        public OtherType3 getField3() { /* ... */ }
    }
    
  4. 这是陷阱。上面的(2)和(3)没有给出完全动态的解决方案。您希望您的服务能够返回与每个不同请求相关的灵活记录结构。您有以下选择:

    4A)在XSD中,将Result声明为单一的强类型变体记录类型,并在WSDL中从单个服务端点和单个操作返回Result。在声明变量记录结构时,XSD仍然需要对鉴别器元素的值进行硬编码。

    4B)在XSD中,为每个可能的客户端请求声明多个强类型唯一类型Result1,Result2等。在WSDL中,有一个多个唯一命名的操作来返回其中的每一个。这些操作可以跨越一个或多个服务端点 - 甚至跨多个WSDL。虽然这避免了将请求类型硬编码为特定字段本身,但它实际上并不是一个通用的客户端独立解决方案,因为您仍然通过创建唯一名称来明确硬编码来区分每个请求类型对于每种结果类型和每个操作。所以任何明显的活力都是海市蜃楼。

    4C)在XSD中,定义一个灵活的通用数据结构,它不是变体,但有许多通常命名的字段,能够处理所需的所有可能结果。示例字段可以是“stringField1”,“stringField2”,“integerField1”,“dateField1058”等,即使用非常弱的类型并且在客户端上负担以神奇地知道每个字段中的数据。这个选项可能非常通用,但通常被认为是可怕的做法。它不够优雅,非常难以理解,容易出错并且无论如何都有内置的限制/假设 - 你怎么知道你有足够的通用字段?在你的情况下,(4A)可能是最好的选择。

    4D)使用灵活的XSD架构设计策略 - 类型可替代性和使用“any”元素。请参阅http://www.xfront.com/ExtensibleContentModels.html

    4E)对您自己的工厂类方法使用@Produces @SomeQualifier注释,该方法创建一个高级类型。这告诉CDI总是使用这种方法来构造特定的bean类型&amp;预选赛。您的工厂方法可以有奇特的逻辑来决定在每次调用时构造哪个特定的低级类型。 @SomeQualifier可以有其他参数来指导选择类型。这可能会将限定符的数量减少到只有一个。

    如果使用(4D),您将拥有灵活的服务端点设计,可以非常有效地处理不断变化的需求。但是您的服务实现仍然需要实现灵活的行为来决定为每个请求返回哪些结果字段。事实上,如果您对不同的数据结构有逻辑要求,那么您的代码必须知道如何为每个单独的请求处理这些数据结构,因此必须依赖于某种形式的RequestType /唯一操作名称来区分。任何完全动态处理的目标(不适应每个客户对结果数据的需求)都过于雄心勃勃。