001package com.github.theholywaffle.teamspeak3.api.reconnect; 002 003/* 004 * #%L 005 * TeamSpeak 3 Java API 006 * %% 007 * Copyright (C) 2014 - 2016 Bert De Geyter, Roger Baumgartner 008 * %% 009 * Permission is hereby granted, free of charge, to any person obtaining a copy 010 * of this software and associated documentation files (the "Software"), to deal 011 * in the Software without restriction, including without limitation the rights 012 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 013 * copies of the Software, and to permit persons to whom the Software is 014 * furnished to do so, subject to the following conditions: 015 * 016 * The above copyright notice and this permission notice shall be included in 017 * all copies or substantial portions of the Software. 018 * 019 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 020 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 021 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 022 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 023 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 024 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 025 * THE SOFTWARE. 026 * #L% 027 */ 028 029public abstract class ReconnectStrategy { 030 031 private static final int CONSTANT_BACKOFF = 10000; 032 private static final int START_TIMEOUT = 1000; 033 private static final int TIMEOUT_CAP = 60000; 034 private static final int ADDEND = 2000; 035 private static final double MULTIPLIER = 1.5; 036 037 private ReconnectStrategy() {} 038 039 public abstract ConnectionHandler create(ConnectionHandler userConnectionHandler); 040 041 public static ReconnectStrategy userControlled() { 042 return new UserControlled(); 043 } 044 045 public static ReconnectStrategy disconnect() { 046 return new Disconnect(); 047 } 048 049 public static ReconnectStrategy constantBackoff() { 050 return constantBackoff(CONSTANT_BACKOFF); 051 } 052 053 public static ReconnectStrategy constantBackoff(int timeout) { 054 return new Constant(timeout); 055 } 056 057 public static ReconnectStrategy linearBackoff() { 058 return linearBackoff(START_TIMEOUT, ADDEND, TIMEOUT_CAP); 059 } 060 061 public static ReconnectStrategy linearBackoff(int startTimeout, int addend) { 062 return linearBackoff(startTimeout, addend, TIMEOUT_CAP); 063 } 064 065 public static ReconnectStrategy linearBackoff(int startTimeout, int addend, int timeoutCap) { 066 return new Linear(startTimeout, addend, timeoutCap); 067 } 068 069 public static ReconnectStrategy exponentialBackoff() { 070 return exponentialBackoff(START_TIMEOUT, MULTIPLIER, TIMEOUT_CAP); 071 } 072 073 public static ReconnectStrategy exponentialBackoff(int startTimeout, double multiplier) { 074 return exponentialBackoff(startTimeout, multiplier, TIMEOUT_CAP); 075 } 076 077 public static ReconnectStrategy exponentialBackoff(int startTimeout, double multiplier, int timeoutCap) { 078 return new Exponential(startTimeout, multiplier, timeoutCap); 079 } 080 081 private static class UserControlled extends ReconnectStrategy { 082 083 @Override 084 public ConnectionHandler create(ConnectionHandler userConnectionHandler) { 085 String message = "userConnectionHandler cannot be null when using strategy UserControlled!"; 086 if (userConnectionHandler == null) throw new NullPointerException(message); 087 return userConnectionHandler; 088 } 089 } 090 091 private static class Disconnect extends ReconnectStrategy { 092 093 @Override 094 public ConnectionHandler create(ConnectionHandler userConnectionHandler) { 095 return new DisconnectingConnectionHandler(userConnectionHandler); 096 } 097 } 098 099 private static class Constant extends ReconnectStrategy { 100 101 private final int timeout; 102 103 public Constant(int timeout) { 104 if (timeout <= 0) throw new IllegalArgumentException("Timeout must be greater than 0"); 105 106 this.timeout = timeout; 107 } 108 109 @Override 110 public ConnectionHandler create(ConnectionHandler userConnectionHandler) { 111 return new ReconnectingConnectionHandler(userConnectionHandler, timeout, timeout, 0, 1.0); 112 } 113 } 114 115 private static class Linear extends ReconnectStrategy { 116 117 private final int startTimeout; 118 private final int addend; 119 private final int timeoutCap; 120 121 private Linear(int startTimeout, int addend, int timeoutCap) { 122 if (startTimeout <= 0) throw new IllegalArgumentException("Starting timeout must be greater than 0"); 123 if (addend <= 0) throw new IllegalArgumentException("Addend must be greater than 0"); 124 125 this.startTimeout = startTimeout; 126 this.addend = addend; 127 this.timeoutCap = timeoutCap; 128 } 129 130 @Override 131 public ConnectionHandler create(ConnectionHandler userConnectionHandler) { 132 return new ReconnectingConnectionHandler(userConnectionHandler, startTimeout, timeoutCap, addend, 1.0); 133 } 134 } 135 136 private static class Exponential extends ReconnectStrategy { 137 138 private final int startTimeout; 139 private final double multiplier; 140 private final int timeoutCap; 141 142 private Exponential(int startTimeout, double multiplier, int timeoutCap) { 143 if (startTimeout <= 0) throw new IllegalArgumentException("Starting timeout must be greater than 0"); 144 if (multiplier <= 1.0) throw new IllegalArgumentException("Multiplier must be greater than 1"); 145 146 this.startTimeout = startTimeout; 147 this.multiplier = multiplier; 148 this.timeoutCap = timeoutCap; 149 } 150 151 @Override 152 public ConnectionHandler create(ConnectionHandler userConnectionHandler) { 153 return new ReconnectingConnectionHandler(userConnectionHandler, startTimeout, timeoutCap, 0, multiplier); 154 } 155 } 156}