source: java/main/src/main/java/com/framsticks/hosting/Server.java @ 193

Last change on this file since 193 was 193, checked in by Maciej Komosinski, 10 years ago

Set svn:eol-style native for all textual files

  • Property svn:eol-style set to native
File size: 4.8 KB
Line 
1package com.framsticks.hosting;
2
3import org.apache.logging.log4j.Level;
4import org.apache.logging.log4j.Logger;
5import org.apache.logging.log4j.LogManager;
6
7import com.framsticks.params.ParamFlags;
8import com.framsticks.params.annotations.AutoAppendAnnotation;
9import com.framsticks.params.annotations.FramsClassAnnotation;
10import com.framsticks.params.annotations.ParamAnnotation;
11import com.framsticks.structure.Tree;
12import com.framsticks.util.FramsticksException;
13import com.framsticks.util.dispatching.AbstractJoinable;
14import com.framsticks.util.dispatching.Dispatching;
15import com.framsticks.util.dispatching.Joinable;
16import com.framsticks.util.dispatching.JoinableCollection;
17import com.framsticks.util.dispatching.JoinableParent;
18import com.framsticks.util.dispatching.JoinableState;
19import com.framsticks.util.dispatching.RunAt;
20import com.framsticks.util.dispatching.ThrowExceptionHandler;
21
22import java.io.IOException;
23import java.net.InetSocketAddress;
24import java.net.ServerSocket;
25import java.net.Socket;
26import java.util.TimerTask;
27
28import com.framsticks.util.dispatching.Thread;
29
30@FramsClassAnnotation
31public class Server extends AbstractJoinable implements JoinableParent {
32
33        private final static Logger log = LogManager.getLogger(Server.class);
34
35        protected int port;
36
37        protected ServerSocket acceptSocket;
38        protected Tree hosted;
39        protected final JoinableCollection<ClientAtServer> clients = new JoinableCollection<ClientAtServer>(JoinableCollection.FinishPolicy.Never);
40
41        public static class Accept {
42        };
43
44        protected Thread<Accept> acceptThread = new Thread<>();
45
46        /**
47         *
48         */
49        public Server() {
50                log.debug("created server");
51                port = 9009;
52        }
53
54        /**
55         * @return the port
56         */
57        @ParamAnnotation
58        public int getPort() {
59                return port;
60        }
61
62        /**
63         * @param port the port to set
64         */
65        @ParamAnnotation(flags = ParamFlags.USERREADONLY)
66        public void setPort(int port) {
67                this.port = port;
68        }
69
70
71        /**
72         * @return the hosted
73         */
74        public Tree getHosted() {
75                return hosted;
76        }
77
78        @AutoAppendAnnotation
79        public void setHosted(Tree hosted) {
80                if (this.hosted != null) {
81                        throw new FramsticksException().msg("hosted tree is already set").arg("current", this.hosted);
82                }
83                this.hosted = hosted;
84                acceptThread.setName(hosted.getName() + " acceptor");
85                clients.setObservableName(hosted.getName() + " clients");
86        }
87
88        @Override
89        public void childChangedState(Joinable joinable, JoinableState state) {
90                proceedToState(state);
91        }
92
93        @Override
94        @ParamAnnotation
95        public String getName() {
96                return hosted != null ? hosted.getName() : "server";
97        }
98
99        protected void acceptNext() {
100                if (!isRunning()) {
101                        log.debug("server is not in running state, aborting accepting");
102                        return;
103                }
104                acceptThread.dispatch(new RunAt<Accept>(hosted) {
105                        @Override
106                        protected void runAt() {
107                                try {
108                                        log.debug("accepting");
109                                        final Socket socket = acceptSocket.accept();
110                                        assert socket != null;
111                                        log.debug("accepted socket: {}", socket.getInetAddress().getHostAddress());
112                                        hosted.dispatch(new RunAt<Tree>(this) {
113                                                @Override
114                                                protected void runAt() {
115                                                        ClientAtServer client = new ClientAtServer(Server.this, socket);
116                                                        clients.add(client);
117                                                        log.info("client connected: {}", client);
118                                                }
119                                        });
120                                } catch (IOException e) {
121                                        log.log((isRunning() ? Level.ERROR : Level.DEBUG), "failed to accept socket: {}", e);
122                                }
123                                acceptNext();
124                        }
125                });
126        }
127
128        protected void tryBind(int when) {
129                Dispatching.getTimer().schedule(new TimerTask() {
130
131                        @Override
132                        public void run() {
133                                acceptThread.dispatch(new RunAt<Accept>(ThrowExceptionHandler.getInstance()) {
134                                        @Override
135                                        protected void runAt() {
136                                                try {
137                                                        acceptSocket.bind(new InetSocketAddress(port));
138                                                        log.debug("started accepting on port {}", port);
139                                                        acceptNext();
140                                                        return;
141                                                } catch (IOException e) {
142                                                        log.warn("failed to accept on port {} (repeating): ", port, e);
143                                                }
144                                                tryBind(1000);
145                                        }
146                                });
147                        }
148
149                }, when);
150        }
151
152
153        @Override
154        protected void joinableStart() {
155                Dispatching.use(acceptThread, this);
156                Dispatching.use(hosted, this);
157                Dispatching.use(clients, this);
158                try {
159                        acceptSocket = new ServerSocket();
160                        acceptSocket.setReuseAddress(true);
161                } catch (IOException e) {
162                        throw new FramsticksException().msg("failed to create server socket").cause(e);
163                }
164                tryBind(0);
165        }
166
167        @Override
168        protected void joinableInterrupt() {
169                Dispatching.drop(acceptThread, this);
170                Dispatching.drop(hosted, this);
171                Dispatching.drop(clients, this);
172
173                try {
174                        acceptSocket.close();
175                } catch (IOException e) {
176                        log.debug("exception caught during socket closing: ", e);
177                }
178
179                finishJoinable();
180        }
181
182        @Override
183        protected void joinableFinish() {
184
185        }
186
187        @Override
188        protected void joinableJoin() throws InterruptedException {
189                Dispatching.join(acceptThread);
190                Dispatching.join(hosted);
191                Dispatching.join(clients);
192        }
193
194}
Note: See TracBrowser for help on using the repository browser.