KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > server > hmux > HmuxPath


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.server.hmux;
31
32 import com.caucho.util.Alarm;
33 import com.caucho.util.CharBuffer;
34 import com.caucho.util.L10N;
35 import com.caucho.util.LruCache;
36 import com.caucho.util.QDate;
37 import com.caucho.vfs.FilesystemPath;
38 import com.caucho.vfs.Path;
39 import com.caucho.vfs.ReadStream;
40 import com.caucho.vfs.StreamImpl;
41 import com.caucho.vfs.WriteStream;
42 import com.caucho.xml.XmlParser;
43
44 import org.xml.sax.Attributes JavaDoc;
45 import org.xml.sax.SAXException JavaDoc;
46
47 import java.io.IOException JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.Map JavaDoc;
50
51 /**
52  * The HTTP scheme. Currently it supports GET and POST.
53  *
54  * <p>TODO: support WEBDAV, enabling the full Path API.
55  */

56 public class HmuxPath extends FilesystemPath {
57   protected static L10N L = new L10N(HmuxPath.class);
58
59   protected static LruCache<String JavaDoc,CacheEntry> _cache =
60     new LruCache<String JavaDoc,CacheEntry>(1024);
61   
62   protected String JavaDoc _host;
63   protected int _port;
64   protected String JavaDoc _query;
65
66   protected String JavaDoc _virtualHost;
67
68   protected CacheEntry _cacheEntry;
69
70   /**
71    * Creates a new HTTP root path with a host and a port.
72    *
73    * @param host the target host
74    * @param port the target port, if zero, uses port 80.
75    */

76   public HmuxPath(String JavaDoc host, int port)
77   {
78     super(null, "/", "/");
79
80     _root = this;
81     _host = host;
82     _port = port == 0 ? 80 : port;
83   }
84
85   /**
86    * Creates a new HTTP sub path.
87    *
88    * @param root the HTTP filesystem root
89    * @param userPath the argument to the calling lookup()
90    * @param newAttributes any attributes passed to http
91    * @param path the full normalized path
92    * @param query any query string
93    */

94   HmuxPath(FilesystemPath root,
95            String JavaDoc userPath, Map JavaDoc<String JavaDoc,Object JavaDoc> newAttributes,
96        String JavaDoc path, String JavaDoc query)
97   {
98     super(root, userPath, path);
99
100     _host = ((HmuxPath) root)._host;
101     _port = ((HmuxPath) root)._port;
102     _query = query;
103
104     if (newAttributes != null) {
105       _virtualHost = (String JavaDoc) newAttributes.get("host");
106     }
107   }
108
109   /**
110    * Overrides the default lookup to parse the host and port
111    * before parsing the path.
112    *
113    * @param userPath the path passed in by the user
114    * @param newAttributes attributes passed by the user
115    *
116    * @return the final path.
117    */

118   public Path lookupImpl(String JavaDoc userPath, Map JavaDoc<String JavaDoc,Object JavaDoc> newAttributes)
119   {
120     String JavaDoc newPath;
121
122     if (userPath == null)
123       return _root.fsWalk(getPath(), newAttributes, "/");
124
125     int length = userPath.length();
126     int colon = userPath.indexOf(':');
127     int slash = userPath.indexOf('/');
128
129     // parent handles scheme:xxx
130
if (colon != -1 && (colon < slash || slash == -1))
131       return super.lookupImpl(userPath, newAttributes);
132       
133       // //hostname
134
if (slash == 0 && length > 1 && userPath.charAt(1) == '/')
135       return schemeWalk(userPath, newAttributes, userPath, 0);
136
137       // /path
138
else if (slash == 0)
139       newPath = normalizePath("/", userPath, 0, '/');
140
141       // path
142
else
143       newPath = normalizePath(_pathname, userPath, 0, '/');
144
145     // XXX: does missing root here cause problems with restrictions?
146
return _root.fsWalk(userPath, newAttributes, newPath);
147   }
148
149   /**
150    * Walk down the path starting from the portion immediately following
151    * the scheme. i.e. schemeWalk is responsible for parsing the host and
152    * port from the URL.
153    *
154    * @param userPath the user's passed in path
155    * @param attributes the attributes for the new path
156    * @param uri the normalized full uri
157    * @param offset offset into the uri to start processing, i.e. after the
158    * scheme.
159    *
160    * @return the looked-up path.
161    */

162   protected Path schemeWalk(String JavaDoc userPath,
163                             Map JavaDoc<String JavaDoc,Object JavaDoc> attributes,
164                 String JavaDoc uri,
165                             int offset)
166   {
167     int length = uri.length();
168
169     if (length < 2 + offset ||
170         uri.charAt(offset) != '/' ||
171         uri.charAt(offset + 1) != '/')
172       throw new RuntimeException JavaDoc(L.l("bad scheme in `{0}'", uri));
173
174     CharBuffer buf = CharBuffer.allocate();
175     int i = 2 + offset;
176     int ch = 0;
177     for (; i < length && (ch = uri.charAt(i)) != ':' && ch != '/' && ch != '?';
178      i++) {
179       buf.append((char) ch);
180     }
181
182     String JavaDoc host = buf.close();
183     if (host.length() == 0)
184       throw new RuntimeException JavaDoc(L.l("bad host in `{0}'", uri));
185
186     int port = 0;
187     if (ch == ':') {
188       for (i++; i < length && (ch = uri.charAt(i)) >= '0' && ch <= '9'; i++) {
189     port = 10 * port + uri.charAt(i) - '0';
190       }
191     }
192
193     if (port == 0)
194       port = 80;
195
196     HmuxPath root = create(host, port);
197
198     return root.fsWalk(userPath, attributes, uri.substring(i));
199   }
200
201   /**
202    * Scans the path portion of the URI, i.e. everything after the
203    * host and port.
204    *
205    * @param userPath the user's supplied path
206    * @param attributes the attributes for the new path
207    * @param uri the full uri for the new path.
208    *
209    * @return the found path.
210    */

211   public Path fsWalk(String JavaDoc userPath,
212             Map JavaDoc<String JavaDoc,Object JavaDoc> attributes,
213             String JavaDoc uri)
214   {
215     String JavaDoc path;
216     String JavaDoc query = null;
217     int queryIndex = uri.indexOf('?');
218     if (queryIndex >= 0) {
219       path = uri.substring(0, queryIndex);
220       query = uri.substring(queryIndex + 1);
221     } else
222       path = uri;
223
224     if (path.length() == 0)
225       path = "/";
226
227     return create(_root, userPath, attributes, path, query);
228   }
229
230   protected HmuxPath create(String JavaDoc host, int port)
231   {
232     return new HmuxPath(host, port);
233   }
234
235   protected HmuxPath create(FilesystemPath root,
236                             String JavaDoc userPath,
237                 Map JavaDoc<String JavaDoc,Object JavaDoc> newAttributes,
238                             String JavaDoc path, String JavaDoc query)
239   {
240     return new HmuxPath(root, userPath, newAttributes, path, query);
241   }
242
243   /**
244    * Returns the scheme, http.
245    */

246   public String JavaDoc getScheme()
247   {
248     return "http";
249   }
250
251   /**
252    * Returns a full URL for the path.
253    */

254   public String JavaDoc getURL()
255   {
256     int port = getPort();
257
258     return (getScheme() + "://" + getHost() +
259         (port == 80 ? "" : ":" + getPort()) +
260         getPath() +
261         (_query == null ? "" : "?" + _query));
262   }
263
264   /**
265    * Returns the host part of the url.
266    */

267   public String JavaDoc getHost()
268   {
269     return _host;
270   }
271
272   /**
273    * Returns the port part of the url.
274    */

275   public int getPort()
276   {
277     return _port;
278   }
279
280   /**
281    * Returns the user's path.
282    */

283   public String JavaDoc getUserPath()
284   {
285     return _userPath;
286   }
287
288   /**
289    * Returns the virtual host, if any.
290    */

291   public String JavaDoc getVirtualHost()
292   {
293     return _virtualHost;
294   }
295
296   /**
297    * Returns the query string.
298    */

299   public String JavaDoc getQuery()
300   {
301     return _query;
302   }
303
304   /**
305    * Returns the last modified time.
306    */

307   public long getLastModified()
308   {
309     return getCache().lastModified;
310   }
311
312   /**
313    * Returns the file's length
314    */

315   public long getLength()
316   {
317     return getCache().length;
318   }
319
320   /**
321    * Returns true if the file exists.
322    */

323   public boolean exists()
324   {
325     return getCache().lastModified >= 0;
326   }
327
328   /**
329    * Returns true if the file exists.
330    */

331   public boolean isFile()
332   {
333     return ! getPath().endsWith("/") && getCache().lastModified >= 0;
334   }
335
336   /**
337    * Returns true if the file is readable.
338    */

339   public boolean canRead()
340   {
341     return isFile();
342   }
343
344   /**
345    * Returns the last modified time.
346    */

347   public boolean isDirectory()
348   {
349     return getPath().endsWith("/") && getCache().lastModified >= 0;
350   }
351   
352   /**
353    * @return The contents of this directory or null if the path does not
354    * refer to a directory.
355    */

356   public String JavaDoc []list() throws IOException JavaDoc
357   {
358     try {
359       HmuxStream stream = (HmuxStream) openReadWriteImpl();
360       stream.setMethod("PROPFIND");
361       stream.setAttribute("Depth", "1");
362
363       WriteStream os = new WriteStream(stream);
364       os.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
365       os.println("<propfind xmlns=\"DAV:\"><prop>");
366       os.println("<resourcetype/>");
367       os.println("</prop></propfind>");
368       os.flush();
369
370       ReadStream is = new ReadStream(stream);
371     
372       ListHandler handler = new ListHandler(getPath());
373       XmlParser parser = new XmlParser();
374       parser.setContentHandler(handler);
375
376       parser.parse(is);
377
378       is.close();
379       os.close();
380       stream.close();
381
382       ArrayList JavaDoc<String JavaDoc> names = handler.getNames();
383       String JavaDoc []list = new String JavaDoc[names.size()];
384       names.toArray(list);
385       
386       return list;
387     } catch (Exception JavaDoc e) {
388       throw new IOException JavaDoc(L.l("list() is not supported by this server"));
389     }
390   }
391
392   protected CacheEntry getCache()
393   {
394     if (_cacheEntry == null) {
395       synchronized (_cache) {
396         _cacheEntry = _cache.get(getPath());
397         if (_cacheEntry == null) {
398           _cacheEntry = new CacheEntry();
399           _cache.put(getPath(), _cacheEntry);
400         }
401       }
402     }
403     
404     long now = Alarm.getCurrentTime();
405     synchronized (_cacheEntry) {
406       try {
407         if (_cacheEntry.expires > now)
408           return _cacheEntry;
409       
410         HmuxStreamWrapper stream = (HmuxStreamWrapper) openReadImpl();
411         stream.setHead(true);
412         stream.setSocketTimeout(120000);
413
414         String JavaDoc status = (String JavaDoc) stream.getAttribute("status");
415         if (status.equals("200")) {
416           String JavaDoc lastModified = (String JavaDoc) stream.getAttribute("last-modified");
417
418           _cacheEntry.lastModified = 0;
419           if (lastModified != null) {
420             QDate date = QDate.getGlobalDate();
421             synchronized (date) {
422               _cacheEntry.lastModified = date.parseDate(lastModified);
423             }
424           }
425
426           String JavaDoc length = (String JavaDoc) stream.getAttribute("content-length");
427           _cacheEntry.length = 0;
428           if (length != null) {
429             _cacheEntry.length = Integer.parseInt(length);
430           }
431         }
432         else
433           _cacheEntry.lastModified = -1;
434         
435         _cacheEntry.expires = now + 5000;
436       
437         stream.close();
438         return _cacheEntry;
439       } catch (Exception JavaDoc e) {
440         _cacheEntry.lastModified = -1;
441         _cacheEntry.expires = now + 5000;
442
443         return _cacheEntry;
444       }
445     }
446   }
447   
448
449   /**
450    * Returns a read stream for a GET request.
451    */

452   public StreamImpl openReadImpl() throws IOException JavaDoc
453   {
454     return HmuxStream.openRead(this);
455   }
456
457   /**
458    * Returns a read/write pair for a POST request.
459    */

460   public StreamImpl openReadWriteImpl() throws IOException JavaDoc
461   {
462     return HmuxStream.openReadWrite(this);
463   }
464
465   @Override JavaDoc
466   protected Path cacheCopy()
467   {
468     return new HmuxPath(getRoot(), getUserPath(),
469             null,
470             getPath(), _query);
471   }
472   
473   /**
474    * Returns the string form of the http path.
475    */

476   public String JavaDoc toString()
477   {
478     return getURL();
479   }
480
481   /**
482    * Returns a hashCode for the path.
483    */

484   public int hashCode()
485   {
486     return 65537 * super.hashCode() + 37 * _host.hashCode() + _port;
487   }
488
489   /**
490    * Overrides equals to test for equality with an HTTP path.
491    */

492   public boolean equals(Object JavaDoc o)
493   {
494     if (! (o instanceof HmuxPath))
495       return false;
496
497     HmuxPath test = (HmuxPath) o;
498
499     if (! _host.equals(test._host))
500       return false;
501     else if (_port != test._port)
502       return false;
503     else if (_query != null && ! _query.equals(test._query))
504       return false;
505     else if (_query == null && test._query != null)
506       return false;
507     else
508       return true;
509   }
510
511   static class CacheEntry {
512     long lastModified;
513     long length;
514     boolean canRead;
515     long expires;
516   }
517
518   static class ListHandler extends org.xml.sax.helpers.DefaultHandler JavaDoc {
519     String JavaDoc _prefix;
520     ArrayList JavaDoc<String JavaDoc> _names = new ArrayList JavaDoc<String JavaDoc>();
521     boolean _inHref;
522
523     ListHandler(String JavaDoc prefix)
524     {
525       _prefix = prefix;
526     }
527     
528     ArrayList JavaDoc<String JavaDoc> getNames()
529     {
530       return _names;
531     }
532
533     public void startElement (String JavaDoc uri, String JavaDoc localName,
534                   String JavaDoc qName, Attributes JavaDoc attributes)
535     {
536       if (localName.equals("href"))
537         _inHref = true;
538     }
539
540     public void characters(char []data, int offset, int length)
541     throws SAXException JavaDoc
542     {
543       if (! _inHref)
544         return;
545
546       String JavaDoc href = new String JavaDoc(data, offset, length).trim();
547       if (! href.startsWith(_prefix))
548         return;
549
550       href = href.substring(_prefix.length());
551       if (href.startsWith("/"))
552         href = href.substring(1);
553
554       int p = href.indexOf('/');
555       if (href.equals("") || p == 0)
556         return;
557
558       if (p < 0)
559         _names.add(href);
560       else
561         _names.add(href.substring(0, p));
562     }
563
564     public void endElement (String JavaDoc uri, String JavaDoc localName, String JavaDoc qName)
565     throws SAXException JavaDoc
566     {
567       if (localName.equals("href"))
568         _inHref = false;
569     }
570   }
571 }
572
Popular Tags