/*
* Copyright 2011-2017 the original author or 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.glowroot.ui;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.base.Ticker;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.immutables.builder.Builder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.glowroot.common.config.EmbeddedWebConfig;
import org.glowroot.common.live.LiveAggregateRepository;
import org.glowroot.common.live.LiveJvmService;
import org.glowroot.common.live.LiveTraceRepository;
import org.glowroot.common.live.LiveWeavingService;
import org.glowroot.common.repo.AgentRepository;
import org.glowroot.common.repo.AggregateRepository;
import org.glowroot.common.repo.ConfigRepository;
import org.glowroot.common.repo.EnvironmentRepository;
import org.glowroot.common.repo.GaugeValueRepository;
import org.glowroot.common.repo.RepoAdmin;
import org.glowroot.common.repo.SyntheticResultRepository;
import org.glowroot.common.repo.TraceAttributeNameRepository;
import org.glowroot.common.repo.TraceRepository;
import org.glowroot.common.repo.TransactionTypeRepository;
import org.glowroot.common.repo.TriggeredAlertRepository;
import org.glowroot.common.repo.util.MailService;
import org.glowroot.common.repo.util.RollupLevelService;
import org.glowroot.common.util.Clock;
import static com.google.common.base.Preconditions.checkNotNull;
public class UiModule {
private static final Logger logger = LoggerFactory.getLogger(UiModule.class);
// non-null when using netty
private final @Nullable HttpServer httpServer;
// CommonHandler is non-null when using servlet container (applies to central only)
private final @Nullable CommonHandler commonHandler;
@Builder.Factory
public static UiModule createUiModule(
boolean central,
boolean servlet,
boolean offline,
@Nullable String bindAddress, // only used for central
@Nullable Integer port, // only used for central
@Nullable Boolean https, // only used for central
@Nullable String contextPath, // only used for central
File certificateDir,
File logDir,
@Nullable Ticker ticker, // @Nullable to deal with shading from glowroot server
Clock clock,
@Nullable LiveJvmService liveJvmService,
final ConfigRepository configRepository,
AgentRepository agentRepository,
EnvironmentRepository environmentRepository,
TransactionTypeRepository transactionTypeRepository,
AggregateRepository aggregateRepository,
TraceAttributeNameRepository traceAttributeNameRepository,
TraceRepository traceRepository,
GaugeValueRepository gaugeValueRepository,
@Nullable SyntheticResultRepository syntheticResultRepository, // null for embedded
TriggeredAlertRepository triggeredAlertRepository,
RepoAdmin repoAdmin,
RollupLevelService rollupLevelService,
LiveTraceRepository liveTraceRepository,
LiveAggregateRepository liveAggregateRepository,
@Nullable LiveWeavingService liveWeavingService,
SessionMapFactory sessionMapFactory,
int numWorkerThreads,
String version) throws Exception {
TransactionCommonService transactionCommonService = new TransactionCommonService(
aggregateRepository, liveAggregateRepository, configRepository, clock);
TraceCommonService traceCommonService =
new TraceCommonService(traceRepository, liveTraceRepository, agentRepository);
ErrorCommonService errorCommonService =
new ErrorCommonService(aggregateRepository, liveAggregateRepository);
MailService mailService = new MailService();
AdminJsonService adminJsonService = new AdminJsonService(central, certificateDir,
configRepository, repoAdmin, liveAggregateRepository, mailService);
List<Object> jsonServices = Lists.newArrayList();
jsonServices.add(new TransactionJsonService(transactionCommonService, aggregateRepository,
configRepository, rollupLevelService, clock));
jsonServices.add(new TracePointJsonService(traceRepository, liveTraceRepository,
configRepository, ticker, clock));
jsonServices.add(new TraceJsonService(traceCommonService));
jsonServices.add(new ErrorJsonService(errorCommonService, transactionCommonService,
traceRepository, rollupLevelService, clock));
jsonServices.add(new GaugeValueJsonService(gaugeValueRepository, rollupLevelService,
agentRepository, configRepository));
jsonServices.add(new JvmJsonService(environmentRepository, liveJvmService));
jsonServices.add(new AlertIncidentJsonService(triggeredAlertRepository,
configRepository));
jsonServices.add(new ConfigJsonService(agentRepository, configRepository));
jsonServices
.add(new AlertConfigJsonService(configRepository, gaugeValueRepository, central));
jsonServices.add(new AgentConfigJsonService(configRepository, agentRepository));
jsonServices.add(new UserConfigJsonService(configRepository));
jsonServices.add(new RoleConfigJsonService(central, configRepository, agentRepository));
jsonServices.add(new GaugeConfigJsonService(configRepository, liveJvmService));
jsonServices.add(new InstrumentationConfigJsonService(configRepository, liveWeavingService,
liveJvmService));
jsonServices.add(adminJsonService);
if (central) {
checkNotNull(syntheticResultRepository);
checkNotNull(triggeredAlertRepository);
jsonServices.add(new SyntheticResultJsonService(syntheticResultRepository,
rollupLevelService, configRepository));
jsonServices.add(new ReportJsonService(aggregateRepository, agentRepository,
gaugeValueRepository));
jsonServices.add(new SyntheticMonitorConfigJsonService(configRepository));
}
LayoutService layoutService =
new LayoutService(central, servlet, offline, version, configRepository,
agentRepository, transactionTypeRepository, traceAttributeNameRepository);
HttpSessionManager httpSessionManager = new HttpSessionManager(central, offline,
configRepository, clock, layoutService, sessionMapFactory);
IndexHtmlHttpService indexHtmlHttpService = new IndexHtmlHttpService(layoutService);
TraceDetailHttpService traceDetailHttpService =
new TraceDetailHttpService(traceCommonService);
TraceExportHttpService traceExportHttpService =
new TraceExportHttpService(traceCommonService, version);
GlowrootLogHttpService glowrootLogHttpService = new GlowrootLogHttpService(logDir);
Map<Pattern, HttpService> httpServices = Maps.newHashMap();
// http services
httpServices.put(Pattern.compile("^/$"), indexHtmlHttpService);
httpServices.put(Pattern.compile("^/transaction/.*$"), indexHtmlHttpService);
httpServices.put(Pattern.compile("^/error/.*$"), indexHtmlHttpService);
httpServices.put(Pattern.compile("^/jvm/.*$"), indexHtmlHttpService);
httpServices.put(Pattern.compile("^/config/.*$"), indexHtmlHttpService);
httpServices.put(Pattern.compile("^/admin/.*$"), indexHtmlHttpService);
httpServices.put(Pattern.compile("^/profile/.*$"), indexHtmlHttpService);
httpServices.put(Pattern.compile("^/login$"), indexHtmlHttpService);
// export service is not bound under /backend since the export url is visible to users
// as the download url for the export file
httpServices.put(Pattern.compile("^/export/trace$"), traceExportHttpService);
httpServices.put(Pattern.compile("^/backend/trace/entries$"), traceDetailHttpService);
httpServices.put(Pattern.compile("^/backend/trace/main-thread-profile$"),
traceDetailHttpService);
httpServices.put(Pattern.compile("^/backend/trace/aux-thread-profile$"),
traceDetailHttpService);
httpServices.put(Pattern.compile("^/log$"), glowrootLogHttpService);
if (central) {
httpServices.put(Pattern.compile("^/synthetic-monitors$"), indexHtmlHttpService);
httpServices.put(Pattern.compile("^/alerts$"), indexHtmlHttpService);
httpServices.put(Pattern.compile("^/report/.*$"), indexHtmlHttpService);
}
CommonHandler commonHandler = new CommonHandler(layoutService, httpServices,
httpSessionManager, jsonServices, clock);
if (servlet) {
return new UiModule(commonHandler);
} else {
HttpServer httpServer;
int initialPort;
if (central) {
httpServer = new HttpServer(checkNotNull(bindAddress), checkNotNull(https),
Suppliers.ofInstance(checkNotNull(contextPath)), numWorkerThreads,
commonHandler, certificateDir);
initialPort = checkNotNull(port);
} else {
final EmbeddedWebConfig initialWebConfig = configRepository.getEmbeddedWebConfig();
Supplier<String> contextPathSupplier = new Supplier<String>() {
@Override
public String get() {
try {
return configRepository.getEmbeddedWebConfig().contextPath();
} catch (Exception e) {
logger.error(e.getMessage(), e);
return initialWebConfig.contextPath();
}
}
};
httpServer = new HttpServer(initialWebConfig.bindAddress(),
initialWebConfig.https(), contextPathSupplier, numWorkerThreads,
commonHandler, certificateDir);
initialPort = initialWebConfig.port();
}
adminJsonService.setHttpServer(httpServer);
httpServer.bindEventually(initialPort);
return new UiModule(httpServer);
}
}
private UiModule(HttpServer httpServer) {
this.httpServer = httpServer;
commonHandler = null;
}
private UiModule(CommonHandler commonHandler) {
this.commonHandler = commonHandler;
httpServer = null;
}
public CommonHandler getCommonHandler() {
// only called when using servlet container
return checkNotNull(commonHandler);
}
// used by tests and by central ui
public void close(boolean waitForChannelClose) throws InterruptedException {
if (httpServer != null) {
httpServer.close(waitForChannelClose);
}
}
}