/*
* Copyright 2016 The Simple File Server Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sfs;
import com.fasterxml.jackson.core.JsonFactory;
import io.vertx.core.Future;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpServer;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.sfs.auth.AuthProviderService;
import org.sfs.elasticsearch.Elasticsearch;
import org.sfs.encryption.AwsKms;
import org.sfs.encryption.AzureKms;
import org.sfs.encryption.ContainerKeys;
import org.sfs.encryption.MasterKeys;
import org.sfs.filesystem.temp.TempDirectoryCleaner;
import org.sfs.jobs.Jobs;
import org.sfs.nodes.ClusterInfo;
import org.sfs.nodes.NodeStats;
import org.sfs.nodes.Nodes;
import org.sfs.rx.Defer;
import org.sfs.rx.ObservableFuture;
import org.sfs.rx.RxHelper;
import org.sfs.rx.ToVoid;
import rx.Subscriber;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
public class SfsServer extends Server {
private static final Logger LOGGER = LoggerFactory.getLogger(SfsServer.class);
private static final String KEY = "sfs.server.delegate";
private VertxContext<Server> vertxContext;
private SfsSingletonServer delegate;
private HttpClient httpClient;
private HttpClient httpsClient;
private List<HttpServer> httpServers = new ArrayList<>();
public SfsServer() {
}
@Override
public void start(Future<Void> startedResult) {
SfsServer _this = this;
LOGGER.info("Starting verticle " + _this);
SfsSingletonServer candidate = new SfsSingletonServer();
if (setDelegate(candidate)) {
candidate.init(vertx, vertx.getOrCreateContext());
candidate.start(Future.future());
}
vertx.setPeriodic(100, event -> {
SfsSingletonServer server = getDelegate();
if (server != null && server.isStarted()) {
Throwable startException = server.getStartException();
vertx.cancelTimer(event);
if (startException == null) {
vertxContext = new VertxContext<Server>(this);
httpsClient = server.createHttpClient(vertx, true);
httpClient = server.createHttpClient(vertx, false);
server.initRxSchedulers(vertx);
server.initHttpListeners(vertxContext, true)
.doOnNext(httpServers1 -> httpServers.addAll(httpServers1))
.map(new ToVoid<>())
.subscribe(new Subscriber<Void>() {
@Override
public void onCompleted() {
LOGGER.info("Started verticle " + _this);
startedResult.complete();
}
@Override
public void onError(Throwable e) {
LOGGER.error("Failed to start verticle " + _this, e);
startedResult.fail(e);
}
@Override
public void onNext(Void aVoid) {
}
});
} else {
LOGGER.error("Failed to start verticle " + _this, startException);
startedResult.fail(startException);
}
}
});
}
@Override
public void stop(Future<Void> stoppedResult) {
SfsServer _this = this;
LOGGER.info("Stopping verticle " + _this);
SfsSingletonServer sfsSingletonServer = (SfsSingletonServer) vertx.sharedData().getLocalMap(KEY).remove("a");
if (sfsSingletonServer != null) {
sfsSingletonServer.stop(stoppedResult);
} else {
LOGGER.info("Stopped verticle " + _this);
Defer.aVoid()
.flatMap(aVoid ->
RxHelper.iterate(vertx, httpServers, httpServer -> {
ObservableFuture<Void> handler = RxHelper.observableFuture();
httpServer.close(handler.toHandler());
return handler
.onErrorResumeNext(throwable -> {
LOGGER.error("Unhandled Exception", throwable);
return Defer.aVoid();
})
.map(aVoid1 -> Boolean.TRUE);
}).map(new ToVoid<>()))
.subscribe(
aVoid -> {
// do nothing
},
throwable -> {
LOGGER.info("Failed to stop verticle " + _this, throwable);
stoppedResult.fail(throwable);
},
() -> {
LOGGER.info("Stopped verticle " + _this);
stoppedResult.complete();
});
}
}
protected boolean setDelegate(SfsSingletonServer sfsSingletonServer) {
return vertx.sharedData().getLocalMap(KEY).putIfAbsent("a", sfsSingletonServer) == null;
}
protected SfsSingletonServer getDelegate() {
if (delegate == null) {
delegate = (SfsSingletonServer) vertx.sharedData().getLocalMap(KEY).get("a");
}
return delegate;
}
@Override
public HttpClient httpClient(boolean https) {
return https ? httpsClient : httpClient;
}
@Override
public ExecutorService getBackgroundPool() {
return getDelegate().getBackgroundPool();
}
@Override
public ExecutorService getIoPool() {
return getDelegate().getIoPool();
}
@Override
public Elasticsearch elasticsearch() {
return getDelegate().elasticsearch();
}
@Override
public JsonFactory jsonFactory() {
return getDelegate().jsonFactory();
}
@Override
public Nodes nodes() {
return getDelegate().nodes();
}
@Override
public SfsFileSystem sfsFileSystem() {
return getDelegate().sfsFileSystem();
}
@Override
public TempDirectoryCleaner tempFileFactory() {
return getDelegate().tempFileFactory();
}
@Override
public Jobs jobs() {
return getDelegate().jobs();
}
@Override
public AuthProviderService authProviderService() {
return getDelegate().authProviderService();
}
@Override
public AwsKms awsKms() {
return getDelegate().awsKms();
}
@Override
public AzureKms azureKms() {
return getDelegate().azureKms();
}
@Override
public MasterKeys masterKeys() {
return getDelegate().masterKeys();
}
@Override
public ContainerKeys containerKeys() {
return getDelegate().containerKeys();
}
@Override
public ClusterInfo getClusterInfo() {
return getDelegate().getClusterInfo();
}
@Override
public NodeStats getNodeStats() {
return getDelegate().getNodeStats();
}
@Override
public byte[] getRemoteNodeSecret() {
return getDelegate().getRemoteNodeSecret();
}
@Override
public VertxContext<Server> vertxContext() {
return vertxContext;
}
}