001    /**
002     * Copyright (C) 2012 FuseSource, Inc.
003     * http://fusesource.com
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *    http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.fusesource.hawtdispatch.transport;
019    
020    import org.fusesource.hawtdispatch.DispatchQueue;
021    import org.fusesource.hawtdispatch.Task;
022    import org.fusesource.hawtdispatch.TaskWrapper;
023    
024    import java.util.LinkedList;
025    
026    /**
027     * <p>
028     * The BaseService provides helpers for dealing async service state.
029     * </p>
030     *
031     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
032     */
033    public abstract class ServiceBase {
034    
035        public static class State {
036            public String toString() {
037                return getClass().getSimpleName();
038            }
039            public boolean isStarted() {
040                return false;
041            }
042            public boolean isStarting() {
043                return false;
044            }
045        }
046    
047        static class CallbackSupport extends State {
048            LinkedList<Task> callbacks = new LinkedList<Task>();
049    
050            void add(Task r) {
051                if (r != null) {
052                    callbacks.add(r);
053                }
054            }
055    
056            void done() {
057                for (Task callback : callbacks) {
058                    callback.run();
059                }
060            }
061        }
062    
063        public static final State CREATED = new State();
064        public static class STARTING extends CallbackSupport {
065            public boolean isStarting() {
066                return true;
067            }
068        }
069        public static final State STARTED = new State() {
070            public boolean isStarted() {
071                return true;
072            }
073        };
074        public static class STOPPING extends CallbackSupport {
075        }
076    
077        public static final State STOPPED = new State();
078    
079    
080        protected State _serviceState = CREATED;
081    
082        final public void start(final Runnable onCompleted) {
083            start(new TaskWrapper(onCompleted));
084        }
085    
086        final public void start(final Task onCompleted) {
087            getDispatchQueue().execute(new Task() {
088                public void run() {
089                    if (_serviceState == CREATED ||
090                            _serviceState == STOPPED) {
091                        final STARTING state = new STARTING();
092                        state.add(onCompleted);
093                        _serviceState = state;
094                        _start(new Task() {
095                            public void run() {
096                                _serviceState = STARTED;
097                                state.done();
098                            }
099                        });
100                    } else if (_serviceState instanceof STARTING) {
101                        ((STARTING) _serviceState).add(onCompleted);
102                    } else if (_serviceState == STARTED) {
103                        if (onCompleted != null) {
104                            onCompleted.run();
105                        }
106                    } else {
107                        if (onCompleted != null) {
108                            onCompleted.run();
109                        }
110                        error("start should not be called from state: " + _serviceState);
111                    }
112                }
113            });
114        }
115    
116        final public void stop(final Runnable onCompleted) {
117            stop(new TaskWrapper(onCompleted));
118        }
119    
120        final public void stop(final Task onCompleted) {
121            getDispatchQueue().execute(new Task() {
122                public void run() {
123                    if (_serviceState == STARTED) {
124                        final STOPPING state = new STOPPING();
125                        state.add(onCompleted);
126                        _serviceState = state;
127                        _stop(new Task() {
128                            public void run() {
129                                _serviceState = STOPPED;
130                                state.done();
131                            }
132                        });
133                    } else if (_serviceState instanceof STOPPING) {
134                        ((STOPPING) _serviceState).add(onCompleted);
135                    } else if (_serviceState == STOPPED) {
136                        if (onCompleted != null) {
137                            onCompleted.run();
138                        }
139                    } else {
140                        if (onCompleted != null) {
141                            onCompleted.run();
142                        }
143                        error("stop should not be called from state: " + _serviceState);
144                    }
145                }
146            });
147        }
148    
149        private void error(String msg) {
150            try {
151                throw new AssertionError(msg);
152            } catch (Exception e) {
153                e.printStackTrace();
154            }
155        }
156    
157        protected State getServiceState() {
158            return _serviceState;
159        }
160    
161        abstract protected DispatchQueue getDispatchQueue();
162    
163        abstract protected void _start(Task onCompleted);
164    
165        abstract protected void _stop(Task onCompleted);
166    
167    }