Java tutorial
/* * Copyright 2015-2016 Red Hat, Inc, and individual contributors. * * 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 * * https://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.jboss.hal.client.runtime; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import javax.inject.Provider; import com.google.common.base.Strings; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.web.bindery.event.shared.EventBus; import com.gwtplatform.mvp.shared.proxy.PlaceRequest; import elemental2.dom.Element; import elemental2.dom.HTMLDivElement; import elemental2.dom.HTMLElement; import elemental2.dom.HTMLTableCellElement; import elemental2.dom.HTMLTableColElement; import elemental2.dom.HTMLTableElement; import elemental2.dom.HTMLTableSectionElement; import elemental2.dom.MouseEvent; import elemental2.dom.NodeList; import org.jboss.gwt.elemento.core.Elements; import org.jboss.gwt.elemento.core.EventCallbackFn; import org.jboss.gwt.elemento.core.builder.HtmlContentBuilder; import org.jboss.hal.ballroom.Format; import org.jboss.hal.ballroom.LabelBuilder; import org.jboss.hal.client.runtime.server.ServerStatusSwitch; import org.jboss.hal.config.Environment; import org.jboss.hal.core.finder.FinderPath; import org.jboss.hal.core.finder.FinderPathFactory; import org.jboss.hal.core.finder.PreviewAttributes; import org.jboss.hal.core.finder.PreviewAttributes.PreviewAttribute; import org.jboss.hal.core.finder.PreviewContent; import org.jboss.hal.core.finder.StaticItem; import org.jboss.hal.core.mvp.Places; import org.jboss.hal.core.runtime.TopologyTasks; import org.jboss.hal.core.runtime.group.ServerGroup; import org.jboss.hal.core.runtime.group.ServerGroupActionEvent; import org.jboss.hal.core.runtime.group.ServerGroupActionEvent.ServerGroupActionHandler; import org.jboss.hal.core.runtime.group.ServerGroupActions; import org.jboss.hal.core.runtime.group.ServerGroupResultEvent; import org.jboss.hal.core.runtime.group.ServerGroupResultEvent.ServerGroupResultHandler; import org.jboss.hal.core.runtime.host.Host; import org.jboss.hal.core.runtime.host.HostActionEvent; import org.jboss.hal.core.runtime.host.HostActionEvent.HostActionHandler; import org.jboss.hal.core.runtime.host.HostActions; import org.jboss.hal.core.runtime.host.HostResultEvent; import org.jboss.hal.core.runtime.host.HostResultEvent.HostResultHandler; import org.jboss.hal.core.runtime.server.Server; import org.jboss.hal.core.runtime.server.ServerActionEvent; import org.jboss.hal.core.runtime.server.ServerActionEvent.ServerActionHandler; import org.jboss.hal.core.runtime.server.ServerActions; import org.jboss.hal.core.runtime.server.ServerResultEvent; import org.jboss.hal.core.runtime.server.ServerResultEvent.ServerResultHandler; import org.jboss.hal.dmr.ModelNode; import org.jboss.hal.dmr.NamedNode; import org.jboss.hal.dmr.dispatch.Dispatcher; import org.jboss.hal.flow.FlowContext; import org.jboss.hal.flow.Outcome; import org.jboss.hal.flow.Progress; import org.jboss.hal.meta.AddressTemplate; import org.jboss.hal.meta.security.AuthorisationDecision; import org.jboss.hal.meta.security.Constraint; import org.jboss.hal.meta.security.Constraints; import org.jboss.hal.meta.security.SecurityContextRegistry; import org.jboss.hal.meta.token.NameTokens; import org.jboss.hal.resources.CSS; import org.jboss.hal.resources.Ids; import org.jboss.hal.resources.Names; import org.jboss.hal.resources.Resources; import org.jboss.hal.resources.UIConstants; import org.jboss.hal.spi.Message; import org.jboss.hal.spi.MessageEvent; import static com.google.common.collect.Lists.asList; import static elemental2.dom.DomGlobal.clearTimeout; import static elemental2.dom.DomGlobal.document; import static elemental2.dom.DomGlobal.setTimeout; import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toList; import static org.jboss.gwt.elemento.core.Elements.*; import static org.jboss.gwt.elemento.core.EventType.click; import static org.jboss.hal.dmr.ModelDescriptionConstants.*; import static org.jboss.hal.flow.Flow.series; import static org.jboss.hal.resources.CSS.*; class TopologyPreview extends PreviewContent<StaticItem> implements HostActionHandler, HostResultHandler, ServerGroupActionHandler, ServerGroupResultHandler, ServerActionHandler, ServerResultHandler { private static final String DOT = "."; private static final String CONTAINER = "container"; private final SecurityContextRegistry securityContextRegistry; private final Environment environment; private final Dispatcher dispatcher; private final Provider<Progress> progress; private final EventBus eventBus; private final Places places; private final HostActions hostActions; private final ServerGroupActions serverGroupActions; private final ServerActions serverActions; private final Resources resources; private final HTMLElement loadingSection; private final HTMLElement topologySection; private final HTMLElement hostAttributesSection; private final HTMLElement serverGroupAttributesSection; private final HTMLElement serverAttributesSection; private final PreviewAttributes<ServerGroup> serverGroupAttributes; private final PreviewAttributes<Host> hostAttributes; private final PreviewAttributes<Server> serverAttributes; private final HTMLElement serverUrl; private final LabelBuilder labelBuilder; TopologyPreview(SecurityContextRegistry securityContextRegistry, Environment environment, Dispatcher dispatcher, Provider<Progress> progress, EventBus eventBus, Places places, FinderPathFactory finderPathFactory, HostActions hostActions, ServerGroupActions serverGroupActions, ServerActions serverActions, Resources resources) { super(Names.TOPOLOGY, resources.previews().runtimeTopology()); this.securityContextRegistry = securityContextRegistry; this.environment = environment; this.dispatcher = dispatcher; this.progress = progress; this.eventBus = eventBus; this.places = places; this.hostActions = hostActions; this.serverGroupActions = serverGroupActions; this.serverActions = serverActions; this.resources = resources; this.labelBuilder = new LabelBuilder(); eventBus.addHandler(HostActionEvent.getType(), this); eventBus.addHandler(HostResultEvent.getType(), this); eventBus.addHandler(ServerGroupActionEvent.getType(), this); eventBus.addHandler(ServerGroupResultEvent.getType(), this); eventBus.addHandler(ServerActionEvent.getType(), this); eventBus.addHandler(ServerResultEvent.getType(), this); previewBuilder() .add(p().add(a().css(clickable, pullRight).on(click, event -> update(null)) .add(span().css(fontAwesome("refresh"), marginRight5)) .add(span().textContent(resources.constants().refresh())))) .add(loadingSection = section().css(centerBlock) .add(p().textContent(resources.constants().loading())).add(div().css(spinner, spinnerLg)) .get()) .add(topologySection = section().get()); hostAttributes = new PreviewAttributes<>(new Host(new ModelNode()), Names.HOST).append(model -> { String token = lazyToken(NameTokens.RUNTIME, model, ModelNode::isDefined, m -> finderPathFactory.runtimeHostPath(m.getAddressName())); return new PreviewAttribute(Names.NAME, model.getName(), token); }).append(RELEASE_CODENAME).append(RELEASE_VERSION).append(PRODUCT_NAME).append(PRODUCT_VERSION) .append(HOST_STATE).append(RUNNING_MODE) .append(model -> new PreviewAttribute(labelBuilder.label(MANAGEMENT_VERSION), String.join(DOT, model.get(MANAGEMENT_MAJOR_VERSION).asString(), model.get(MANAGEMENT_MINOR_VERSION).asString(), model.get(MANAGEMENT_MICRO_VERSION).asString()))) .append(model -> new PreviewAttribute(labelBuilder.label(LAST_CONNECTED), model.getLastConnected() != null ? Format.mediumDateTime(model.getLastConnected()) : Names.NOT_AVAILABLE)) .append(model -> new PreviewAttribute(labelBuilder.label(DISCONNECTED), model.getLastConnected() != null ? Format.mediumDateTime(model.getDisconnected()) : Names.NOT_AVAILABLE)); serverGroupAttributes = new PreviewAttributes<>(new ServerGroup("", new ModelNode()), Names.SERVER_GROUP) .append(model -> { String token = lazyToken(NameTokens.RUNTIME, model, ModelNode::isDefined, m -> finderPathFactory.runtimeServerGroupPath(m.getName())); return new PreviewAttribute(Names.NAME, model.getName(), token); }).append(model -> { String token = lazyToken(NameTokens.CONFIGURATION, model, ModelNode::isDefined, m -> new FinderPath().append(Ids.CONFIGURATION, Ids.asId(Names.PROFILES)) .append(Ids.PROFILE, m.getProfile())); return new PreviewAttribute(Names.PROFILE, model.getProfile(), token); }).append(model -> { String token = lazyToken(NameTokens.CONFIGURATION, model, ModelNode::isDefined, m -> new FinderPath().append(Ids.CONFIGURATION, Ids.asId(Names.SOCKET_BINDINGS)) .append(Ids.SOCKET_BINDING_GROUP, model.get(SOCKET_BINDING_GROUP).asString())); return new PreviewAttribute(Names.SOCKET_BINDING_GROUP, model.get(SOCKET_BINDING_GROUP).asString(), token); }).append(SOCKET_BINDING_PORT_OFFSET).append(SOCKET_BINDING_DEFAULT_INTERFACE); serverUrl = span().textContent(Names.NOT_AVAILABLE).get(); serverAttributes = new PreviewAttributes<>(new Server("", new ModelNode()), Names.SERVER).append(model -> { String token = lazyToken(NameTokens.RUNTIME, model, m -> !Strings.isNullOrEmpty(m.getHost()), m -> finderPathFactory.runtimeServerPath(model.getHost(), model.getName())); return new PreviewAttribute(Names.NAME, model.getName(), token); }).append(model -> { String token = lazyToken(NameTokens.RUNTIME, model, m -> !Strings.isNullOrEmpty(m.getHost()), m -> finderPathFactory.runtimeHostPath(model.getHost())); return new PreviewAttribute(Names.HOST, model.getHost(), token); }).append(model -> { String token = lazyToken(NameTokens.RUNTIME, model, m -> !Strings.isNullOrEmpty(m.getHost()), m -> finderPathFactory.runtimeServerGroupPath(model.getServerGroup())); return new PreviewAttribute(Names.SERVER_GROUP, model.getServerGroup(), token); }).append(model -> { String token = lazyToken(NameTokens.CONFIGURATION, model, m -> !Strings.isNullOrEmpty(m.getHost()), m -> new FinderPath().append(Ids.CONFIGURATION, Ids.asId(Names.PROFILES)).append(Ids.PROFILE, model.get(PROFILE_NAME).asString())); return new PreviewAttribute(Names.PROFILE, model.get(PROFILE_NAME).asString(), token); }).append(model -> new PreviewAttribute(Names.URL, serverUrl)).append(AUTO_START) .append(SOCKET_BINDING_PORT_OFFSET).append(STATUS).append(RUNNING_MODE).append(SERVER_STATE) .append(SUSPEND_STATE); previewBuilder().add(hostAttributesSection = section().addAll(hostAttributes).get()) .add(serverGroupAttributesSection = section().addAll(serverGroupAttributes).get()) .add(serverAttributesSection = section().addAll(serverAttributes).get()); } private <T extends NamedNode> String lazyToken(String tlc, T model, Predicate<T> defined, Function<T, FinderPath> path) { String token = ""; if (defined.test(model)) { PlaceRequest placeRequest = places.finderPlace(tlc, path.apply(model)).build(); token = places.historyToken(placeRequest); } return token; } // ------------------------------------------------------ dmr functions @Override @SuppressWarnings("HardCodedStringLiteral") public void update(StaticItem item) { // remember selection HTMLElement element = (HTMLElement) document.querySelector(DOT + topology + " ." + selected); String hostName = element != null ? String.valueOf(element.dataset.get("host")) : null; String serverGroupName = element != null ? String.valueOf(element.dataset.get("serverGroup")) : null; String serverName = element != null ? String.valueOf(element.dataset.get("server")) : null; clearSelected(); Elements.setVisible(loadingSection, false); Elements.setVisible(topologySection, false); hideDetails(); // show the loading indicator if the dmr operation takes too long double timeoutHandle = setTimeout((o) -> Elements.setVisible(loadingSection, true), UIConstants.MEDIUM_TIMEOUT); series(new FlowContext(progress.get()), new TopologyTasks.Topology(environment, dispatcher), new TopologyTasks.TopologyStartedServers(environment, dispatcher)) .subscribe(new Outcome<FlowContext>() { @Override public void onError(FlowContext context, Throwable error) { clearTimeout(timeoutHandle); Elements.setVisible(loadingSection, false); MessageEvent.fire(eventBus, Message.error(resources.messages().topologyError(), error.getMessage())); } @Override public void onSuccess(FlowContext context) { clearTimeout(timeoutHandle); Elements.setVisible(loadingSection, false); Elements.removeChildrenFrom(topologySection); List<Host> hosts = context.get(TopologyTasks.HOSTS); List<ServerGroup> serverGroups = context.get(TopologyTasks.SERVER_GROUPS); List<Server> servers = context.get(TopologyTasks.SERVERS); topologySection.appendChild(buildTable(hosts, serverGroups, servers)); Elements.setVisible(topologySection, true); adjustTdHeight(); // restore selection if (hostName != null) { hosts.stream().filter(host -> hostName.equals(host.getName())).findAny() .ifPresent(host -> hostDetails(host)); } if (serverGroupName != null) { serverGroups.stream() .filter(serverGroup -> serverGroupName.equals(serverGroup.getName())) .findAny().ifPresent(serverGroup -> serverGroupDetails(serverGroup)); } if (serverName != null) { servers.stream().filter(server -> serverName.equals(server.getName())).findAny() .ifPresent(server -> serverDetails(server)); } } }); } private void updateServer(Server server) { series(new FlowContext(progress.get()), // TODO Include function to read server boot errors new TopologyTasks.HostWithServerConfigs(server.getHost(), dispatcher), new TopologyTasks.HostStartedServers(dispatcher), new TopologyTasks.ServerGroupWithServerConfigs(server.getServerGroup(), dispatcher), new TopologyTasks.ServerGroupStartedServers(dispatcher)).subscribe(new Outcome<FlowContext>() { @Override public void onError(FlowContext context, Throwable error) { MessageEvent.fire(eventBus, Message.error( resources.messages().updateServerError(server.getName()), error.getMessage())); } @Override public void onSuccess(FlowContext context) { Host host = context.get(TopologyTasks.HOST); ServerGroup serverGroup = context.get(TopologyTasks.SERVER_GROUP); if (host != null && serverGroup != null) { // Does not matter where we take the updated server from (must be included in both // host and server group) host.getServers().stream().filter(srv -> srv.getId().equals(server.getId())).findAny() .ifPresent(updatedServer -> { String updatedContainerId = Ids.build(updatedServer.getId(), CONTAINER); replaceElement(document.getElementById(updatedContainerId), () -> serverElement(updatedServer), whatever -> serverDetails(updatedServer)); }); // Update not only the server, but also the host and server group elements. Since the // server's state has changed the host and server group dropdown links need to be updated // as well. replaceElement(document.querySelector(hostSelector(host)), () -> hostElement(host), whatever -> hostDetails(host)); replaceElement(document.querySelector(serverGroupSelector(serverGroup)), () -> serverGroupElement(serverGroup), updatedElement -> serverGroupDetails(serverGroup)); } } }); } // ------------------------------------------------------ UI methods @SuppressWarnings("HardCodedStringLiteral") private HTMLElement buildTable(List<Host> hosts, List<ServerGroup> serverGroups, List<Server> servers) { HTMLTableElement table = table().css(topology).get(); // <colgroup> double width = 100.0 / (serverGroups.size() + 1); HtmlContentBuilder<HTMLTableColElement> colgroup = colgroup().add(col().attr("width", width + "%")); for (int i = 0; i < serverGroups.size(); i++) { colgroup.add(col().attr("width", width + "%")); } table.appendChild(colgroup.get()); // </colgroup> // <thead> HtmlContentBuilder<HTMLTableSectionElement> thead = thead().add(tr() .add(th().css(empty) .innerHtml(new SafeHtmlBuilder().appendEscaped(Names.SERVER_GROUPS + " ") .appendHtmlConstant("→").appendHtmlConstant("<br/>") .appendEscaped(Names.HOSTS + " ").appendHtmlConstant("↓").toSafeHtml())) .addAll(serverGroups.stream().map(this::serverGroupElement).collect(toList()))); table.appendChild(thead.get()); // </thead> HTMLElement tbody = tbody().get(); for (Host host : hosts) { HTMLElement tr; tbody.appendChild(tr = tr().get()); tr.appendChild(hostElement(host)); for (ServerGroup serverGroup : serverGroups) { List<HTMLElement> matchingServers = servers.stream() .filter(sc -> host.getName().equals(sc.getHost()) && serverGroup.getName().equals(sc.getServerGroup())) .sorted(comparing(Server::getName)).map(this::serverElement).collect(toList()); if (matchingServers.isEmpty()) { tr.appendChild(td().css(empty).get()); } else { tr.appendChild(td().add(div().css(CSS.servers).addAll(matchingServers)).get()); } } } table.appendChild(tbody); // </tbody> return table; } private HTMLElement hostElement(Host host) { HTMLElement dropdown; HTMLTableCellElement th = th().css(asList(rowHeader, statusCss(host)).toArray(new String[] {})) .on(click, event -> hostDetails(host)).data("host", host.getName()) //NON-NLS .add(div().css(hostContainer).add(dropdown = div().css(CSS.dropdown).get())).get(); HTMLElement hostNameElement; if (host.isConnected() && host.hasServers() && !hostActions.isPending(host) && isAllowed(host)) { String hostDropDownId = Ids.host(host.getAddressName()); dropdown.appendChild(hostNameElement = a().id(hostDropDownId).css(clickable, dropdownToggle, name) .data(UIConstants.TOGGLE, UIConstants.DROPDOWN).aria(UIConstants.HAS_POPUP, UIConstants.TRUE) .title(host.getName()).get()); dropdown.appendChild(ul().css(dropdownMenu).attr(UIConstants.ROLE, UIConstants.MENU) .aria(UIConstants.LABELLED_BY, hostDropDownId).addAll(hostActions(host)).get()); } else { dropdown.appendChild(hostNameElement = span().css(name).title(host.getName()).get()); } hostNameElement.appendChild(hostNameElement.ownerDocument.createTextNode(host.getName())); if (!host.isConnected()) { hostNameElement.classList.add(disconnected); hostNameElement.title = hostNameElement.title + " (" + resources.constants().disconnected() + ")"; } if (host.isDomainController()) { hostNameElement .appendChild(span().css(fontAwesome("star"), marginLeft5).title(Names.DOMAIN_CONTROLLER).get()); } return th; } private HTMLElement serverGroupElement(ServerGroup serverGroup) { HTMLElement dropdown; HTMLTableCellElement element = th().on(click, event -> serverGroupDetails(serverGroup)) .data("serverGroup", serverGroup.getName()) //NON-NLS .add(div().css(serverGroupContainer).add(dropdown = div().css(CSS.dropdown).get())).get(); if (!serverGroupActions.isPending(serverGroup) && isAllowed(serverGroup)) { String serverGroupDropDownId = Ids.serverGroup(serverGroup.getName()); dropdown.appendChild(a().id(serverGroupDropDownId).css(clickable, dropdownToggle, name) .data(UIConstants.TOGGLE, UIConstants.DROPDOWN).aria(UIConstants.HAS_POPUP, UIConstants.TRUE) .title(serverGroup.getName()).textContent(serverGroup.getName()).get()); dropdown.appendChild(ul().css(dropdownMenu).attr(UIConstants.ROLE, UIConstants.MENU) .aria(UIConstants.LABELLED_BY, serverGroupDropDownId).addAll(serverGroupActions(serverGroup)) .get()); } else { dropdown.appendChild( span().css(name).title(serverGroup.getName()).textContent(serverGroup.getName()).get()); } return element; } private HTMLElement serverElement(Server srv) { HTMLElement dropdown; HTMLDivElement element = div().id(Ids.build(srv.getId(), CONTAINER)) .css(asList(server, statusCss(srv)).toArray(new String[] {})).data(SERVER, srv.getId()) .on(click, event -> serverDetails(srv)).add(dropdown = div().css(CSS.dropdown).get()).get(); if (!serverActions.isPending(srv) && isAllowed(srv)) { dropdown.appendChild(a().id(srv.getId()).css(clickable, dropdownToggle, name) .data(UIConstants.TOGGLE, UIConstants.DROPDOWN).aria(UIConstants.HAS_POPUP, UIConstants.TRUE) .title(srv.getName()).textContent(srv.getName()).get()); dropdown.appendChild(ul().css(dropdownMenu).attr(UIConstants.ROLE, UIConstants.MENU) .aria(UIConstants.LABELLED_BY, srv.getId()).addAll(serverActions(srv)).get()); } else { dropdown.appendChild(span().css(name).title(srv.getName()).textContent(srv.getName()).get()); } return element; } private void replaceElement(Element existingElement, Supplier<Element> updateElement, Consumer<Element> select) { if (existingElement != null) { boolean hasSelection = existingElement.classList.contains(selected); Element parent = (Element) existingElement.parentNode; if (parent != null) { Element updatedElement = updateElement.get(); parent.replaceChild(updatedElement, existingElement); if (hasSelection && select != null) { select.accept(updatedElement); } } } } private void adjustTdHeight() { NodeList<Element> servers = document.querySelectorAll(DOT + topology + " ." + CSS.servers); Elements.stream(servers).filter(htmlElements()).map(asHtmlElement()).forEach(element -> { HTMLElement parent = (HTMLElement) element.parentNode; element.style.height = height(px(parent.offsetHeight - 1)); }); } private void hideDetails() { Elements.setVisible(serverGroupAttributesSection, false); Elements.setVisible(hostAttributesSection, false); Elements.setVisible(serverAttributesSection, false); } private void clearSelected() { NodeList<Element> selectedNodes = document.querySelectorAll(DOT + topology + " ." + selected); Elements.elements(selectedNodes).forEach(element -> element.classList.remove(selected)); } private HTMLElement actionLink(EventCallbackFn<MouseEvent> listener, String text) { return li().attr(UIConstants.ROLE, UIConstants.PRESENTATION) .add(a().css(clickable).on(click, listener).textContent(text)).get(); } private void startProgress(String selector) { Elements.stream(document.querySelectorAll(selector)) .forEach(element -> element.classList.add(withProgress)); } private void stopProgress(String selector) { Elements.stream(document.querySelectorAll(selector)) .forEach(element -> element.classList.remove(withProgress)); } private void disableDropdown(String id, String name) { Element link = document.getElementById(id); if (link != null) { Element parent = (Element) link.parentNode; Element ul = link.nextElementSibling; if (parent != null && ul != null) { HTMLElement noLink = span().css(CSS.name).title(name).textContent(name).get(); parent.classList.remove("opened"); //NON-NLS parent.replaceChild(noLink, link); parent.removeChild(ul); } } } private boolean isVisible() { return Elements.isVisible(topologySection) && topologySection.parentNode != null; } // ------------------------------------------------------ host private void hostDetails(Host host) { clearSelected(); HTMLElement element = (HTMLElement) document.querySelector(hostSelector(host)); if (element != null) { element.classList.add(selected); } hostAttributes.refresh(host); hostAttributes.setVisible(RELEASE_CODENAME, host.isConnected()); hostAttributes.setVisible(RELEASE_VERSION, host.isConnected()); hostAttributes.setVisible(PRODUCT_NAME, host.isConnected()); hostAttributes.setVisible(PRODUCT_VERSION, host.isConnected()); hostAttributes.setVisible(HOST_STATE, host.isConnected() && hostActions.isPending(host)); hostAttributes.setVisible(RUNNING_MODE, host.isConnected() && hostActions.isPending(host)); hostAttributes.setVisible(labelBuilder.label(MANAGEMENT_VERSION), host.isConnected()); hostAttributes.setVisible(labelBuilder.label(LAST_CONNECTED), !host.isConnected()); hostAttributes.setVisible(labelBuilder.label(DISCONNECTED), !host.isConnected()); Elements.setVisible(serverGroupAttributesSection, false); Elements.setVisible(hostAttributesSection, true); Elements.setVisible(serverAttributesSection, false); } private boolean isAllowed(Host host) { // To keep it simple, we take a all or nothing approach: // We check *one* action and assume that the other actions have the same constraints return AuthorisationDecision.from(environment, securityContextRegistry) .isAllowed(Constraint.executable(AddressTemplate.of("/host=" + host.getAddressName()), RELOAD)); } private List<HTMLElement> hostActions(Host host) { List<HTMLElement> actions = new ArrayList<>(); actions.add(actionLink(event -> hostActions.reload(host), resources.constants().reload())); actions.add(actionLink(event -> hostActions.restart(host), resources.constants().restart())); return actions; } private String[] statusCss(Host host) { return hostActions.isPending(host) ? new String[] { withProgress } : new String[] {}; } @Override public void onHostAction(HostActionEvent event) { if (isVisible()) { Host host = event.getHost(); disableDropdown(Ids.host(host.getAddressName()), host.getName()); startProgress(hostSelector(host)); event.getServers().forEach(server -> { disableDropdown(server.getId(), server.getName()); startProgress(serverSelector(server)); }); } } @Override public void onHostResult(HostResultEvent event) { if (isVisible()) { Host host = event.getHost(); stopProgress(hostSelector(host)); event.getServers().forEach(server -> stopProgress(serverSelector(server))); update(null); } } private String hostSelector(Host host) { return "[data-host='" + host.getName() + "']"; //NON-NLS } // ------------------------------------------------------ server group private void serverGroupDetails(ServerGroup serverGroup) { clearSelected(); HTMLElement element = (HTMLElement) document.querySelector(serverGroupSelector(serverGroup)); if (element != null) { element.classList.add(selected); } serverGroupAttributes.refresh(serverGroup); Elements.setVisible(serverGroupAttributesSection, true); Elements.setVisible(hostAttributesSection, false); Elements.setVisible(serverAttributesSection, false); } @SuppressWarnings("unused") private boolean isAllowed(ServerGroup serverGroup) { // To keep it simple, we take a all or nothing approach: // We check *one* action and assume that the other actions have the same constraints Constraints constraints = Constraints .or(Constraint.executable(AddressTemplate.of("/server-group=*"), RELOAD_SERVERS), Constraint .executable(AddressTemplate.of("/server-group=" + serverGroup.getName()), RELOAD_SERVERS)); return AuthorisationDecision.from(environment, securityContextRegistry).isAllowed(constraints); } private List<HTMLElement> serverGroupActions(ServerGroup serverGroup) { List<HTMLElement> actions = new ArrayList<>(); // Order is: reload, restart, suspend, resume, stop, start if (serverGroup.hasServers(Server::isStarted)) { actions.add( actionLink(event -> serverGroupActions.reload(serverGroup), resources.constants().reload())); actions.add( actionLink(event -> serverGroupActions.restart(serverGroup), resources.constants().restart())); } if (serverGroup.getServers(Server::isStarted).size() - serverGroup.getServers(Server::isSuspended).size() > 0) { actions.add( actionLink(event -> serverGroupActions.suspend(serverGroup), resources.constants().suspend())); } if (serverGroup.hasServers(Server::isSuspended)) { actions.add( actionLink(event -> serverGroupActions.resume(serverGroup), resources.constants().resume())); } if (serverGroup.hasServers(Server::isStarted)) { actions.add(actionLink(event -> serverGroupActions.stop(serverGroup), resources.constants().stop())); } if (serverGroup.hasServers(server -> server.isStopped() || server.isFailed())) { actions.add(actionLink(event -> serverGroupActions.start(serverGroup), resources.constants().start())); } // add kill link regardless of state to destroy and kill servers which might show a wrong state actions.add(actionLink(event -> serverGroupActions.destroy(serverGroup), resources.constants().destroy())); actions.add(actionLink(event -> serverGroupActions.kill(serverGroup), resources.constants().kill())); // add remove action to groups which have only stopped servers or no servers at all if (!serverGroup.hasServers(Server::isStarted)) { actions.add( actionLink(event -> serverGroupActions.remove(serverGroup), resources.constants().remove())); } return actions; } @Override public void onServerGroupAction(ServerGroupActionEvent event) { if (isVisible()) { ServerGroup serverGroup = event.getServerGroup(); disableDropdown(Ids.serverGroup(serverGroup.getName()), serverGroup.getName()); event.getServers().forEach(server -> { disableDropdown(server.getId(), server.getName()); startProgress(serverSelector(server)); }); } } @Override public void onServerGroupResult(ServerGroupResultEvent event) { if (isVisible()) { event.getServers().forEach(server -> stopProgress(serverSelector(server))); update(null); } } private String serverGroupSelector(ServerGroup serverGroup) { return "[data-server-group='" + serverGroup.getName() + "']"; //NON-NLS } // ------------------------------------------------------ server private void serverDetails(Server server) { clearSelected(); HTMLElement element = (HTMLElement) document.querySelector(serverSelector(server)); if (element != null) { element.classList.add(selected); } if (server.hasBootErrors()) { PlaceRequest placeRequest = new PlaceRequest.Builder().nameToken(NameTokens.SERVER_BOOT_ERRORS) .with(HOST, server.getHost()).with(SERVER, server.getName()).build(); String token = places.historyToken(placeRequest); serverAttributes.setDescription(resources.messages().serverBootErrorsAndLink(server.getName(), token)); } else { serverAttributes.hideDescription(); } serverAttributes.refresh(server); serverAttributes.setVisible(PROFILE, server.isStarted()); serverAttributes.setVisible(URL, server.isStarted()); serverAttributes.setVisible(RUNNING_MODE, server.isStarted()); serverAttributes.setVisible(SERVER_STATE, server.isStarted()); serverAttributes.setVisible(SUSPEND_STATE, server.isStarted()); Elements.setVisible(serverGroupAttributesSection, false); Elements.setVisible(hostAttributesSection, false); Elements.setVisible(serverAttributesSection, true); if (server.isStarted()) { serverActions.readUrl(server, serverUrl); } } private boolean isAllowed(Server server) { // To keep it simple, we take a all or nothing approach: // We check *one* action and assume that the other actions have the same constraints return AuthorisationDecision.from(environment, securityContextRegistry).isAllowed(Constraint .executable(AddressTemplate.of("/host=" + server.getHost() + "/server-config=*"), RELOAD)); } private List<HTMLElement> serverActions(Server server) { List<HTMLElement> actions = new ArrayList<>(); if (!server.isStarted()) { actions.add(actionLink(event -> serverActions.start(server), resources.constants().start())); } else { actions.add(actionLink(event -> serverActions.editUrl(server, () -> { if (isVisible()) { updateServer(server); } }), resources.constants().editURL())); actions.add(li().css(divider).attr(UIConstants.ROLE, UIConstants.SEPARATOR).get()); // Order is: reload, restart, (resume | suspend), stop actions.add(actionLink(event -> serverActions.reload(server), resources.constants().reload())); actions.add(actionLink(event -> serverActions.restart(server), resources.constants().restart())); if (server.isSuspended()) { actions.add(actionLink(event -> serverActions.resume(server), resources.constants().resume())); } else { actions.add(actionLink(event -> serverActions.suspend(server), resources.constants().suspend())); } actions.add(actionLink(event -> serverActions.stop(server), resources.constants().stop())); } // add kill link regardless of state to destroy and kill servers which might show a wrong state actions.add(actionLink(event -> serverActions.destroy(server), resources.constants().destroy())); actions.add(actionLink(event -> serverActions.kill(server), resources.constants().kill())); return actions; } private String[] statusCss(Server server) { Set<String> status = new HashSet<>(); ServerStatusSwitch sss = new ServerStatusSwitch(serverActions) { @Override protected void onPending(Server server) { } @Override protected void onBootErrors(Server server) { status.add(error); } @Override protected void onFailed(Server server) { status.add(error); } @Override protected void onAdminMode(Server server) { status.add(inactive); } @Override protected void onStarting(Server server) { } @Override protected void onSuspended(Server server) { status.add(suspended); } @Override protected void onNeedsReload(Server server) { status.add(warning); } @Override protected void onNeedsRestart(Server server) { status.add(warning); } @Override protected void onRunning(Server server) { status.add(ok); } @Override protected void onStopped(Server server) { status.add(inactive); } @Override protected void onUnknown(Server server) { } }; sss.accept(server); if (serverActions.isPending(server) || server.isStandalone()) { status.add(withProgress); } return status.toArray(new String[0]); } @Override public void onServerAction(ServerActionEvent event) { if (isVisible()) { Server server = event.getServer(); disableDropdown(server.getId(), server.getName()); startProgress(serverSelector(server)); } } @Override public void onServerResult(ServerResultEvent event) { if (isVisible()) { stopProgress(serverSelector(event.getServer())); updateServer(event.getServer()); } } private String serverSelector(Server server) { return "[data-server='" + server.getId() + "']"; //NON-NLS } }