1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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 }