View Javadoc

1   /*
2    *
3    * The Seasar Software License, Version 1.1
4    *
5    * Copyright (c) 2003-2004 The Seasar Project. All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or
8    * without modification, are permitted provided that the following
9    * conditions are met:
10   *
11   * 1. Redistributions of source code must retain the above
12   *    copyright notice, this list of conditions and the following
13   *    disclaimer.
14   *
15   * 2. Redistributions in binary form must reproduce the above
16   *    copyright notice, this list of conditions and the following
17   *    disclaimer in the documentation and/or other materials provided
18   *    with the distribution.
19   *
20   * 3. The end-user documentation included with the redistribution,
21   *    if any, must include the following acknowledgement:
22   *    "This product includes software developed by the
23   *    Seasar Project (http://www.seasar.org/)."
24   *    Alternately, this acknowledgement may appear in the software
25   *    itself, if and wherever such third-party acknowledgements
26   *    normally appear.
27   *
28   * 4. Neither the name "The Seasar Project" nor the names of its
29   *    contributors may be used to endorse or promote products derived
30   *    from this software without specific prior written permission of
31   *    the Seasar Project.
32   *
33   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR
34   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
36   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE SEASAR PROJECT
37   * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38   * INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42   * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING
43   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
44   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45   */
46  package org.seasar.remoting.common.connector.impl;
47  
48  import java.lang.reflect.Method;
49  import java.net.MalformedURLException;
50  import java.net.URL;
51  import java.util.LinkedHashMap;
52  import java.util.Map;
53  
54  /***
55   * ターゲットとなるオブジェクトごとに個別のURLを使用してリモートメソッド呼び出しを行うコネクタの抽象基底クラスです。
56   * <p>
57   * このコネクタはリモートオブジェクトの名前をスーパークラスのプロパティに設定されたベースURLからの相対URLとしてターゲットとなるリモートオブジェクトのURLを解決します。
58   * このため,ベースURLがスラッシュ( <code>/</code> )で終了していない場合、予期しない結果になるかもしれないことに注意してください。
59   * <p>
60   * 例を示します。 <br>
61   * ベースURLが次のように設定されているとします。
62   * 
63   * <pre>
64   *  http://host/context/services/
65   * </pre>
66   * 
67   * リモートオブジェクトが次の名前であるとします。
68   * 
69   * <pre>
70   *  Foo
71   * </pre>
72   * 
73   * リモートオブジェクトのURLは次のようになります。
74   * 
75   * <pre>
76   *  http://host/context/services/Foo
77   * </pre>
78   * 
79   * ベースURLが次のようにスラッシュ( <code>/</code> )で終了していない場合は結果が異なります。
80   * 
81   * <pre>
82   *  http://host/context/services
83   * </pre>
84   * 
85   * リモートオブジェクトが次の名前であるとします。
86   * 
87   * <pre>
88   *  Foo
89   * </pre>
90   * 
91   * リモートオブジェクトのURLは次のようになります。
92   * 
93   * <pre>
94   *  http://host/context/Foo
95   * </pre>
96   * 
97   * @author koichik
98   */
99  public abstract class TargetSpecificURLBasedConnector extends URLBasedConnector {
100     /***
101      * リモートオブジェクトのURLをキャッシュする上限のデフォルト値
102      */
103     protected static final int DEFAULT_MAX_CACHED_URLS = 10;
104 
105     protected LRUMap cachedURLs = new LRUMap(DEFAULT_MAX_CACHED_URLS);
106 
107     /***
108      * リモートオブジェクトのURLをキャッシュする上限を設定します。
109      * 
110      * @param maxCachedURLs
111      *            リモートオブジェクトのURLをキャッシュする上限です
112      */
113     public synchronized void setMaxCachedURLs(final int maxCachedURLs) {
114         cachedURLs.setMaxSize(maxCachedURLs);
115     }
116 
117     /***
118      * ターゲットとなるリモートオブジェクトのURLを解決し、サブクラス固有の方法でメソッド呼び出しを実行します。
119      * 
120      * @param remoteName
121      *            リモートオブジェクトの名前
122      * @param method
123      *            呼び出すメソッド
124      * @param args
125      *            リモートオブジェクトのメソッド呼び出しに渡される引数値を格納するオブジェクト配列
126      * @return リモートオブジェクトに対するメソッド呼び出しからの戻り値
127      * @throws Throwable
128      *             リモートオブジェクトに対するメソッド呼び出しからスローされた例外です
129      */
130     public Object invoke(final String remoteName, final Method method, final Object[] args)
131             throws Throwable {
132         return invoke(getTargetURL(remoteName), method, args);
133     }
134 
135     /***
136      * ターゲットとなるリモートオブジェクトのURLを返します。
137      * リモートオブジェクトのURLは、リモートオブジェクトの名前をベースURLからの相対URLとして解決します。
138      * 
139      * @param remoteName
140      *            ターゲットとなるリモートオブジェクトの名前
141      * @return ターゲットとなるリモートオブジェクトのURL
142      * @throws MalformedURLException
143      *             ベースURLとリモートオブジェクトの名前からURLを作成できなかった場合にスローされます
144      */
145     protected synchronized URL getTargetURL(final String remoteName) throws MalformedURLException {
146         URL targetURL = (URL) cachedURLs.get(remoteName);
147         if (targetURL == null) {
148             targetURL = new URL(baseURL, remoteName);
149             cachedURLs.put(remoteName, targetURL);
150         }
151         return targetURL;
152     }
153 
154     /***
155      * サブクラス固有の方法でリモートメソッドの呼び出しを実行し、その結果を返します。
156      * 
157      * @param targetURL
158      *            ターゲットとなるリモートオブジェクトのURL
159      * @param method
160      *            呼び出すメソッド
161      * @param args
162      *            リモートオブジェクトのメソッド呼び出しに渡される引数値を格納するオブジェクト配列
163      * @return リモートオブジェクトに対するメソッド呼び出しからの戻り値
164      * @throws Throwable
165      *             リモートオブジェクトに対するメソッド呼び出しからスローされた例外です
166      */
167     protected abstract Object invoke(URL targetURL, Method method, Object[] args) throws Throwable;
168 
169     /***
170      * LRUマップ <br>
171      * エントリ数に上限があり、それを超えてエントリが追加された場合にはもっとも使用されていないエントリが取り除かれるマップの実装です。
172      * エントリ数の上限は随時増やすことが出来ますが、減らしてもその数までエントリが取り除かれることはありません。 このマップは同期されません。
173      * 
174      * @author koichik
175      */
176     protected static class LRUMap extends LinkedHashMap {
177         /*** デフォルト初期容量 */
178         protected static final int DEFAULT_INITIAL_CAPACITY = 16;
179         /*** デフォルト負荷係数 */
180         protected static final float DEFAULT_LOAD_FACTOR = 0.75f;
181 
182         protected int maxSize;
183 
184         /***
185          * デフォルトの初期容量と負荷係数で指定されたエントリ数を上限とするインスタンスを構築します。
186          * 
187          * @param maxSize
188          *            エントリ数の最大数
189          */
190         public LRUMap(final int maxSize) {
191             this(maxSize, DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
192         }
193 
194         /***
195          * 指定された初期容量と負荷係数、エントリ数の上限を持つインスタンスを構築します。
196          * 
197          * @param maxSize
198          *            エントリ数の最大数
199          * @param initialCapacity
200          *            初期容量
201          * @param loadFactor
202          *            負荷係数
203          */
204         public LRUMap(final int maxSize, final int initialCapacity, final float loadFactor) {
205             super(initialCapacity, loadFactor, true);
206             this.maxSize = maxSize;
207         }
208 
209         /***
210          * エントリ数の最大値を設定します。
211          * 
212          * @param maxSize
213          *            エントリ数の最大数
214          */
215         public void setMaxSize(final int maxSize) {
216             this.maxSize = maxSize;
217         }
218 
219         /***
220          * マップのエントリ数が最大数を超えている場合 <code>true</code> を返します。
221          * その結果、最も前にマップに挿入されたエントリがマップから削除されます。
222          * 
223          * @param eldest
224          *            もっとも前にマップに挿入されたエントリ
225          * @return マップのエントリ数が最大数を超えている場合 <code>true</code>
226          */
227         protected boolean removeEldestEntry(final Map.Entry eldest) {
228             return maxSize > 0 && size() > maxSize;
229         }
230     }
231 }