View Javadoc

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