]> sjero.net Git - linphone/blob - p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/endpoint/servlethttp/ServletHttpTransport.java
remove mediastreamer2 and add it as a submodule instead.
[linphone] / p2pproxy / dependencies-src / jxse-src-2.5 / impl / src / net / jxta / impl / endpoint / servlethttp / ServletHttpTransport.java
1 /*
2  * Copyright (c) 2001-2007 Sun Microsystems, Inc.  All rights reserved.
3  *  
4  *  The Sun Project JXTA(TM) Software License
5  *  
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions are met:
8  *  
9  *  1. Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *  
12  *  2. Redistributions in binary form must reproduce the above copyright notice, 
13  *     this list of conditions and the following disclaimer in the documentation 
14  *     and/or other materials provided with the distribution.
15  *  
16  *  3. The end-user documentation included with the redistribution, if any, must 
17  *     include the following acknowledgment: "This product includes software 
18  *     developed by Sun Microsystems, Inc. for JXTA(TM) technology." 
19  *     Alternately, this acknowledgment may appear in the software itself, if 
20  *     and wherever such third-party acknowledgments normally appear.
21  *  
22  *  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must 
23  *     not be used to endorse or promote products derived from this software 
24  *     without prior written permission. For written permission, please contact 
25  *     Project JXTA at http://www.jxta.org.
26  *  
27  *  5. Products derived from this software may not be called "JXTA", nor may 
28  *     "JXTA" appear in their name, without prior written permission of Sun.
29  *  
30  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
32  *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN 
33  *  MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
34  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
35  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
36  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
37  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
38  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
39  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *  
41  *  JXTA is a registered trademark of Sun Microsystems, Inc. in the United 
42  *  States and other countries.
43  *  
44  *  Please see the license information page at :
45  *  <http://www.jxta.org/project/www/license.html> for instructions on use of 
46  *  the license in source files.
47  *  
48  *  ====================================================================
49  *  
50  *  This software consists of voluntary contributions made by many individuals 
51  *  on behalf of Project JXTA. For more information on Project JXTA, please see 
52  *  http://www.jxta.org.
53  *  
54  *  This license is based on the BSD license adopted by the Apache Foundation. 
55  */
56 package net.jxta.impl.endpoint.servlethttp;
57
58 import java.net.InetAddress;
59 import java.util.ArrayList;
60 import java.util.Comparator;
61 import java.util.Collections;
62 import java.util.Enumeration;
63 import java.util.Iterator;
64 import java.util.List;
65
66 import java.net.UnknownHostException;
67 import java.util.concurrent.Executor;
68
69 import java.util.logging.Logger;
70 import java.util.logging.Level;
71
72 import net.jxta.logging.Logging;
73
74 import net.jxta.document.Advertisement;
75 import net.jxta.document.AdvertisementFactory;
76 import net.jxta.document.Attribute;
77 import net.jxta.document.XMLElement;
78 import net.jxta.endpoint.EndpointAddress;
79 import net.jxta.endpoint.EndpointService;
80 import net.jxta.id.ID;
81 import net.jxta.meter.MonitorResources;
82 import net.jxta.peergroup.PeerGroup;
83 import net.jxta.protocol.ConfigParams;
84 import net.jxta.protocol.ModuleImplAdvertisement;
85 import net.jxta.protocol.TransportAdvertisement;
86 import net.jxta.platform.Module;
87
88 import net.jxta.exception.PeerGroupException;
89
90 import net.jxta.impl.endpoint.transportMeter.TransportBindingMeter;
91 import net.jxta.impl.endpoint.transportMeter.TransportMeter;
92 import net.jxta.impl.endpoint.transportMeter.TransportMeterBuildSettings;
93 import net.jxta.impl.endpoint.transportMeter.TransportServiceMonitor;
94 import net.jxta.impl.endpoint.IPUtils;
95 import net.jxta.impl.protocol.HTTPAdv;
96
97 import net.jxta.impl.meter.*;
98 import net.jxta.impl.peergroup.StdPeerGroup;
99
100 /**
101  * A JXTA Message Transport
102  *
103  * <p/>This class is really a facade for the following:<ul>
104  * <li>An HTTP client message sender</li>
105  * <li>An HTTP-server-based message receiver</li>
106  * </ul>
107  */
108 public final class ServletHttpTransport implements Module {
109
110     /**
111      * Logger
112      */
113     private final static transient Logger LOG = Logger.getLogger(ServletHttpTransport.class.getName());
114
115     /**
116      * The name of the protocol
117      */
118     private final static String DEFAULT_HTTP_PROTOCOL_NAME = "http";
119
120     String HTTP_PROTOCOL_NAME = DEFAULT_HTTP_PROTOCOL_NAME;
121
122     /**
123      * PeerGroup we are working for
124      */
125     PeerGroup group;
126     ID assignedID;
127     ModuleImplAdvertisement implAdvertisement;
128     
129     /**
130      * The executor used by HttpClientMessenger
131      */
132     Executor executor;
133
134     /**
135      * The endpoint we attach to.
136      */
137     private EndpointService endpoint = null;
138
139     /**
140      * If {@code true} then we are configured to act as an HTTP client. This
141      * means we will poll for messages.
142      */
143     private boolean configClient = false;
144
145     /**
146      * If {@code true} then we are configured to act as an HTTP server. This
147      * means we will accept connections from polling clients.
148      */
149     private boolean configServer = false;
150
151     /**
152      * The HttpMessageSender instance
153      */
154     private HttpMessageSender sender = null;
155
156     /**
157      * The HttpMessageReceiver instance
158      */
159     private HttpMessageReceiver receiver = null;
160
161     /**
162      * The TransportMeter for this httpTransport
163      */
164     private TransportMeter transportMeter;
165
166     /**
167      * The TransportBindingMeter for unknown connections (pings/errors)
168      */
169     private TransportBindingMeter unknownTransportBindingMeter;
170
171     /**
172      * The InetAddress of the network interface we are bound to otherwise the
173      * ALL/ANY address.
174      */
175     InetAddress usingInterface = null;
176
177     /**
178      * Port number to which we are bound.
179      */
180     int usingPort = 0;
181
182     /**
183      * The addresses which we will advertise and by which we may be reached.
184      */
185     private List<EndpointAddress> publicAddresses = null;
186
187     /**
188      * Our preferred return address which we will use as the "source" for
189      * messages we send.
190      */
191     private EndpointAddress publicAddress;
192
193     /**
194      * {@inheritDoc}
195      */
196     public synchronized void init(PeerGroup group, ID assignedID, Advertisement impl) throws PeerGroupException {
197         this.group = group;
198         this.assignedID = assignedID;
199         implAdvertisement = (ModuleImplAdvertisement) impl;
200         
201         this.executor = ((StdPeerGroup) group).getExecutor();
202
203         // Get out invariable parameters from the implAdv
204         XMLElement param = (XMLElement) implAdvertisement.getParam();
205
206         if (param != null) {
207             Enumeration list = param.getChildren("Proto");
208
209             if (list.hasMoreElements()) {
210                 XMLElement pname = (XMLElement) list.nextElement();
211                 String configProtoName = pname.getTextValue();
212                 if (null != configProtoName) {
213                     HTTP_PROTOCOL_NAME = configProtoName.trim();
214                 }
215             }
216         }
217
218         ConfigParams peerAdv = group.getConfigAdvertisement();
219
220         param = (XMLElement) peerAdv.getServiceParam(assignedID);
221
222         Enumeration httpChilds = param.getChildren(TransportAdvertisement.getAdvertisementType());
223
224         // get the TransportAdv
225         if (httpChilds.hasMoreElements()) {
226             param = (XMLElement) httpChilds.nextElement();
227             Attribute typeAttr = param.getAttribute("type");
228
229             if (!HTTPAdv.getAdvertisementType().equals(typeAttr.getValue())) {
230                 throw new IllegalArgumentException("Transport adv is not an http adv");
231             }
232
233             if (httpChilds.hasMoreElements()) {
234                 throw new IllegalArgumentException("Configuration contained multiple http advertisements");
235             }
236         } else {
237             throw new IllegalArgumentException("Configuration did not contain http advertisement");
238         }
239
240         Advertisement paramsAdv = AdvertisementFactory.newAdvertisement(param);
241
242         if (!(paramsAdv instanceof HTTPAdv)) {
243             throw new IllegalArgumentException("Provided advertisement was not a " + HTTPAdv.getAdvertisementType());
244         }
245
246         HTTPAdv httpAdv = (HTTPAdv) paramsAdv;
247
248         // determine the local interface to use. If the user specifies
249         // one, use that. Otherwise, use the all the available interfaces.
250         String interfaceAddressStr = httpAdv.getInterfaceAddress();
251         boolean publicAddressOnly = httpAdv.getPublicAddressOnly();
252
253         if (interfaceAddressStr != null) {
254             try {
255                 usingInterface = InetAddress.getByName(interfaceAddressStr);
256             } catch (UnknownHostException failed) {
257                 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
258                     LOG.warning("Invalid address for local interface address, using default");
259                 }
260                 usingInterface = IPUtils.ANYADDRESS;
261             }
262         } else {
263             usingInterface = IPUtils.ANYADDRESS;
264         }
265
266         usingPort = httpAdv.getPort();
267
268         configClient = httpAdv.isClientEnabled();
269
270         configServer = httpAdv.isServerEnabled();
271
272         publicAddresses = getPublicAddresses(configServer, httpAdv.getServer(), usingInterface, usingPort, publicAddressOnly);
273
274         if (!configClient && !configServer) {
275             throw new IllegalArgumentException("Neither incoming nor outgoing connections configured.");
276         }
277
278         publicAddress = publicAddresses.get(0);
279
280         // Tell tell the world about our configuration.
281         if (Logging.SHOW_CONFIG && LOG.isLoggable(Level.CONFIG)) {
282             StringBuilder configInfo = new StringBuilder("Configuring HTTP Message Transport : " + assignedID);
283
284             if (implAdvertisement != null) {
285                 configInfo.append("\n\tImplementation:");
286                 configInfo.append("\n\t\tModule Spec ID: ").append(implAdvertisement.getModuleSpecID());
287                 configInfo.append("\n\t\tImpl Description: ").append(implAdvertisement.getDescription());
288                 configInfo.append("\n\t\tImpl URI: ").append(implAdvertisement.getUri());
289                 configInfo.append("\n\t\tImpl Code: ").append(implAdvertisement.getCode());
290             }
291             configInfo.append("\n\tGroup Params:");
292             configInfo.append("\n\t\tGroup: ").append(group.getPeerGroupName());
293             configInfo.append("\n\t\tGroup ID: ").append(group.getPeerGroupID());
294             configInfo.append("\n\t\tPeer ID: ").append(group.getPeerID());
295             configInfo.append("\n\tConfiguration :");
296             configInfo.append("\n\t\tProtocol: ").append(httpAdv.getProtocol());
297             configInfo.append("\n\t\tClient Enabled: ").append(configClient);
298             configInfo.append("\n\t\tServer Enabled: ").append(configServer);
299             configInfo.append("\n\t\tPublic address: ").append(httpAdv.getServer() == null ? "(unspecified)" : httpAdv.getServer());
300             configInfo.append("\n\t\tInterface address: ").append(interfaceAddressStr == null ? "(unspecified)" : interfaceAddressStr);
301             configInfo.append("\n\t\tUnicast Server Bind Addr: ").append(IPUtils.getHostAddress(usingInterface)).append(":").append(usingPort);
302             configInfo.append("\n\t\tPublic Addresses: ");
303             configInfo.append("\n\t\t\tDefault Endpoint Addr : ").append(publicAddress);
304             for (EndpointAddress anAddr : publicAddresses) {
305                 configInfo.append("\n\t\t\tEndpoint Addr : ").append(anAddr);
306             }
307             LOG.config(configInfo.toString());
308         }
309     }
310
311     /**
312      * {@inheritDoc}
313      */
314     public synchronized int startApp(String[] args) {
315         endpoint = group.getEndpointService();
316
317         if (null == endpoint) {
318             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
319                 LOG.warning("Stalled until there is an endpoint service");
320             }
321
322             return START_AGAIN_STALLED;
323         }
324
325         if (TransportMeterBuildSettings.TRANSPORT_METERING) {
326             TransportServiceMonitor transportServiceMonitor = (TransportServiceMonitor) MonitorManager.getServiceMonitor(group,
327                     MonitorResources.transportServiceMonitorClassID);
328
329             if (transportServiceMonitor != null) {
330                 transportMeter = transportServiceMonitor.createTransportMeter("HTTP", publicAddress);
331                 unknownTransportBindingMeter = transportMeter.getTransportBindingMeter(TransportMeter.UNKNOWN_PEER,
332                         TransportMeter.UNKNOWN_ADDRESS);
333             }
334         }
335
336         if (configServer) {
337             // Start the http server that runs the receiver.
338
339             try {
340                 receiver = new HttpMessageReceiver(this, publicAddresses, usingInterface, usingPort);
341                 receiver.start();
342             } catch (PeerGroupException e) {
343                 if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
344                     LOG.log(Level.SEVERE, "Could not start http message receiver", e);
345                 }
346                 return -1; // Can't go on; if we were configured to be a server we must make the failure obvious.
347             }
348         }
349
350         if (configClient) {
351             // create the MessageSender
352
353             try {
354                 sender = new HttpMessageSender(this,
355                         new EndpointAddress("jxta", group.getPeerID().getUniqueValue().toString(), null, null));
356                 sender.start();
357             } catch (PeerGroupException e) {
358                 if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
359                     LOG.log(Level.SEVERE, "Could not start http message sender", e);
360                 }
361                 return -1; // Can't go on; if we were configured to be a server we must make the failure obvious.
362             }
363         }
364
365         return 0;
366     }
367
368     /**
369      * {@inheritDoc}
370      */
371     public synchronized void stopApp() {
372         if (receiver != null) {
373             receiver.stop();
374         }
375
376         if (sender != null) {
377             sender.stop();
378         }
379
380         endpoint = null;
381     }
382
383     /**
384      * {@inheritDoc}
385      */
386     EndpointService getEndpointService() {
387         return endpoint;
388     }
389
390     private List<EndpointAddress> getPublicAddresses(boolean serverEnabled, String serverName, InetAddress usingInterface, int serverSocketPort, boolean publicAddressOnly) {
391         List<EndpointAddress> publicAddresses = new ArrayList<EndpointAddress>();
392
393         if (serverEnabled) {
394             // Build the publicAddresses
395
396             // first in the list is the "public server name". We don't try to
397             // resolve this since it might not be resolvable in the context
398             // we are running in, we just assume it's good.
399             if (serverName != null) {
400                 // use speced server name.
401                 EndpointAddress newAddr = new EndpointAddress(HTTP_PROTOCOL_NAME, serverName, null, null);
402
403                 publicAddresses.add(newAddr);
404                 if (publicAddressOnly) {
405                     return publicAddresses;
406                 }
407             }
408         }
409
410         // then add the rest of the local interfaces as appropriate
411         if (usingInterface.equals(IPUtils.ANYADDRESS)) {
412             // its wildcarded
413             Iterator<InetAddress> eachLocal = IPUtils.getAllLocalAddresses();
414             List<EndpointAddress> wildAddrs = new ArrayList<EndpointAddress>();
415
416             while (eachLocal.hasNext()) {
417                 InetAddress anAddress = eachLocal.next();
418
419                 String hostAddress = IPUtils.getHostAddress(anAddress);
420
421                 EndpointAddress newAddr = new EndpointAddress(HTTP_PROTOCOL_NAME,
422                         hostAddress + ":" + Integer.toString(serverSocketPort), null, null);
423
424                 // don't add it if its already in the list
425                 if (!publicAddresses.contains(newAddr)) {
426                     wildAddrs.add(newAddr);
427                 }
428             }
429
430             // we sort them so that later equals() will be deterministic.
431             // the result of IPUtils.getAllLocalAddresses() is not known
432             // to be sorted.
433             Collections.sort(wildAddrs, new Comparator<EndpointAddress>() {
434                 public int compare(EndpointAddress one, EndpointAddress two) {
435                     return one.toString().compareTo(two.toString());
436                 }
437
438                 @Override
439                 public boolean equals(Object that) {
440                     return this == that;
441                 }
442             });
443
444             publicAddresses.addAll(wildAddrs);
445         } else {
446             // use specified interface
447             String hostAddress = IPUtils.getHostAddress(usingInterface);
448
449             EndpointAddress newAddr = new EndpointAddress(HTTP_PROTOCOL_NAME,
450                     hostAddress + ":" + Integer.toString(serverSocketPort), null, null);
451
452             // don't add it if its already in the list
453             if (!publicAddresses.contains(newAddr)) {
454                 publicAddresses.add(newAddr);
455             }
456         }
457
458         return publicAddresses;
459     }
460
461     TransportBindingMeter getTransportBindingMeter(String peerIDString, EndpointAddress destinationAddress) {
462         if (transportMeter != null) {
463             return transportMeter.getTransportBindingMeter((peerIDString != null) ? peerIDString : TransportMeter.UNKNOWN_PEER,
464                     destinationAddress);
465         } else {
466             return null;
467         }
468     }
469
470     TransportBindingMeter getUnknownTransportBindingMeter() {
471         return unknownTransportBindingMeter;
472     }
473 }