KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > httpserver > HttpServerSettings


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.httpserver;
21
22 import java.awt.Dialog JavaDoc;
23 import java.beans.IntrospectionException JavaDoc;
24 import java.util.Hashtable JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Set JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28 import java.util.Properties JavaDoc;
29 import java.net.InetAddress JavaDoc;
30 import java.net.UnknownHostException JavaDoc;
31 import java.util.logging.Level JavaDoc;
32 import java.util.logging.Logger JavaDoc;
33 import java.util.prefs.Preferences JavaDoc;
34 import javax.swing.event.EventListenerList JavaDoc;
35 import org.openide.DialogDescriptor;
36
37 import org.openide.util.NbBundle;
38 import org.openide.util.HelpCtx;
39 import org.openide.util.Utilities;
40 import org.openide.NotifyDescriptor;
41 import org.openide.DialogDisplayer;
42 import org.openide.nodes.BeanNode;
43 import org.openide.util.NbPreferences;
44
45 /** Options for http server
46 *
47 * @author Ales Novak, Petr Jiricka
48 */

49 public class HttpServerSettings {
50     private static HttpServerSettings INSTANCE = new HttpServerSettings();
51     private static BeanNode view = null;
52
53     private static final int MAX_START_RETRIES = 20;
54     private static int currentRetries = 0;
55
56     protected static EventListenerList JavaDoc listenerList = new EventListenerList JavaDoc();
57
58     /** Has this been initialized ?
59     * Becomes true if a "running" getter or setter is called
60     */

61     static boolean inited = false;
62
63     /** Contains threads which are or will be asking for access for the given IP address. */
64     private static Hashtable JavaDoc<InetAddress JavaDoc,Thread JavaDoc> whoAsking = new Hashtable JavaDoc<InetAddress JavaDoc,Thread JavaDoc>();
65
66     public static final int SERVER_STARTUP_TIMEOUT = 3000;
67
68     /** constant for local host */
69     public static final String JavaDoc LOCALHOST = "local"; // NOI18N
70
/** constant for any host */
71     public static final String JavaDoc ANYHOST = "any"; // NOI18N
72

73     public static HostProperty hostProperty = null;
74     
75     public static final String JavaDoc PROP_PORT = "port"; // NOI18N
76
public static final String JavaDoc PROP_HOST_PROPERTY = "hostProperty"; // NOI18N
77
static final String JavaDoc PROP_WRAPPER_BASEURL = "wrapperBaseURL"; // NOI18N
78
public static final String JavaDoc PROP_RUNNING = "running"; // NOI18N
79

80     private static final String JavaDoc PROP_SHOW_GRANT_ACCESS = "showGrantAccess"; // NOI18N
81

82     /** port */
83      private static final int DEFAULT_PORT = 8082;
84
85     /** mapping of wrapper to URL */
86     private static String JavaDoc wrapperBaseURL = "/resource/"; // NOI18N
87

88     /** Reflects whether the server is actually running, not the running property */
89     static boolean running = false;
90
91     private static boolean startStopMessages = true;
92
93     private static Properties JavaDoc mappedServlets = new Properties JavaDoc();
94
95     /** http settings
96      * @deprecated use <CODE>SharedClassObject.findObject()</CODE>
97      */

98     public static HttpServerSettings OPTIONS = null;
99
100     /** Lock for the httpserver operations */
101     private static Object JavaDoc httpLock;
102     
103     private static Preferences JavaDoc getPreferences() {
104         return NbPreferences.forModule(HttpServerSettings.class);
105     }
106     
107     /**
108      * Obtains lock for httpserver synchronization
109      */

110     static final Object JavaDoc httpLock () {
111         if (httpLock == null) {
112             httpLock = new Object JavaDoc ();
113         }
114         return httpLock;
115     }
116
117     private HttpServerSettings() {
118     }
119
120     public static HttpServerSettings getDefault() {
121         return INSTANCE;
122     }
123     
124     /** human presentable name */
125     public String JavaDoc displayName() {
126         return NbBundle.getMessage(HttpServerSettings.class, "CTL_HTTP_settings");
127     }
128
129     /** getter for running status */
130     public boolean isRunning() {
131         if (inited) {
132             return running;
133         }
134         else {
135             // this used to be true, but it seems more reasonable not to start the server by default
136
// Fixes bug 11347
137
setRunning(false);
138             return running;
139         }
140     }
141
142     /** Intended to be called by the thread which succeeded to start the server */
143     void runSuccess() {
144         synchronized (httpLock ()) {
145             currentRetries = 0;
146             running = true;
147             httpLock ().notifyAll();
148         }
149     }
150
151     /** Intended to be called by the thread which failed to start the server.
152      * It decides whether try to start server on next port or show appropriate
153      * error message.
154      */

155     void runFailure(Throwable JavaDoc t) {
156         running = false;
157         if (t instanceof IncompatibleClassChangeError JavaDoc) {
158             // likely there is a wrong servlet API version on CLASSPATH
159
DialogDisplayer.getDefault ().notify(new NotifyDescriptor.Message(
160                NbBundle.getMessage (HttpServerSettings.class, "MSG_HTTP_SERVER_incompatbleClasses"),
161                NotifyDescriptor.Message.WARNING_MESSAGE));
162         }
163         else if (t instanceof java.net.BindException JavaDoc) {
164             // can't open socket - we can retry
165
currentRetries ++;
166             if (currentRetries <= MAX_START_RETRIES) {
167                 setPort(getPort() + 1);
168                 setRunning(true);
169             }
170             else {
171                 currentRetries = 0;
172                 DialogDisplayer.getDefault ().notify(new NotifyDescriptor.Message(
173                                                NbBundle.getMessage (HttpServerSettings.class, "MSG_HTTP_SERVER_START_FAIL"),
174                                                NotifyDescriptor.Message.WARNING_MESSAGE));
175                 int p = getPort ();
176                 if (p < 1024 && inited && Utilities.isUnix()) {
177                     DialogDisplayer.getDefault ().notify(new NotifyDescriptor.Message(
178                                                NbBundle.getMessage (HttpServerSettings.class, "MSG_onlyRootOnUnix"),
179                                                NotifyDescriptor.WARNING_MESSAGE));
180                 }
181
182             }
183         }
184         else {
185             // unknown problem
186
DialogDisplayer.getDefault ().notify(new NotifyDescriptor.Message(
187                NbBundle.getMessage (HttpServerSettings.class, "MSG_HTTP_SERVER_START_FAIL_unknown"),
188                NotifyDescriptor.Message.WARNING_MESSAGE));
189         }
190     }
191
192     /** Restarts the server if it is running - must be called in a synchronized block
193      * No need to restart if it is called during deserialization.
194      */

195     private void restartIfNecessary(boolean printMessages) {
196         if (running) {
197             if (!printMessages)
198                 setStartStopMessages(false);
199             HttpServerModule.stopHTTPServer();
200             HttpServerModule.initHTTPServer();
201             // messages will be enabled by the server thread
202
}
203     }
204
205     /** Returns a relative directory URL with a leading and a trailing slash */
206     private String JavaDoc getCanonicalRelativeURL(String JavaDoc url) {
207         String JavaDoc newURL;
208         if (url.length() == 0)
209             newURL = "/"; // NOI18N
210
else {
211             if (url.charAt(0) != '/')
212                 newURL = "/" + url; // NOI18N
213
else
214                 newURL = url;
215             if (newURL.charAt(newURL.length() - 1) != '/')
216                 newURL = newURL + "/"; // NOI18N
217
}
218         return newURL;
219     }
220
221     /** setter for running status */
222     public void setRunning(boolean running) {
223         inited = true;
224         if (this.running == running)
225             return;
226
227         synchronized (httpLock ()) {
228             if (running) {
229                 // running status is set by another thread
230
HttpServerModule.initHTTPServer();
231             }
232             else {
233                 this.running = false;
234                 HttpServerModule.stopHTTPServer();
235             }
236         }
237     }
238
239     // NOT publicly available
240

241     /** getter for classpath base */
242     String JavaDoc getWrapperBaseURL() {
243         return wrapperBaseURL;
244     }
245
246     /** setter for classpath base */
247     void setWrapperBaseURL(String JavaDoc wrapperBaseURL) {
248         // canonical form starts and ends with a /
249
String JavaDoc oldURL;
250         String JavaDoc newURL = getCanonicalRelativeURL(wrapperBaseURL);
251
252         // check if any change is taking place
253
if (this.wrapperBaseURL.equals(newURL))
254             return;
255
256         // implement the change
257
synchronized (httpLock ()) {
258             oldURL = this.wrapperBaseURL;
259             this.wrapperBaseURL = newURL;
260             restartIfNecessary(false);
261         }
262     }
263
264     /** setter for port */
265     public void setPort(int p) {
266         if (p <= 0 || p >65535) {
267             NotifyDescriptor.Message msg = new NotifyDescriptor.Message(
268                         NbBundle.getMessage(HttpServerSettings.class, "ERR_PortNumberOutOfRange", new Integer JavaDoc(p)), NotifyDescriptor.ERROR_MESSAGE);
269             
270             DialogDisplayer.getDefault().notify(msg);
271             return;
272         }
273         
274         synchronized (httpLock ()) {
275             getPreferences().putInt(PROP_PORT,p);
276             restartIfNecessary(true);
277         }
278     }
279
280     /** getter for port */
281     public int getPort() {
282         return getPreferences().getInt(PROP_PORT, DEFAULT_PORT);
283     }
284
285     public void setStartStopMessages(boolean ssm) {
286         startStopMessages = ssm;
287     }
288
289     public boolean isStartStopMessages() {
290         return startStopMessages;
291     }
292
293     public HelpCtx getHelpCtx () {
294         return new HelpCtx (HttpServerSettings.class);
295     }
296
297     /** Returns string for localhost */
298     private String JavaDoc getLocalHost() {
299         try {
300             return InetAddress.getLocalHost().getHostName();
301         }
302         catch (UnknownHostException JavaDoc e) {
303             return "localhost"; // NOI18N
304
}
305     }
306
307     public void addGrantAccessListener(GrantAccessListener l) {
308         listenerList.add(GrantAccessListener.class, l);
309     }
310
311     public void removeGrantAccessListener(GrantAccessListener l) {
312         listenerList.remove(GrantAccessListener.class, l);
313     }
314
315     /** Returns true if oneof the listeners allowed access */
316     protected boolean fireGrantAccessEvent(InetAddress JavaDoc clientAddress, String JavaDoc resource) {
317         Object JavaDoc[] listeners = listenerList.getListenerList();
318         GrantAccessEvent grantAccessEvent = null;
319         for (int i = listeners.length-2; i>=0; i-=2) {
320             if (listeners[i]==GrantAccessListener.class) {
321                 if (grantAccessEvent == null)
322                     grantAccessEvent = new GrantAccessEvent(this, clientAddress, resource);
323                 ((GrantAccessListener)listeners[i+1]).grantAccess(grantAccessEvent);
324             }
325         }
326         return (grantAccessEvent == null) ? false : grantAccessEvent.isGranted();
327     }
328
329     /** Requests access for address addr. If necessary asks the user. Returns true it the access
330     * has been granted. */

331     boolean allowAccess(InetAddress JavaDoc addr, String JavaDoc requestPath) {
332         if (accessAllowedNow(addr, requestPath))
333             return true;
334
335         Thread JavaDoc askThread = null;
336         synchronized (whoAsking) {
337             // one more test in the synchronized block
338
if (accessAllowedNow(addr, requestPath))
339                 return true;
340
341             askThread = (Thread JavaDoc)whoAsking.get(addr);
342             if (askThread == null) {
343                 askThread = Thread.currentThread();
344                 whoAsking.put(addr, askThread);
345             }
346         }
347
348         // now ask the user
349
synchronized (HttpServerSettings.class) {
350             if (askThread != Thread.currentThread()) {
351                 return accessAllowedNow(addr, requestPath);
352             }
353
354             try {
355                 if (!isShowGrantAccessDialog ())
356                     return false;
357                 
358                 String JavaDoc msg = NbBundle.getMessage (HttpServerSettings.class, "MSG_AddAddress", addr.getHostAddress ());
359                 
360                 final GrantAccessPanel panel = new GrantAccessPanel (msg);
361                 DialogDescriptor descriptor = new DialogDescriptor (
362                     panel,
363                     NbBundle.getMessage (HttpServerSettings.class, "CTL_GrantAccessTitle"),
364                     true,
365                     NotifyDescriptor.YES_NO_OPTION,
366                     NotifyDescriptor.NO_OPTION,
367                     null
368                 );
369                 descriptor.setMessageType (NotifyDescriptor.QUESTION_MESSAGE);
370                 // descriptor.setOptionsAlign (DialogDescriptor.BOTTOM_ALIGN);
371
final Dialog JavaDoc d = DialogDisplayer.getDefault ().createDialog (descriptor);
372                 d.setSize (580, 180);
373                 d.setVisible(true);
374
375                 setShowGrantAccessDialog (panel.getShowDialog ());
376                 if (NotifyDescriptor.YES_OPTION.equals(descriptor.getValue ())) {
377                     appendAddressToGranted(addr.getHostAddress());
378                     return true;
379                 }
380                 else
381                     return false;
382             }
383             finally {
384                 whoAsking.remove(addr);
385             }
386         } // end synchronized
387
}
388
389     /** Checks whether access to the server is now allowed. */
390     private boolean accessAllowedNow(InetAddress JavaDoc addr, String JavaDoc resource) {
391         if (hostProperty.getHost().equals(HttpServerSettings.ANYHOST))
392             return true;
393
394         Set JavaDoc hs = getGrantedAddressesSet();
395         if (hs.contains(addr.getHostAddress()))
396             return true;
397
398         if (fireGrantAccessEvent(addr, resource))
399             return true;
400
401         return false;
402     }
403
404     /** Appends the address to the list of addresses which have been granted access. */
405     private void appendAddressToGranted(String JavaDoc addr) {
406         synchronized (httpLock ()) {
407             String JavaDoc granted = hostProperty.getGrantedAddresses().trim();
408             if ((granted.length() > 0) &&
409                     (granted.charAt(granted.length() - 1) != ';') &&
410                     (granted.charAt(granted.length() - 1) != ','))
411                 granted += ',';
412             granted += addr;
413             hostProperty.setGrantedAddresses(granted);
414         }
415     }
416
417     /** Returns a list of addresses which have been granted access to the web server,
418     * including the localhost. Addresses are represented as strings. */

419     Set JavaDoc<String JavaDoc> getGrantedAddressesSet() {
420         HashSet JavaDoc<String JavaDoc> addr = new HashSet JavaDoc<String JavaDoc>();
421         try {
422             addr.add(InetAddress.getByName("localhost").getHostAddress()); // NOI18N
423
addr.add(InetAddress.getLocalHost().getHostAddress());
424         }
425         catch (UnknownHostException JavaDoc e) {}
426         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(hostProperty.getGrantedAddresses(), ",;"); // NOI18N
427
while (st.hasMoreTokens()) {
428             String JavaDoc ipa = st.nextToken();
429             ipa = ipa.trim();
430             try {
431                 addr.add(InetAddress.getByName(ipa).getHostAddress());
432             }
433             catch (UnknownHostException JavaDoc e) {}
434         }
435         return addr;
436     }
437
438     Properties JavaDoc getMappedServlets() {
439         return mappedServlets;
440     }
441
442     /** Converts string into string that is usable in URL.
443      * This mangling changes some characters
444      */

445     static String JavaDoc mangle (String JavaDoc name) {
446         StringBuffer JavaDoc sb = new StringBuffer JavaDoc ();
447         for (int i = 0; i < name.length (); i++) {
448             if (Character.isLetterOrDigit (name.charAt (i)) ||
449                 name.charAt (i) == '.') {
450                 sb.append (name.charAt (i));
451             }
452             else {
453                 String JavaDoc code = Integer.toHexString ((int)name.charAt (i)).toUpperCase ();
454                 if (code.length ()<2)
455                     code = (code.length () == 0)? "00": "0"+code; // NOI18N
456
sb.append ("%"). // NOI18N
457
append ((code.length () == 2)? code: code.substring (code.length ()-2));
458             }
459         }
460         return sb.toString ();
461     }
462     
463     /** Unconverts string from URL into old string.
464      * This mangling decodes '%xy'
465      */

466     static String JavaDoc demangle (String JavaDoc name) {
467         StringBuffer JavaDoc sb = new StringBuffer JavaDoc ();
468         try {
469             for (int i = 0; i < name.length (); i++) {
470                 if (name.charAt (i) != '%') {
471                     sb.append (name.charAt (i));
472                 }
473                 else {
474                     sb.append ((char)Integer.parseInt (name.substring (i+1, i+3), 16));
475                     i += 2;
476                 }
477             }
478         }
479         catch (NumberFormatException JavaDoc ex) {
480             ex.printStackTrace ();
481             return ""; // NOI18N
482
}
483         return sb.toString ();
484     }
485     
486     /** Getter for property hostProperty.
487      * @return Value of property hostProperty.
488      */

489     public HttpServerSettings.HostProperty getHostProperty () {
490         if (hostProperty == null) {
491             hostProperty = new HostProperty(getPreferences().get("grantedAddresses",""),
492                     getPreferences().get("host",LOCALHOST));
493         }
494         return hostProperty;
495     }
496     
497     /** Setter for property hostProperty.
498      * @param hostProperty New value of property hostProperty.
499      */

500     public void setHostProperty (HttpServerSettings.HostProperty hostProperty) {
501         if (ANYHOST.equals(hostProperty.getHost ()) || LOCALHOST.equals(hostProperty.getHost ())) {
502             this.hostProperty.setHost(hostProperty.getHost());
503             this.hostProperty.setGrantedAddresses(hostProperty.getGrantedAddresses());
504             getPreferences().put("host", hostProperty.getHost());//NOI18N
505
getPreferences().put("grantedAddresses", hostProperty.getGrantedAddresses());//NOI18N
506
}
507     }
508     
509     public boolean isShowGrantAccessDialog () {
510         return getPreferences().getBoolean(PROP_SHOW_GRANT_ACCESS, true);
511     }
512     
513     public void setShowGrantAccessDialog (boolean show) {
514         getPreferences().putBoolean(PROP_SHOW_GRANT_ACCESS,show);
515     }
516     
517     /** Property value that describes set of host with granted access
518      */

519     public static class HostProperty implements java.io.Serializable JavaDoc {
520         
521         private String JavaDoc grantedAddresses;
522         
523         private String JavaDoc host;
524         
525         private static final long serialVersionUID = 1927848926692414249L;
526         
527         HostProperty (String JavaDoc grantedAddresses, String JavaDoc host) {
528             this.grantedAddresses = grantedAddresses;
529             this.host = host;
530         }
531         
532         /** Getter for property host.
533          * @return Value of property host.
534          */

535         public String JavaDoc getHost () {
536             return host;
537         }
538         
539         /** Setter for property host.
540          * @param host New value of property host.
541          */

542         public void setHost (String JavaDoc host) {
543             this.host = host;
544         }
545         
546         /** Getter for property grantedAddresses.
547          * @return Value of property grantedAddresses.
548          */

549         public String JavaDoc getGrantedAddresses () {
550             return grantedAddresses;
551         }
552         
553         /** Setter for property grantedAddresses.
554          * @param grantedAddresses New value of property grantedAddresses.
555          */

556         public void setGrantedAddresses (String JavaDoc grantedAddresses) {
557             this.grantedAddresses = grantedAddresses;
558         }
559         
560     }
561     static synchronized BeanNode createViewNode() {
562         if (view == null) {
563             try {
564                 view = new BeanNode<HttpServerSettings>(HttpServerSettings.getDefault());
565             }
566             catch (IntrospectionException JavaDoc ex) {
567                 Logger.getLogger(HttpServerSettings.class.getName()).log(Level.INFO, null, ex);
568             }
569         }
570         return view;
571     }
572 }
573
Popular Tags