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   * @since 1.1.4
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 int 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 = -1;
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 	 * 
124 	 * @param port
125 	 *            ホスト上のポート番号
126 	 * @throws IllegalArgumentException
127 	 *             ポート番号が負の値の場合
128 	 */
129 	public void setPort(final int port) {
130 		if (port < 0) {
131 			throw new IllegalArgumentException("Invalid port number :" + port);
132 		}
133 		this.port = port;
134 	}
135 
136 	/**
137 	 * ホスト上のファイルを取得します。
138 	 * 
139 	 * @return ホスト上のファイル
140 	 */
141 	public String getFile() {
142 		return file;
143 	}
144 
145 	/**
146 	 * ホスト上のファイルを設定します。
147 	 * 
148 	 * @param file
149 	 *            ホスト上のファイル
150 	 */
151 	public void setFile(final String file) {
152 		this.file = file;
153 	}
154 
155 	/**
156 	 * このリンクの文字列表現を構築します。
157 	 * <p>
158 	 * 指定された要求とこのオブジェクトに指定されたプロトコル、ホスト名、ホスト上のポート番号が同じ場合は相対パスであるとみなして内部形式
159 	 * のリンク文字列を、そうでない場合は外部形式のリンク文字列を構築します。
160 	 * </p>
161 	 * 
162 	 * @param request
163 	 *            要求
164 	 * @return URL の文字列表現
165 	 * @throws MalformedURLException
166 	 *             未知のプロトコルとして指定された場合
167 	 */
168 	public String toLink(final HttpServletRequest request)
169 			throws MalformedURLException {
170 		final URL requestURL = new URL(request.getRequestURL().toString());
171 		final URL newURL = new URL(getNewProtocol(requestURL.getProtocol()),
172 				getNewHost(requestURL.getHost()), getNewPort(requestURL
173 						.getPort()), getNewFile(requestURL.getFile()));
174 		if (isRelativeLink(requestURL, newURL)) {
175 			return newURL.getFile();
176 		} else {
177 			return newURL.toExternalForm();
178 		}
179 	}
180 
181 	/**
182 	 * 指定された 2 つの URL を比較して、相対パス形式の URL 文字列を生成するかどうかを示します。
183 	 * 
184 	 * @param url1
185 	 *            URL1
186 	 * @param url2
187 	 *            URL2
188 	 * @return 相対パス形式の URL 文字列を生成する場合は <code>true</code>、そうでない場合は
189 	 *         <code>false</code>
190 	 */
191 	private boolean isRelativeLink(final URL url1, final URL url2) {
192 		if (!url1.getProtocol().equals(url2.getProtocol())) {
193 			return false;
194 		}
195 		if (!url1.getHost().equals(url2.getHost())) {
196 			return false;
197 		}
198 		if (url1.getPort() != url2.getPort()) {
199 			return false;
200 		}
201 		return true;
202 	}
203 
204 	/**
205 	 * 新しい URL のプロトコルを返します。
206 	 * 
207 	 * @param requestProtocol
208 	 *            要求のプロトコル
209 	 * @return 新しい URL のプロトコル
210 	 */
211 	private String getNewProtocol(final String requestProtocol) {
212 		if (this.protocol == null) {
213 			return requestProtocol;
214 		} else {
215 			return this.protocol;
216 		}
217 	}
218 
219 	/**
220 	 * 新しい URL のホスト名を返します。
221 	 * 
222 	 * @param requestHost
223 	 *            要求のホスト名
224 	 * @return 新しい URL のホスト名
225 	 */
226 	private String getNewHost(final String requestHost) {
227 		if (this.host == null) {
228 			return requestHost;
229 		} else {
230 			return this.host;
231 		}
232 	}
233 
234 	/**
235 	 * 新しい URL のホスト上のポート番号
236 	 * 
237 	 * @param requestPort
238 	 *            要求のホスト上のポート番号
239 	 * @return 新しい URL のホスト上のポート番号
240 	 */
241 	private int getNewPort(final int requestPort) {
242 		if (this.port < 0) {
243 			return requestPort;
244 		} else {
245 			return this.port;
246 		}
247 	}
248 
249 	/**
250 	 * 新しい URL のホスト上のファイル
251 	 * 
252 	 * @param requestPort
253 	 *            要求のホスト上のファイル
254 	 * @return 新しい URL のホスト上のファイル
255 	 */
256 	private String getNewFile(final String currentFile) {
257 		if (this.file == null) {
258 			return currentFile;
259 		} else {
260 			return this.file;
261 		}
262 	}
263 
264 	/**
265 	 * プロトコルを設定します。
266 	 * 
267 	 * @param protocol
268 	 *            プロトコル
269 	 * @return このオブジェクト
270 	 */
271 	public LinkBuilder protocol(final String protocol) {
272 		this.setProtocol(protocol);
273 		return this;
274 	}
275 
276 	/**
277 	 * ホスト名を設定します。
278 	 * 
279 	 * @param host
280 	 *            ホスト名
281 	 * @return このオブジェクト
282 	 */
283 	public LinkBuilder host(final String host) {
284 		this.setHost(host);
285 		return this;
286 	}
287 
288 	/**
289 	 * ホスト上のポート場号を設定します。
290 	 * 
291 	 * @param port
292 	 *            ホスト上のポート場号
293 	 * @return このオブジェクト
294 	 */
295 	public LinkBuilder port(final int port) {
296 		this.setPort(port);
297 		return this;
298 	}
299 
300 	/**
301 	 * ホスト上のファイルを設定します。
302 	 * 
303 	 * @param file
304 	 *            ホスト上のファイル
305 	 * @return このオブジェクト
306 	 */
307 	public LinkBuilder file(final String file) {
308 		this.setFile(file);
309 		return this;
310 	}
311 
312 	/**
313 	 * {@inheritDoc}
314 	 */
315 	@Override
316 	public String toString() {
317 		final StringBuilder builder = new StringBuilder();
318 		builder.append(this);
319 		builder.append(" [host=");
320 		builder.append(host);
321 		builder.append(",protocol=");
322 		builder.append(protocol);
323 		builder.append(",port=");
324 		builder.append(port);
325 		builder.append(",file=");
326 		builder.append(file);
327 		builder.append("]");
328 		return builder.toString();
329 	}
330 
331 }