View Javadoc

1   /*
2    * Copyright 2004-2010 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  
17  package org.seasar.cubby.util;
18  
19  import java.io.Serializable;
20  import java.net.MalformedURLException;
21  import java.net.URL;
22  
23  import javax.servlet.http.HttpServletRequest;
24  
25  /**
26   * 要求の URL をベースとしたリンク文字列を構築します。
27   * 
28   * @author baba
29   */
30  public class LinkBuilder implements Serializable {
31  
32  	/** シリアルバージョン UID。 */
33  	private static final long serialVersionUID = 1L;
34  
35  	/** プロトコル。 */
36  	private String protocol;
37  
38  	/** ホスト名。 */
39  	private String host;
40  
41  	/** ホスト上でのポート番号。 */
42  	private Integer port;
43  
44  	/** ホスト上のファイル。 */
45  	private String file;
46  
47  	/**
48  	 * URL ビルダオブジェクトを生成します。
49  	 */
50  	public LinkBuilder() {
51  		this.clear();
52  	}
53  
54  	/**
55  	 * このインスタンスをクリアします。
56  	 */
57  	public void clear() {
58  		this.protocol = null;
59  		this.host = null;
60  		this.port = null;
61  		this.file = null;
62  	}
63  
64  	/**
65  	 * プロトコルを取得します。
66  	 * 
67  	 * @return プロトコル
68  	 */
69  	public String getProtocol() {
70  		return protocol;
71  	}
72  
73  	/**
74  	 * プロトコルを設定します。
75  	 * 
76  	 * @param protocol
77  	 *            プロトコル
78  	 * @throws NullPointerException
79  	 *             指定された <code>protocol</code> が <code>null</code> の場合
80  	 */
81  	public void setProtocol(final String protocol) {
82  		if (protocol == null) {
83  			throw new NullPointerException("No protocol");
84  		}
85  		this.protocol = protocol;
86  	}
87  
88  	/**
89  	 * ホスト名を取得します。
90  	 * 
91  	 * @return ホスト名
92  	 */
93  	public String getHost() {
94  		return host;
95  	}
96  
97  	/**
98  	 * ホスト名を設定します。
99  	 * 
100 	 * @param host
101 	 *            ホスト名
102 	 * @throws NullPointerException
103 	 *             指定された <code>host</code> が <code>null</code> の場合
104 	 */
105 	public void setHost(final String host) {
106 		if (host == null) {
107 			throw new NullPointerException("No host");
108 		}
109 		this.host = host;
110 	}
111 
112 	/**
113 	 * ホスト上のポート番号を取得します。
114 	 * 
115 	 * @return ホスト上のポート番号
116 	 */
117 	public int getPort() {
118 		return port;
119 	}
120 
121 	/**
122 	 * ホスト上のポート番号を設定します。
123 	 * <p>
124 	 * <code>port</code> に -1 を指定した場合は、プロトコルのデフォルトポートを使用します。
125 	 * </p>
126 	 * 
127 	 * @param port
128 	 *            ホスト上のポート番号
129 	 */
130 	public void setPort(final int port) {
131 		this.port = port;
132 	}
133 
134 	/**
135 	 * ホスト上のファイルを取得します。
136 	 * 
137 	 * @return ホスト上のファイル
138 	 */
139 	public String getFile() {
140 		return file;
141 	}
142 
143 	/**
144 	 * ホスト上のファイルを設定します。
145 	 * 
146 	 * @param file
147 	 *            ホスト上のファイル
148 	 */
149 	public void setFile(final String file) {
150 		this.file = file;
151 	}
152 
153 	/**
154 	 * このリンクの文字列表現を構築します。
155 	 * <p>
156 	 * 指定された要求とこのオブジェクトに指定されたプロトコル、ホスト名、ホスト上のポート番号が同じ場合は相対パスであるとみなして内部形式
157 	 * のリンク文字列を、そうでない場合は外部形式のリンク文字列を構築します。
158 	 * </p>
159 	 * 
160 	 * @param request
161 	 *            要求
162 	 * @return URL の文字列表現
163 	 * @throws MalformedURLException
164 	 *             未知のプロトコルとして指定された場合
165 	 */
166 	public String toLink(final HttpServletRequest request)
167 			throws MalformedURLException {
168 		final URL requestURL = new URL(request.getRequestURL().toString());
169 		final String newProtocol = getNewProtocol(requestURL.getProtocol());
170 		final String newHost = getNewHost(requestURL.getHost());
171 		final int newPort = getNewPort(requestURL.getPort());
172 		final String newFile = getNewFile(requestURL.getFile());
173 		final URL newURL = correctDefaultPort(new URL(newProtocol, newHost,
174 				newPort, newFile));
175 		if (isRelativeLink(requestURL, newURL)) {
176 			return newURL.getFile();
177 		} else {
178 			return newURL.toExternalForm();
179 		}
180 	}
181 
182 	/**
183 	 * 指定された URL に設定されたポートが、プロトコルのデフォルトポートだった場合はポートに -1 を指定した URL を返します。
184 	 * 
185 	 * @param url
186 	 *            URL
187 	 * @return URL
188 	 * @throws MalformedURLException
189 	 *             未知のプロトコルとして指定された場合
190 	 */
191 	private URL correctDefaultPort(URL url) throws MalformedURLException {
192 		if (url.getPort() == url.getDefaultPort()) {
193 			final URL correctedURL = new URL(url.getProtocol(), url.getHost(),
194 					-1, url.getFile());
195 			return correctedURL;
196 		}
197 		return url;
198 	}
199 
200 	/**
201 	 * 指定された 2 つの URL を比較して、相対パス形式の URL 文字列を生成するかどうかを示します。
202 	 * 
203 	 * @param url1
204 	 *            URL1
205 	 * @param url2
206 	 *            URL2
207 	 * @return 相対パス形式の URL 文字列を生成する場合は <code>true</code>、そうでない場合は
208 	 *         <code>false</code>
209 	 */
210 	private boolean isRelativeLink(final URL url1, final URL url2) {
211 		if (!url1.getProtocol().equals(url2.getProtocol())) {
212 			return false;
213 		}
214 		if (!url1.getHost().equals(url2.getHost())) {
215 			return false;
216 		}
217 		if (url1.getPort() != url2.getPort()) {
218 			return false;
219 		}
220 		return true;
221 	}
222 
223 	/**
224 	 * 新しい URL のプロトコルを返します。
225 	 * 
226 	 * @param requestProtocol
227 	 *            要求のプロトコル
228 	 * @return 新しい URL のプロトコル
229 	 */
230 	private String getNewProtocol(final String requestProtocol) {
231 		if (this.protocol == null) {
232 			return requestProtocol;
233 		} else {
234 			return this.protocol;
235 		}
236 	}
237 
238 	/**
239 	 * 新しい URL のホスト名を返します。
240 	 * 
241 	 * @param requestHost
242 	 *            要求のホスト名
243 	 * @return 新しい URL のホスト名
244 	 */
245 	private String getNewHost(final String requestHost) {
246 		if (this.host == null) {
247 			return requestHost;
248 		} else {
249 			return this.host;
250 		}
251 	}
252 
253 	/**
254 	 * 新しい URL のホスト上のポート番号
255 	 * 
256 	 * @param requestPort
257 	 *            要求のホスト上のポート番号
258 	 * @return 新しい URL のホスト上のポート番号
259 	 */
260 	private int getNewPort(final int requestPort) {
261 		if (this.port == null) {
262 			return requestPort;
263 		} else {
264 			return this.port;
265 		}
266 	}
267 
268 	/**
269 	 * 新しい URL のホスト上のファイル
270 	 * 
271 	 * @param requestPort
272 	 *            要求のホスト上のファイル
273 	 * @return 新しい URL のホスト上のファイル
274 	 */
275 	private String getNewFile(final String currentFile) {
276 		if (this.file == null) {
277 			return currentFile;
278 		} else {
279 			return this.file;
280 		}
281 	}
282 
283 	/**
284 	 * プロトコルを設定します。
285 	 * 
286 	 * @param protocol
287 	 *            プロトコル
288 	 * @return このオブジェクト
289 	 */
290 	public LinkBuilder protocol(final String protocol) {
291 		this.setProtocol(protocol);
292 		return this;
293 	}
294 
295 	/**
296 	 * ホスト名を設定します。
297 	 * 
298 	 * @param host
299 	 *            ホスト名
300 	 * @return このオブジェクト
301 	 */
302 	public LinkBuilder host(final String host) {
303 		this.setHost(host);
304 		return this;
305 	}
306 
307 	/**
308 	 * ホスト上のポート場号を設定します。
309 	 * 
310 	 * @param port
311 	 *            ホスト上のポート場号
312 	 * @return このオブジェクト
313 	 */
314 	public LinkBuilder port(final int port) {
315 		this.setPort(port);
316 		return this;
317 	}
318 
319 	/**
320 	 * ホスト上のファイルを設定します。
321 	 * 
322 	 * @param file
323 	 *            ホスト上のファイル
324 	 * @return このオブジェクト
325 	 */
326 	public LinkBuilder file(final String file) {
327 		this.setFile(file);
328 		return this;
329 	}
330 
331 	/**
332 	 * {@inheritDoc}
333 	 */
334 	@Override
335 	public String toString() {
336 		final StringBuilder builder = new StringBuilder();
337 		builder.append(this);
338 		builder.append(" [host=");
339 		builder.append(host);
340 		builder.append(",protocol=");
341 		builder.append(protocol);
342 		builder.append(",port=");
343 		builder.append(port);
344 		builder.append(",file=");
345 		builder.append(file);
346 		builder.append("]");
347 		return builder.toString();
348 	}
349 
350 }