1 package fr.in2p3.jsaga.impl.url;
2
3 import fr.in2p3.jsaga.adaptor.data.read.FileAttributes;
4 import fr.in2p3.jsaga.helpers.URLEncoder;
5 import fr.in2p3.jsaga.impl.AbstractSagaObjectImpl;
6 import org.ogf.saga.SagaObject;
7 import org.ogf.saga.error.BadParameterException;
8 import org.ogf.saga.error.NoSuccessException;
9 import org.ogf.saga.session.Session;
10 import org.ogf.saga.url.URL;
11
12 import java.net.URI;
13 import java.net.URISyntaxException;
14
15
16
17
18
19
20
21
22
23
24
25
26
27 public class URLImpl extends AbstractSagaObjectImpl implements URL {
28 private URI u;
29 private FileAttributes m_cache;
30 private boolean m_mustRemoveSlash;
31
32
33 URLImpl(String url, boolean encode) throws BadParameterException {
34 if (encode) {
35 if (url.startsWith("file://")) {
36 url = URLEncoder.encodePathOnly(url);
37 } else {
38 url = URLEncoder.encode(url);
39 }
40 }
41 try {
42 while (url.startsWith("//")) {
43 url = url.substring(1);
44 }
45 u = new URI(url);
46 this.fixFileURI();
47 } catch(URISyntaxException e) {
48 throw new BadParameterException("syntax error in url", e);
49 }
50 }
51
52
53 URLImpl(String relativePath) throws BadParameterException {
54 int colonPos = relativePath.indexOf(':');
55 int slashPos = relativePath.indexOf('/');
56 m_mustRemoveSlash = colonPos > -1 && (slashPos == -1 || colonPos < slashPos);
57 if (m_mustRemoveSlash) {
58 relativePath = URLEncoder.encodePathOnly("/"+relativePath);
59 } else {
60 relativePath = URLEncoder.encodePathOnly(relativePath);
61 }
62 try {
63 u = new URI(relativePath);
64 } catch (URISyntaxException e) {
65 throw new BadParameterException("syntax error in url", e);
66 }
67 }
68
69
70 URLImpl(FileAttributes cache) throws BadParameterException {
71 this(cache.getRelativePath());
72 m_cache = cache;
73 }
74
75
76 URLImpl(URL base, String relativePath) {
77 this( base,
78 URLEncoder.encodePathOnly(relativePath),
79 null,
80 null
81 );
82 }
83
84
85 URLImpl(URL base, URL relativeUrl) {
86 this( base,
87 URLEncoder.encodePathOnly(relativeUrl.getPath()),
88 relativeUrl.getQuery()!=null ? relativeUrl.getQuery() : base.getQuery(),
89 relativeUrl.getFragment()!=null ? relativeUrl.getFragment() : base.getFragment()
90 );
91 }
92
93
94 private URLImpl(URL base, String relativePath, String query, String fragment) {
95
96 if (isWindowsAbsolutePath(base.getScheme(), relativePath)) {
97 relativePath = "/"+relativePath;
98 }
99
100
101 if (relativePath.startsWith("//")) {
102 int i;for(i=0; i<relativePath.length() && relativePath.charAt(i)=='/'; i++);
103 if(i>1)relativePath="/"+relativePath.substring(i);
104 }
105
106
107 if (! relativePath.startsWith("/")) {
108 relativePath = "./"+relativePath;
109 }
110
111
112 URI baseUri = ((URLImpl) base).u;
113 String relativeUri = relativePath
114 + concatIfNotNull('?', new String[]{query, baseUri.getQuery()})
115 + concatIfNotNull('#', new String[]{fragment, baseUri.getFragment()});
116 u = baseUri.resolve(relativeUri);
117 }
118
119
120 private URLImpl(URI u) {
121 this.u = u;
122 }
123
124
125 public SagaObject clone() throws CloneNotSupportedException {
126 URLImpl clone = (URLImpl) super.clone();
127 clone.u = u;
128 clone.m_cache = m_cache;
129 clone.m_mustRemoveSlash = m_mustRemoveSlash;
130 return clone;
131 }
132
133
134 public void setString(String url) throws BadParameterException {
135 if (url == null) {
136 url = "";
137 }
138 String encodedUrl = (url.startsWith("file://"))
139 ? URLEncoder.encodePathOnly(url)
140 : URLEncoder.encode(url);
141 try {
142 u = new URI(encodedUrl);
143 this.fixFileURI();
144 } catch(URISyntaxException e) {
145 throw new BadParameterException("syntax error in url", e);
146 }
147 }
148 public void setString() throws BadParameterException {
149 this.setString(null);
150 }
151
152
153 public String getString() {
154 return URLEncoder.decode(u, m_mustRemoveSlash);
155 }
156
157 public String getEscaped() {
158 return u.toString();
159 }
160
161 public String toString() {
162 return u.toString();
163 }
164
165 public String getFragment() {
166 return u.getFragment();
167 }
168
169 public void setFragment(String fragment) throws BadParameterException {
170 try {
171 u = new URI(u.getScheme(), u.getUserInfo(), u.getHost(),
172 u.getPort(), u.getPath(), u.getQuery(), fragment);
173 } catch(URISyntaxException e) {
174 throw new BadParameterException("syntax error in fragment", e);
175 }
176 }
177 public void setFragment() throws BadParameterException {
178 this.setFragment(null);
179 }
180
181 public String getHost() {
182 if (u.getHost() == null) {
183 return this.getSchemeSpecificPart().getHost();
184 }
185 return u.getHost();
186 }
187
188 public void setHost(String host) throws BadParameterException {
189 try {
190 u = new URI(u.getScheme(), u.getUserInfo(), host,
191 u.getPort(), u.getPath(), u.getQuery(), u.getFragment());
192 } catch(URISyntaxException e) {
193 throw new BadParameterException("syntax error in host", e);
194 }
195 }
196 public void setHost() throws BadParameterException {
197 this.setHost(null);
198 }
199
200 public String getPath() {
201 if (u.getPath() == null) {
202 return this.getSchemeSpecificPart().getPath();
203 } else if (".".equals(u.getAuthority())) {
204 return "."+u.getPath();
205 } else if (u.getPath().startsWith("/./") || m_mustRemoveSlash) {
206 return u.getPath().substring(1);
207 } else if (u.getPath().startsWith("//")) {
208 return trimPath(u.getPath());
209 }
210 return u.getPath();
211 }
212 private static String trimPath(String path) {
213 if (path.startsWith("//")) {
214 return trimPath(path.substring(1));
215 } else {
216 return path;
217 }
218 }
219
220 public void setPath(String path) throws BadParameterException {
221 if (path == null) {
222 path = "";
223 }
224 try {
225 if (path.startsWith("./")) {
226
227 u = new URI(u.getScheme(), u.getAuthority(),
228 path.substring(2), u.getQuery(), u.getFragment());
229 } else {
230
231 int i;for(i=0; i<path.length() && path.charAt(i)=='/'; i++);
232 if(i>1)path="/"+path.substring(i);
233 if (path == "" && u.getRawAuthority() == null)
234 throw new BadParameterException("Path cannot by empty if authority is empty");
235 u = new URI(u.getScheme(), u.getUserInfo(), u.getHost(),
236 u.getPort(), path, u.getQuery(), u.getFragment());
237 }
238 } catch(URISyntaxException e) {
239 throw new BadParameterException("syntax error in path", e);
240 }
241 }
242 public void setPath() throws BadParameterException {
243 this.setPath(null);
244 }
245
246 public int getPort() {
247 if (u.getPort() == -1) {
248 return this.getSchemeSpecificPart().getPort();
249 }
250 return u.getPort();
251 }
252
253 public void setPort(int port) throws BadParameterException {
254 try {
255 u = new URI(u.getScheme(), u.getUserInfo(), u.getHost(),
256 port, u.getPath(), u.getQuery(), u.getFragment());
257 } catch(URISyntaxException e) {
258 throw new BadParameterException("syntax error in port", e);
259 }
260 }
261 public void setPort() throws BadParameterException {
262 this.setPort(-1);
263 }
264
265 public String getQuery() {
266 if (u.getQuery() == null) {
267 return this.getSchemeSpecificPart().getQuery();
268 }
269 return u.getQuery();
270 }
271
272 public void setQuery(String query) throws BadParameterException {
273 try {
274 u = new URI(u.getScheme(), u.getUserInfo(), u.getHost(),
275 u.getPort(), u.getPath(), query, u.getFragment());
276 } catch(URISyntaxException e) {
277 throw new BadParameterException("syntax error in query", e);
278 }
279 }
280 public void setQuery() throws BadParameterException {
281 this.setQuery(null);
282 }
283
284 public String getScheme() {
285 return u.getScheme();
286 }
287
288 public void setScheme(String scheme) throws BadParameterException {
289 try {
290 u = new URI(scheme, u.getUserInfo(), u.getHost(),
291 u.getPort(), u.getPath(), u.getQuery(), u.getFragment());
292 } catch(URISyntaxException e) {
293 throw new BadParameterException("syntax error in scheme", e);
294 }
295 }
296 public void setScheme() throws BadParameterException {
297 this.setScheme(null);
298 }
299
300 public String getUserInfo() {
301 if (u.getUserInfo() == null) {
302 return this.getSchemeSpecificPart().getUserInfo();
303 }
304 return u.getUserInfo();
305 }
306
307 public void setUserInfo(String userInfo) throws BadParameterException {
308 try {
309 u = new URI(u.getScheme(), userInfo, u.getHost(),
310 u.getPort(), u.getPath(), u.getQuery(), u.getFragment());
311 } catch(URISyntaxException e) {
312 throw new BadParameterException("syntax error in query", e);
313 }
314 }
315 public void setUserInfo() throws BadParameterException {
316 this.setUserInfo(null);
317 }
318
319 public URL translate(String scheme) throws BadParameterException, NoSuccessException {
320 try {
321 URI url = new URI(scheme, u.getUserInfo(), u.getHost(),
322 u.getPort(), u.getPath(), u.getQuery(), u.getFragment());
323
324
325
326 return new URLImpl(url);
327 } catch(URISyntaxException e) {
328 throw new BadParameterException("syntax error in scheme", e);
329 }
330 }
331 public URL translate(Session session, String scheme) throws BadParameterException, NoSuccessException {
332 return this.translate(scheme);
333 }
334
335 public URL resolve(URL url) throws NoSuccessException {
336 URLImpl urlimpl = (URLImpl) url;
337 URI uri = u.resolve(urlimpl.u);
338 if (uri == urlimpl.u) {
339 return url;
340 }
341 return new URLImpl(uri);
342 }
343
344 public boolean isAbsolute() {
345 return u.isAbsolute();
346 }
347
348 public URL normalize() {
349 URI uri = u.normalize();
350 if (uri == u) {
351 return this;
352 }
353 return new URLImpl(uri);
354 }
355
356
357
358 public int hashCode() {
359 return u.hashCode();
360 }
361
362 public boolean equals(Object o) {
363 if (o == null) {
364 return false;
365 }
366 if (! (o instanceof URLImpl)) {
367 return false;
368 }
369 URLImpl other = (URLImpl) o;
370 return u.equals(other.u);
371 }
372
373
374
375 public void setCache(FileAttributes cache) {
376 m_cache = cache;
377 }
378
379 public FileAttributes getCache() {
380 return m_cache;
381 }
382
383 public boolean hasCache() {
384 return (m_cache != null);
385 }
386
387
388
389 private boolean isWindowsAbsolutePath(String scheme, String relativePath) {
390 return ("file".equals(scheme) || "zip".equals(scheme))
391 && System.getProperty("os.name").startsWith("Windows")
392 && relativePath.length()>=2 && Character.isLetter(relativePath.charAt(0)) && relativePath.charAt(1)==':'
393 && (relativePath.length()==2 || (relativePath.length()>2 && relativePath.charAt(2)=='/'));
394 }
395
396 private void fixFileURI() throws URISyntaxException {
397 boolean isRelative = (u.getHost()==null && u.getAuthority()!=null && !u.getAuthority().equals("."));
398 boolean isWindows = (u.getHost()!=null && u.getHost().length()==1 && u.getAuthority()!=null && u.getAuthority().endsWith(":"));
399 if (isRelative || isWindows) {
400 u = new URI(u.getScheme(), u.getUserInfo(),
401 "",
402 u.getPort(),
403 "/"+u.getAuthority()+u.getPath(),
404 u.getQuery(), u.getFragment());
405 }
406 }
407
408 private URI getSchemeSpecificPart() {
409 try {
410 return new URI(u.getRawSchemeSpecificPart());
411 } catch (URISyntaxException e) {
412 return u;
413 }
414 }
415
416 private static String concatIfNotNull(char prefix, String[] suffix) {
417 for (int i=0; suffix!=null && i<suffix.length; i++) {
418 if (suffix[i] != null) {
419 return prefix + suffix[i];
420 }
421 }
422 return "";
423 }
424 }