1 22 package org.xsocket.stream; 23 24 import java.io.IOException ; 25 import java.lang.reflect.Field ; 26 import java.net.InetAddress ; 27 import java.net.InetSocketAddress ; 28 import java.net.UnknownHostException ; 29 import java.util.ArrayList ; 30 import java.util.HashMap ; 31 import java.util.Map ; 32 import java.util.concurrent.Executor ; 33 import java.util.concurrent.ExecutorService ; 34 import java.util.concurrent.Executors ; 35 import java.util.logging.Level ; 36 import java.util.logging.Logger ; 37 38 import javax.net.ssl.SSLContext; 39 40 41 import org.xsocket.IWorkerPool; 42 import org.xsocket.Resource; 43 import org.xsocket.stream.io.impl.IoProvider; 44 import org.xsocket.stream.io.spi.IAcceptor; 45 import org.xsocket.stream.io.spi.IServerIoProvider; 46 import org.xsocket.stream.io.spi.IAcceptorCallback; 47 import org.xsocket.stream.io.spi.IIoHandler; 48 49 50 51 52 58 public final class MultithreadedServer implements IMultithreadedServer { 59 60 65 66 private static final Logger LOG = Logger.getLogger(MultithreadedServer.class.getName()); 67 68 69 private static final String DEFAULT_HOST_ADDRESS = "0.0.0.0"; 70 71 72 73 74 private boolean isOpen= false; 76 77 78 private static IServerIoProvider serverIoProvider = null; 80 private IAcceptor acceptor = null; 81 private InetSocketAddress address = null; 82 83 84 private Map <String , Object > options = null; 86 private boolean sslOn = false; 87 private SSLContext sslContext = null; 88 89 90 private Executor workerpool = null; 92 private boolean isSelfCreatedWorkerPool = false; 93 94 95 96 private IHandler appHandlerPrototype = null; 98 99 private final IoHandlerContext ioHandlerContext = new IoHandlerContext(null, null); 101 102 103 private final ArrayList <IMutlithreadedServerListener> listeners = new ArrayList <IMutlithreadedServerListener>(); 105 106 107 private int idleTimeoutSec = Integer.MAX_VALUE; 109 private int connectionTimeoutSec = Integer.MAX_VALUE; 110 111 112 113 static { 114 String serverIoProviderClassname = System.getProperty(IServerIoProvider.PROVIDER_CLASSNAME_KEY); 116 if (serverIoProviderClassname != null) { 117 try { 118 Class serverIoProviderClass = Class.forName(serverIoProviderClassname); 119 serverIoProvider = (IServerIoProvider) serverIoProviderClass.newInstance(); 120 } catch (Exception e) { 121 LOG.warning("error occured by creating ServerIoProivder " + serverIoProviderClassname + ": " + e.toString()); 122 LOG.info("using default ServerIoProvider"); 123 124 } 125 } 126 127 if (serverIoProvider == null) { 128 serverIoProvider = new IoProvider(); 129 } 130 } 131 132 133 134 135 145 public MultithreadedServer(IHandler handler) throws UnknownHostException , IOException { 146 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), 0, new HashMap <String , Object >(), handler, false, null); 147 } 148 149 150 161 public MultithreadedServer(IHandler handler, Executor workerpool) throws UnknownHostException , IOException { 162 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), 0, new HashMap <String , Object >(), handler, workerpool, false, null); 163 } 164 165 166 167 170 public MultithreadedServer(StreamSocketConfiguration socketConfiguration, IHandler handler) throws UnknownHostException , IOException { 171 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), 0, socketConfiguration, handler, false, null); 172 } 173 174 175 176 186 public MultithreadedServer(Map <String , Object > options, IHandler handler) throws UnknownHostException , IOException { 187 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), 0, options, handler, false, null); 188 } 189 190 191 201 public MultithreadedServer(int port, IHandler handler) throws UnknownHostException , IOException { 202 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, new HashMap <String , Object >(), handler, false, null); 203 } 204 205 206 218 public MultithreadedServer(int port, IHandler handler, Executor workerpool) throws UnknownHostException , IOException { 219 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, new HashMap <String , Object >(), handler, workerpool, false, null); 220 } 221 222 223 226 public MultithreadedServer(int port, StreamSocketConfiguration socketConfiguration, IHandler handler) throws UnknownHostException , IOException { 227 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, socketConfiguration, handler, false, null); 228 } 229 230 241 public MultithreadedServer(int port, Map <String , Object > options, IHandler handler) throws UnknownHostException , IOException { 242 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, options, handler, false, null); 243 } 244 245 246 247 258 public MultithreadedServer(InetAddress address, int port, IHandler handler) throws UnknownHostException , IOException { 259 this(address, port, new HashMap <String , Object >(), handler, false, null); 260 } 261 262 263 264 265 277 public MultithreadedServer(InetAddress address, int port, IHandler handler, Executor workerPool) throws UnknownHostException , IOException { 278 this(address, port, new HashMap <String , Object >(), handler, workerPool, false, null); 279 } 280 281 282 283 286 public MultithreadedServer(InetAddress address, int port, StreamSocketConfiguration socketConfiguration, IHandler handler) throws UnknownHostException , IOException { 287 this(address, port, socketConfiguration, handler, false, null); 288 } 289 290 291 292 303 public MultithreadedServer(String ipAddress, int port, IHandler handler) throws UnknownHostException , IOException { 304 this(InetAddress.getByName(ipAddress), port, new HashMap <String , Object >(), handler, false, null); 305 } 306 307 308 311 public MultithreadedServer(String ipAddress, int port, StreamSocketConfiguration socketConfiguration, IHandler handler) throws UnknownHostException , IOException { 312 this(InetAddress.getByName(ipAddress), port, socketConfiguration, handler, false, null); 313 } 314 315 316 328 public MultithreadedServer(String ipAddress, int port, Map <String , Object > options, IHandler handler) throws UnknownHostException , IOException { 329 this(InetAddress.getByName(ipAddress), port, options, handler, false, null); 330 } 331 332 333 334 335 347 public MultithreadedServer(int port, IHandler handler, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 348 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, new HashMap <String , Object >(), handler, sslOn ,sslContext); 349 } 350 351 352 355 public MultithreadedServer(int port, StreamSocketConfiguration socketConfiguration, IHandler handler, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 356 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, socketConfiguration, handler, sslOn ,sslContext); 357 } 358 359 360 361 374 public MultithreadedServer(int port,Map <String , Object > options, IHandler handler, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 375 this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, options, handler, sslOn ,sslContext); 376 } 377 378 379 392 public MultithreadedServer(String ipAddress, int port, IHandler handler, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 393 this(InetAddress.getByName(ipAddress), port, new HashMap <String , Object >(), handler, sslOn, sslContext); 394 } 395 396 397 400 public MultithreadedServer(String ipAddress, int port, StreamSocketConfiguration socketConfiguration, IHandler handler, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 401 this(InetAddress.getByName(ipAddress), port, socketConfiguration, handler, sslOn, sslContext); 402 } 403 404 418 public MultithreadedServer(String ipAddress, int port, Map <String , Object > options, IHandler handler, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 419 this(InetAddress.getByName(ipAddress), port, options, handler, sslOn, sslContext); 420 } 421 422 423 436 public MultithreadedServer(InetAddress address, int port, IHandler handler, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 437 this(address, port, new HashMap <String , Object >(), handler, sslOn, sslContext); 438 } 439 440 441 444 public MultithreadedServer(InetAddress address, int port, StreamSocketConfiguration socketConfiguration, IHandler handler, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 445 this(address, port, socketConfiguration, handler, newServerWorkerPool(), sslOn, sslContext); 446 isSelfCreatedWorkerPool = true; 447 } 448 449 450 464 public MultithreadedServer(InetAddress address, int port, Map <String , Object > options, IHandler handler, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 465 this(address, port, options, handler, newServerWorkerPool(), sslOn, sslContext); 466 isSelfCreatedWorkerPool = true; 467 } 468 469 472 public MultithreadedServer(InetAddress address, int port, StreamSocketConfiguration socketConfiguration, IHandler appHandler, Executor workerpool, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 473 this(new InetSocketAddress (address, port), socketConfiguration.toOptions(), appHandler, workerpool, sslOn, sslContext); 474 } 475 476 477 492 public MultithreadedServer(InetAddress address, int port, Map <String , Object > options, IHandler appHandler, Executor workerpool, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 493 this(new InetSocketAddress (address, port), options, appHandler, workerpool, sslOn, sslContext); 494 } 495 496 497 private MultithreadedServer(InetSocketAddress address, Map <String , Object > options, IHandler appHandler, Executor workerpool, boolean sslOn, SSLContext sslContext) throws UnknownHostException , IOException { 498 this.address = address; 499 this.options = options; 500 this.appHandlerPrototype = appHandler; 501 this.workerpool = workerpool; 502 this.sslOn = sslOn; 503 this.sslContext = sslContext; 504 505 ioHandlerContext.updateAppHandler(appHandler); 506 ioHandlerContext.updateWorkerpool(workerpool); 507 } 508 509 510 511 514 @SuppressWarnings ("unchecked") 515 public final void run() { 516 517 try { 518 if (appHandlerPrototype == null) { 519 LOG.warning("no handler has been set. Call setHandler-method to set an assigned handler"); 520 } 521 522 523 Runtime.getRuntime().addShutdownHook(new Thread () { 524 @Override 525 public void run() { 526 close(); 527 } 528 }); 529 530 531 532 if (sslContext != null) { 534 acceptor = new IoProvider().create(new AcceptorCallback(), ioHandlerContext, address, 0, options, sslContext, sslOn); 535 } else { 536 acceptor = serverIoProvider.createAcceptor(new AcceptorCallback(), ioHandlerContext, address, 0, options); 537 } 538 acceptor.listen(); 539 540 541 } catch (Exception e) { 542 throw new RuntimeException (e.toString()); 543 } 544 } 545 546 547 550 public Object getOption(String name) throws IOException { 551 return acceptor.getOption(name); 552 } 553 554 555 556 559 public Map <String , Class > getOptions() { 560 return acceptor.getOptions(); 561 } 562 563 564 565 568 @SuppressWarnings ("unchecked") 569 public void close() { 570 if (isOpen) { 571 isOpen = false; 572 573 try { 574 acceptor.close(); } catch (IOException ignore) { } 576 577 if (isSelfCreatedWorkerPool) { 578 if(workerpool instanceof ExecutorService ) { 579 ((ExecutorService ) workerpool).shutdown(); 580 } 581 } 582 } 583 } 584 585 586 587 private static final ExecutorService newServerWorkerPool() { 588 return Executors.newFixedThreadPool(250); 589 } 590 591 592 593 IAcceptor getAcceptor() { 594 return acceptor; 595 } 596 597 598 601 public void addListener(IMutlithreadedServerListener listener) { 602 listeners.add(listener); 603 } 605 606 607 610 public boolean removeListener(IMutlithreadedServerListener listener) { 611 boolean result = listeners.remove(listener); 612 614 return result; 615 } 616 617 618 623 public IWorkerPool getWorkerPool() { 624 return (IWorkerPool) workerpool; 625 } 626 627 628 631 public Executor getWorkerpool() { 632 return workerpool; 633 } 634 635 636 640 @SuppressWarnings ("unchecked") 641 public void setWorkerPool(IWorkerPool newWorkerPool) { 642 setWorkerPool((Executor ) newWorkerPool); 643 } 644 645 646 @SuppressWarnings ("unchecked") 647 private void setWorkerPool(Executor newWorkerPool) { 648 Executor oldWorkerPool = workerpool; 649 650 this.workerpool = newWorkerPool; 651 652 if (isSelfCreatedWorkerPool) { 653 if(oldWorkerPool instanceof ExecutorService ) { 654 ((ExecutorService ) oldWorkerPool).shutdown(); 655 } 656 } 657 isSelfCreatedWorkerPool = false; 658 659 ioHandlerContext.updateWorkerpool(workerpool); 660 661 if (newWorkerPool instanceof IWorkerPool) { 662 for (IMutlithreadedServerListener listener : (ArrayList <IMutlithreadedServerListener>)listeners.clone()) { 663 listener.onWorkerPoolUpdated(null, (IWorkerPool) newWorkerPool); 664 } 665 } 666 } 667 668 669 670 671 676 public final void setDispatcherPoolSize(int size) { 677 LOG.warning("not implemented. Method will be removed"); 678 } 679 680 685 public int getDispatcherPoolSize() { 686 LOG.warning("not implemented. Method will be removed"); 687 return -1; 688 } 689 690 691 694 public boolean isOpen() { 695 return isOpen; 696 } 697 698 699 700 703 public void setHandler(IHandler appHandler) { 704 if (appHandler == null) { 705 throw new NullPointerException ("handler is null"); 706 } 707 708 if (isOpen) { 709 destroyCurrentHandler(); 710 this.appHandlerPrototype = appHandler; 711 712 ioHandlerContext.updateAppHandler(appHandlerPrototype); 713 initCurrentHandler(); 714 715 } else { 716 this.appHandlerPrototype = appHandler; 717 ioHandlerContext.updateAppHandler(appHandlerPrototype); 718 } 719 } 720 721 722 723 private void destroyCurrentHandler() { 724 if (appHandlerPrototype != null) { 725 if (ioHandlerContext.isLifeCycleHandler()) { 726 ((org.xsocket.ILifeCycle) appHandlerPrototype).onDestroy(); 727 } 728 appHandlerPrototype = null; 729 } 730 } 731 732 private void initCurrentHandler() { 733 injectContext(appHandlerPrototype); 734 735 if (ioHandlerContext.isLifeCycleHandler()) { 736 ((org.xsocket.ILifeCycle) appHandlerPrototype).onInit(); 737 } 738 } 739 740 741 742 743 746 public final int getLocalPort() { 747 return address.getPort(); 748 } 749 750 751 754 public final InetAddress getLocalAddress() { 755 return address.getAddress(); 756 } 757 758 759 760 761 766 public final int getReceiveBufferPreallocationSize() { 767 LOG.warning("not implemented. Method will be removed"); 768 return -1; 769 } 770 771 772 773 778 public void setReceiveBufferPreallocationSize(int size) { 779 LOG.warning("not implemented. Method will be removed"); 780 } 781 782 783 784 785 788 public void setConnectionTimeoutSec(int timeoutSec) { 789 this.connectionTimeoutSec = timeoutSec; 790 } 791 792 793 796 public void setIdleTimeoutSec(int timeoutSec) { 797 this.idleTimeoutSec = timeoutSec; 798 } 799 800 801 802 805 public int getConnectionTimeoutSec() { 806 return connectionTimeoutSec; 807 } 808 809 810 811 814 public int getIdleTimeoutSec() { 815 return idleTimeoutSec; 816 } 817 818 819 820 int getNumberOfOpenConnections() { 821 return acceptor.getNumberOfOpenConnections(); 822 } 823 824 827 long getNumberOfHandledConnections() { 828 return -1; 829 } 830 831 832 833 834 835 836 837 private String getVersionInfo(String packName) { 838 Package p = Package.getPackage(packName); 839 if (p != null) { 840 String implVersion = p.getImplementationVersion(); 841 if (implVersion == null) { 842 implVersion = ""; 843 } 844 return implVersion; 845 } else { 846 return ""; 847 } 848 } 849 850 851 852 853 private void injectContext(IHandler hdl) { 854 IServerContext ctx = null; 855 Field [] fields = hdl.getClass().getDeclaredFields(); 856 for (Field field : fields) { 857 if ((field.getType() == IServerContext.class) && (field.getAnnotation(Resource.class) != null)) { 858 field.setAccessible(true); 859 try { 860 if (ctx == null) { 861 ctx = new HandlerContext(); 862 } 863 field.set(hdl, ctx); 864 } catch (IllegalAccessException iae) { 865 LOG.warning("couldn't set HandlerContext for attribute " + field.getName() + ". Reason " + iae.toString()); 866 } 867 } 868 } 869 } 870 871 872 private final class AcceptorCallback implements IAcceptorCallback { 873 874 @SuppressWarnings ("unchecked") 875 public void onConnected() { 876 877 address = acceptor.getLocalAddress(); 878 isOpen = true; 879 880 881 initCurrentHandler(); 883 884 for (IMutlithreadedServerListener listener : (ArrayList <IMutlithreadedServerListener>)listeners.clone()) { 886 listener.onInit(); 887 } 888 889 String versionInfo = getVersionInfo("org.xsocket").trim(); 890 if (versionInfo.length() > 0) { 891 versionInfo = "xSocket " + versionInfo; 892 } 893 894 895 if (!(serverIoProvider instanceof IoProvider)) { 896 String verInfo = getVersionInfo(serverIoProvider.getClass().getPackage().getName()); 897 if (verInfo.length() > 0) { 898 versionInfo = versionInfo + "; " + serverIoProvider.getClass().getName() + " " + verInfo; 899 } 900 } 901 902 LOG.info("server listening on " + acceptor.getLocalAddress().toString() + " (" + versionInfo + ")"); 903 } 904 905 906 @SuppressWarnings ("unchecked") 907 public void onDisconnected() { 908 909 destroyCurrentHandler(); 910 911 for (IMutlithreadedServerListener listener : (ArrayList <IMutlithreadedServerListener>)listeners.clone()) { 912 listener.onDestroy(); 913 } 914 915 LOG.info("server has been shutdown"); 916 } 917 918 919 public void onConnectionAccepted(IIoHandler ioHandler) throws IOException { 920 921 IHandler hdl = appHandlerPrototype; 922 if (ioHandlerContext.isAppHandlerConnectionScoped()) { 923 try { 924 hdl = (IHandler) ((IConnectionScoped) appHandlerPrototype).clone(); 925 } catch (CloneNotSupportedException cne) { 926 if (LOG.isLoggable(Level.FINE)) { 927 LOG.fine("error occured by cloning appHandler " + appHandlerPrototype.getClass().getName() + ". " + cne.toString()); 928 } 929 } 930 } 931 932 933 INonBlockingConnection connection = new NonBlockingConnection(ioHandlerContext, ioHandler, hdl, serverIoProvider); 935 connection.setIdleTimeoutSec(idleTimeoutSec); 936 connection.setConnectionTimeoutSec(connectionTimeoutSec); 937 } 938 } 939 940 941 private final class HandlerContext implements IServerContext { 942 943 946 public int getLocalePort() { 947 return MultithreadedServer.this.getLocalPort(); 948 } 949 950 953 public InetAddress getLocaleAddress() { 954 return MultithreadedServer.this.getLocalAddress(); 955 } 956 957 960 public int getNumberOfOpenConnections() { 961 return MultithreadedServer.this.getNumberOfOpenConnections(); 962 } 963 964 967 public IWorkerPool getWorkerPool() { 968 return MultithreadedServer.this.getWorkerPool(); 969 } 970 971 974 public Executor getWorkerpool() { 975 return MultithreadedServer.this.getWorkerpool(); 976 } 977 978 981 public int getReceiveBufferPreallocationSize() { 982 return MultithreadedServer.this.getReceiveBufferPreallocationSize(); 983 } 984 } 985 } 986 | Popular Tags |