37.3. ウィジェットベンダーの例

37.3.1. ウィジェット注文インターフェイス

このセクションでは、実際のアプリケーションを解決するために Apache CXF で使用されている置換グループの例を示します。サービスとコンシューマーは、例37.2「複雑なタイプの置換グループ」 で定義されたウィジェット置換グループを使用して開発されます。サービスは、checkWidgetsplaceWidgetOrder の 2 つの操作を提供します。例37.12「ウィジェット注文インターフェイス」 は、注文サービスのインターフェイスを示しています。

例37.12 ウィジェット注文インターフェイス

<message name="widgetOrder">
  <part name="widgetOrderForm" type="xsd1:widgetOrderInfo"/>
</message>
<message name="widgetOrderBill">
  <part name="widgetOrderConformation"
        type="xsd1:widgetOrderBillInfo"/>
</message>
<message name="widgetMessage">
  <part name="widgetPart" element="xsd1:widget" />
</message>
<message name="numWidgets">
  <part name="numInventory" type="xsd:int" />
</message>
<portType name="orderWidgets">
  <operation name="placeWidgetOrder">
    <input message="tns:widgetOrder" name="order"/>
    <output message="tns:widgetOrderBill" name="bill"/>
  </operation>
  <operation name="checkWidgets">
    <input message="tns:widgetMessage" name="request" />
    <output message="tns:numWidgets" name="response" />
  </operation>
</portType>

例37.13「ウィジェットの注文 SEI」 は、インターフェイス用に生成された Java SEI を示しています。

例37.13 ウィジェットの注文 SEI

@WebService(targetNamespace = "http://widgetVendor.com/widgetOrderForm", name = "orderWidgets")
@XmlSeeAlso({com.widgetvendor.types.widgettypes.ObjectFactory.class})
public interface OrderWidgets {

    @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
    @WebResult(name = "numInventory", targetNamespace = "", partName = "numInventory")
    @WebMethod
    public int checkWidgets(
        @WebParam(partName = "widgetPart", name = "widget", targetNamespace = "http://widgetVendor.com/types/widgetTypes")
        com.widgetvendor.types.widgettypes.WidgetType widgetPart
    );

    @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
    @WebResult(name = "widgetOrderConformation", targetNamespace = "", partName = "widgetOrderConformation")
    @WebMethod
    public com.widgetvendor.types.widgettypes.WidgetOrderBillInfo placeWidgetOrder(
        @WebParam(partName = "widgetOrderForm", name = "widgetOrderForm", targetNamespace = "")
        com.widgetvendor.types.widgettypes.WidgetOrderInfo widgetOrderForm
    ) throws BadSize;
}
注記

この例は置換グループの使用のみを示しているため、一部のビジネスロジックは示されていません。

37.3.2. checkWidgets の操作

概要

checkWidgets は、置換グループのヘッドメンバーのパラメーターがある簡単な操作です。この操作は、置換グループのメンバーである個々のパラメーターを処理する方法を示しています。コンシューマーは、パラメーターが置換グループの有効なメンバーであることを確認する必要があります。サービスは、置換グループのどのメンバーが要求で送信されたかを適切に判別する必要があります。

コンシューマーの実装

生成されたメソッドシグネチャーは、置換グループの head 要素のタイプをサポートする Java クラスを使用します。置換グループのメンバー要素は、head 要素と同じ型であるか、head 要素の型から派生した型であるため、置換グループのメンバーをサポートするために生成された Java クラスは、head 要素をサポートするために生成された Java クラスから派生している。Java の型階層は、親クラスの代わりにサブクラスを使用することをネイティブにサポートします。

Apache CXF が置換グループの型および Java の型階層を生成する方法が原因で、クライアントは特別なコードを使用せずに checkWidgets() を呼び出すことができます。checkWidgets() を呼び出すロジックを開発する場合は、ウィジェットの置換グループに対応するために生成されたクラスの 1 つのオブジェクトを渡すことができます。

例37.14「checkWidgets() を呼び出すコンシューマー」 に、checkWidgets() を呼び出すコンシューマーを示します。

例37.14 checkWidgets() を呼び出すコンシューマー

System.out.println("What type of widgets do you want to order?");
System.out.println("1 - Normal");
System.out.println("2 - Wood");
System.out.println("3 - Plastic");
System.out.println("Selection [1-3]");
String selection = reader.readLine();
String trimmed = selection.trim();
char widgetType = trimmed.charAt(0);
switch (widgetType)
{
  case '1':
  {
    WidgetType widget = new WidgetType();
    ...
    break;
  }
  case '2':
  {
    WoodWidgetType widget = new WoodWidgetType();
    ...
    break;
  }
  case '3':
  {
    PlasticWidgetType widget = new PlasticWidgetType();
    ...
    break;
  }
  default :
    System.out.println("Invaid Widget Selection!!");
}

proxy.checkWidgets(widgets);

サービス実装

checkWidgets() のサービスの実装は、ウィジェットの記述を WidgetType オブジェクトとして取得し、ウィジェットのインベントリーを確認し、ストックされているウィジェットの数を返します。置換グループの実装に使用されるクラスはすべて同じベースクラスから継承されるため、JAXB 固有の API を使用せずに checkWidgets() を実装することができます。

widget の置換グループのメンバーをサポートするように生成されたクラスはすべて、WidgetType クラスを拡張します。このため、instanceof を使用して、渡されたウィジェットの型を決定し、単純に widgetPart オブジェクトをより制限のある型にキャストできます (適切であれば)。適切なタイプのオブジェクトを取得したら、適切な種類のウィジェットのインベントリーを確認できます。

例37.15「checkWidgets() のサービス実装」 は、可能な実装を示しています。

例37.15 checkWidgets() のサービス実装

public int checkWidgets(WidgetType widgetPart)
{
  if (widgetPart instanceof WidgetType)
  {
    return checkWidgetInventory(widgetType);
  }
  else if (widgetPart instanceof WoodWidgetType)
  {
    WoodWidgetType widget = (WoodWidgetType)widgetPart;
    return checkWoodWidgetInventory(widget);
  }
  else if (widgetPart instanceof PlasticWidgetType)
  {
    PlasticWidgetType widget = (PlasticWidgetType)widgetPart;
    return checkPlasticWidgetInventory(widget);
  }
}

37.3.3. placeWidgetOrder 操作

概要

placeWidgetOrder は、置換グループが含まれる 2 つの複合型を使用します。この操作は、Java 実装でそのような構造を使用することを示しています。コンシューマーとサービスの両方が、置換グループのメンバーを取得および設定する必要があります。

コンシューマーの実装

placeWidgetOrder() を呼び出すには、コンシューマーはウィジェットの置換グループの要素が 1 つ含まれるウィジェットの注文を構築する必要があります。ウィジェットをオーダーに追加する場合、コンシューマーは、置換グループの各要素に対して生成されたオブジェクトファクトリーメソッドを使用する必要があります。これにより、ランタイムとサービスが注文を正しく処理できるようになります。たとえば、プラスチックウィジェットに注文が置かれている場合、要素を注文に追加する前に ObjectFactory.createPlasticWidget() メソッドを使用して要素を作成します。

例37.16「代替グループメンバーの設定」に、WidgetOrderInfo オブジェクトの widget プロパティーを設定するためのコンシューマーコードを示します。

例37.16 代替グループメンバーの設定

ObjectFactory of = new ObjectFactory();

WidgetOrderInfo order = new of.createWidgetOrderInfo();
...
System.out.println();
System.out.println("What color widgets do you want to order?");
String color = reader.readLine();
System.out.println();
System.out.println("What shape widgets do you want to order?");
String shape = reader.readLine();
System.out.println();
System.out.println("What type of widgets do you want to order?");
System.out.println("1 - Normal");
System.out.println("2 - Wood");
System.out.println("3 - Plastic");
System.out.println("Selection [1-3]");
String selection = reader.readLine();
String trimmed = selection.trim();
char widgetType = trimmed.charAt(0);
switch (widgetType)
{
  case '1':
  {
    WidgetType widget = of.createWidgetType();
    widget.setColor(color);
    widget.setShape(shape);
    JAXB<WidgetType> widgetElement = of.createWidget(widget); order.setWidget(widgetElement);
    break;
  }
  case '2':
  {
    WoodWidgetType woodWidget = of.createWoodWidgetType();
    woodWidget.setColor(color);
    woodWidget.setShape(shape);
    System.out.println();
    System.out.println("What type of wood are your widgets?");
    String wood = reader.readLine();
    woodWidget.setWoodType(wood);
    JAXB<WoodWidgetType> widgetElement = of.createWoodWidget(woodWidget); order.setWoodWidget(widgetElement);
    break;
  }
  case '3':
  {
    PlasticWidgetType plasticWidget = of.createPlasticWidgetType();
    plasticWidget.setColor(color);
    plasticWidget.setShape(shape);
    System.out.println();
    System.out.println("What type of mold to use for your
                        widgets?");
    String mold = reader.readLine();
    plasticWidget.setMoldProcess(mold);
    JAXB<WidgetType> widgetElement = of.createPlasticWidget(plasticWidget); order.setPlasticWidget(widgetElement);
    break;
  }
  default :
    System.out.println("Invaid Widget Selection!!");
    }

サービス実装

placeWidgetOrder() メソッドは、WidgetOrderInfo オブジェクトの形式で注文を受け取り、順番を処理し、WidgetOrderBillInfo オブジェクトの形式でコンシューマーに請求書を返します。注文は、プレーンウィジェット、プラスチックウィジェット、または木製ウィジェットの場合があります。注文されたウィジェットの種類は、どの型のオブジェクトが widgetOrderForm オブジェクトの widget プロパティーに保存されているかによって決まります。widget プロパティーは 置換グループで、widget 要素、woodWidget 要素、または plasticWidget 要素を含めることができます。

実装は、可能な要素のどれが順序で格納されるかを決定する必要があります。要素の QName を決定する JAXBElement<? extends T> オブジェクトの getName() メソッドを使用して、これを実現できます。次に、QName を使用して、置換グループ内のどの要素が順序になっているのかを判別できます。請求書に含まれる要素がわかれば、その値を適切なタイプのオブジェクトに抽出できます。

例37.17「placeWidgetOrder() の実装」 は、可能な実装を示しています。

例37.17 placeWidgetOrder() の実装

public com.widgetvendor.types.widgettypes.WidgetOrderBillInfo placeWidgetOrder(WidgetOrderInfo widgetOrderForm)
{
  ObjectFactory of = new ObjectFactory();

  WidgetOrderBillInfo bill = new WidgetOrderBillInfo()

   // Copy the shipping address and the number of widgets
   // ordered from widgetOrderForm to bill
   ...

  int numOrdered = widgetOrderForm.getAmount();

  String elementName = widgetOrderForm.getWidget().getName().getLocalPart();
  if (elementName.equals("woodWidget")
  {
    WoodWidgetType widget=order.getWidget().getValue();
    buildWoodWidget(widget, numOrdered);

    // Add the widget info to bill
    JAXBElement<WoodWidgetType> widgetElement = of.createWoodWidget(widget);
    bill.setWidget(widgetElement);

    float amtDue = numOrdered * 0.75;
    bill.setAmountDue(amtDue);
  }
  else if (elementName.equals("plasticWidget")
  {
    PlasticWidgetType widget=order.getWidget().getValue();
    buildPlasticWidget(widget, numOrdered);

    // Add the widget info to bill
    JAXBElement<PlasticWidgetType> widgetElement = of.createPlasticWidget(widget);
    bill.setWidget(widgetElement);

    float amtDue = numOrdered * 0.90;
    bill.setAmountDue(amtDue);
  }
  else
  {
    WidgetType widget=order.getWidget().getValue();
    buildWidget(widget, numOrdered);

    // Add the widget info to bill
    JAXBElement<WidgetType> widgetElement = of.createWidget(widget);
    bill.setWidget(widgetElement);

    float amtDue = numOrdered * 0.30;
    bill.setAmountDue(amtDue);
  }

  return(bill);
}

例37.17「placeWidgetOrder() の実装」 のコードは、以下を行います。

オブジェクトファクトリーをインスタンス化して要素を作成します。

WidgetOrderBillInfo オブジェクトをインスタンス化して、請求を保持します。

注文されたウィジェットの数を取得します。

注文に保存されている要素のローカル名を取得します。

要素が woodWidget 要素かどうかを確認します。

注文から適切なタイプのオブジェクトに要素の値を抽出します。

JAXBElement<T> オブジェクトを作成します。

bill オブジェクトの widget プロパティーを設定します。

bill オブジェクトの amountDue プロパティーを設定します。