NetBeansも6.5の正式版が出て、Silverlight2も正式版が出たばっかりということなので両方使って簡単なものを作ってみようと思う。
Silverlight2を使うので、クライアント側はSilverlight2を使わなければならない。
なので、サーバーはJavaでWebサービスを作るようにしてみる。
NetBeans側
作るWebサービスは、NetBeansに付属してくるサンプルデータベースの中にあるCUSTOMERテーブルの中身を返すものにしてみる。

とりあえずNetBeansでWebアプリケーションを新規作成する。とりあえず、フレームワークを何も選択しないで素のWebアプリケーションにしてみた。
プロジェクトを作ったらソースパッケージに適当なパッケージ(自分の作ったプログラムではcom.wankuma.kazukiにした)を作ってそこにWebサービスを新規作成する。
新規にサービスを作ると、下のようなエラーが起きる。
クイックフィックスでとりあえずオペレーションを1つ追加する。名前はgetCustomersにした。
とりあえず、戻り値はStringにしておく。
/**
*
* @author Kazuki
*/
@WebService()
public class CustomerService {
/**
* Web service operation
*/
@WebMethod(operationName = "getCustomers")
public String getCustomers() {
//TODO 実装コードをここに記述します:
return null;
}
}
次に、Customerのデータをとってくるためのクラスを作る。
ここはJPAでやろうと思う。新規作成で、データベースからのエンティティークラスを使いCustomerテーブルのエンティティを作成する。
Customerテーブルのエンティティを作ると関連があるのかDiscountCodeクラスも作られる。
DBアクセスの処理を書く前に、Java DB ドライバをライブラリから追加しておく。
そうして、CustomerServiceに以下のようなコードを書く。要は全件とってくるだけ。
@WebService()
public class CustomerService {
@PersistenceContext
private EntityManager em;
/**
* Web service operation
*/
@WebMethod(operationName = "getCustomers")
public CustomerResult[] getCustomers() {
// DBからデータ取得
List<Customer> customers = (List<Customer>) em.createQuery("select c from Customer c").getResultList();
// 戻り値用のリストを作る
List<CustomerResult> results = new ArrayList<CustomerResult>();
for (Customer c : customers) {
// 詰め替え
CustomerResult result = new CustomerResult();
result.setCustomerId(c.getCustomerId());
result.setName(c.getName());
result.setEmail(c.getEmail());
results.add(result);
}
// 配列にして戻す
return results.toArray(new CustomerResult[results.size()]);
}
}
CustomerResultクラスはcustomerIdプロパティとnameプロパティとemailプロパティの3つを持っただけのシンプルなクラスです。もちろんSerializableを実装する形で作る。
これで基本的に完成。Webサービスをテストからテストも可能になってる。
テスト画面は下のような感じになる。
ボタンを押すことで実行結果の確認も出来る。いい感じ。
Silverlight2側
SilverlightJavaという名前でSilverlightアプリケーションを作成する。
まずは、サービス参照を追加する。追加するのはもちろんJavaで作ったサービス。
JavaのサービスのWSDLへのURLを指定すると普通にサービス参照に追加される。
名前をつけるのがめんどくさかったので、とりあえずServiceReference1という名前で参照した。
Page.xaml.csでは、Webサービスを単純に呼び出して結果をDataContextに入れているだけのシンプル実装。
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
// 処理を呼び出し
var client = new ServiceReference1.CustomerServiceClient();
client.getCustomersCompleted += new EventHandler<SilverlightJava.ServiceReference1.getCustomersCompletedEventArgs>(client_getCustomersCompleted);
client.getCustomersAsync(client);
}
void client_getCustomersCompleted(object sender, SilverlightJava.ServiceReference1.getCustomersCompletedEventArgs e)
{
// 実行結果をDataContextへ
DataContext = e.Result;
}
}
後はXAMLで見た目を整えれば大丈夫。今回はDataGridに単純に表示するだけにした。
<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="SilverlightJava.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300" Loaded="UserControl_Loaded">
<Grid x:Name="LayoutRoot" Background="White">
<data:DataGrid x:Name="dataGrid" ItemsSource="{Binding}" />
</Grid>
</UserControl>
これでSilverlight側もおしまい。
仕上げ
これでWebサービスとSiliverlight2の両方を実行してもエラーが出てしまう。
これは、WebサービスとSilverlightをホストしてるサーバーのドメインが違うからおきてしまうらしい。
まぁSilverlightからWebサービスが呼び放題とかどうよ?って感じになるからね。
これを、呼び出せるようにするにはWebサービス側にclientaccesspolicy.xmlという名前のファイルを置いてやる必要がある。置く場所は、Webサービスのある側のルートに置くらしい。つまり、http://ドメイン/clientaccesspolicy.xmlでアクセスできないといけない。
実際には、何処に何をアクセスさせるか決めないといけないけど、とりあえずは全アクセス許可で作った。
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
これをGlassFishのpersonalDomain/docrootに置いて実行する。
今度は無事実行される。
いい感じ。