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
018package org.fusesource.hawtdispatch.transport;
019
020import org.fusesource.hawtdispatch.DispatchQueue;
021import org.fusesource.hawtdispatch.Task;
022import org.fusesource.hawtdispatch.TaskWrapper;
023
024import 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 */
033public 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}