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}