org.jboss.hal.client.configuration.subsystem.datasource.DataSourceView.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.hal.client.configuration.subsystem.datasource.DataSourceView.java

Source

/*
 * 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.configuration.subsystem.datasource;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import com.google.common.collect.LinkedListMultimap;
import com.google.gwt.core.client.GWT;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import elemental2.dom.HTMLElement;
import org.jboss.gwt.elemento.core.Elements;
import org.jboss.hal.ballroom.autocomplete.StaticAutoComplete;
import org.jboss.hal.ballroom.form.Form;
import org.jboss.hal.ballroom.form.PropertiesItem;
import org.jboss.hal.core.datasource.DataSource;
import org.jboss.hal.core.elytron.CredentialReference;
import org.jboss.hal.core.elytron.CredentialReference.AlternativeValidation;
import org.jboss.hal.core.mbui.form.GroupedForm;
import org.jboss.hal.core.mvp.HalViewImpl;
import org.jboss.hal.dmr.ModelNode;
import org.jboss.hal.dmr.Property;
import org.jboss.hal.meta.Metadata;
import org.jboss.hal.meta.MetadataRegistry;
import org.jboss.hal.resources.Constants;
import org.jboss.hal.resources.Ids;
import org.jboss.hal.resources.Names;
import org.jboss.hal.resources.Resources;

import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static org.jboss.gwt.elemento.core.Elements.h;
import static org.jboss.gwt.elemento.core.Elements.p;
import static org.jboss.hal.ballroom.LayoutBuilder.column;
import static org.jboss.hal.ballroom.LayoutBuilder.row;
import static org.jboss.hal.client.configuration.subsystem.datasource.AddressTemplates.DATA_SOURCE_TEMPLATE;
import static org.jboss.hal.client.configuration.subsystem.datasource.AddressTemplates.XA_DATA_SOURCE_TEMPLATE;
import static org.jboss.hal.client.configuration.subsystem.datasource.Attribute.Scope.BOTH;
import static org.jboss.hal.client.configuration.subsystem.datasource.Attribute.Scope.NON_XA;
import static org.jboss.hal.client.configuration.subsystem.datasource.Attribute.Scope.XA;
import static org.jboss.hal.dmr.ModelDescriptionConstants.*;
import static org.jboss.hal.dmr.ModelNodeHelper.failSafeGet;
import static org.jboss.hal.dmr.ModelNodeHelper.failSafePropertyList;

@SuppressWarnings("ResultOfMethodCallIgnored")
public class DataSourceView extends HalViewImpl implements DataSourcePresenter.MyView {

    private static final Constants CONSTANTS = GWT.create(Constants.class);
    private static LinkedListMultimap<String, Attribute> attributes = LinkedListMultimap.create();

    static {
        // main attributes
        attributes.putAll(CONSTANTS.attributes(),
                asList(new Attribute("datasource-class", NON_XA), new Attribute("driver-class", NON_XA),
                        new Attribute(DRIVER_NAME), new Attribute(ENABLED), new Attribute(JNDI_NAME),
                        new Attribute(STATISTICS_ENABLED), new Attribute("xa-datasource-class", XA)));

        // connection
        //noinspection HardCodedStringLiteral,DuplicateStringLiteralInspection
        attributes.putAll(CONSTANTS.connection(),
                asList(new Attribute(CONNECTION_URL, NON_XA), new Attribute("connection-listener-class"),
                        new Attribute("connection-listener-property"), new Attribute("interleaving", XA),
                        new Attribute("jta", NON_XA), new Attribute("new-connection-sql"),
                        new Attribute("pad-xid", XA), new Attribute("same-rm-override", XA),
                        new Attribute("transaction-isolation"), new Attribute("url-delimiter"),
                        new Attribute("url-property", XA), new Attribute("url-selector-strategy-class-name"),
                        new Attribute("use-ccm"), new Attribute("wrap-xa-resource", XA)));

        // pool
        //noinspection HardCodedStringLiteral,DuplicateStringLiteralInspection
        attributes.putAll(CONSTANTS.pool(), asList(new Attribute("initial-pool-size"), new Attribute(MIN_POOL_SIZE),
                new Attribute(MAX_POOL_SIZE), new Attribute("flush-strategy"), new Attribute("pool-fair"),
                new Attribute("pool-prefill"), new Attribute("pool-use-strict-min"), new Attribute("use-fast-fail"),
                new Attribute("capacity-incrementer-class"), new Attribute("capacity-incrementer-properties"),
                new Attribute("capacity-decrementer-class"), new Attribute("capacity-decrementer-properties"),
                new Attribute("no-recovery", XA), new Attribute("tx-separate-pool", XA)));

        // security
        //noinspection HardCodedStringLiteral,DuplicateStringLiteralInspection
        attributes.putAll(CONSTANTS.security(), asList(new Attribute("user-name"), new Attribute("password"),
                new Attribute("authentication-context"), new Attribute("security-domain"),
                new Attribute("allow-multiple-users"), new Attribute("reauth-plugin-class-name"),
                new Attribute("reauth-plugin-properties"), new Attribute("recovery-username", XA),
                new Attribute("recovery-password", XA), new Attribute("recovery-security-domain", XA),
                new Attribute("recovery-plugin-class-name", XA), new Attribute("recovery-plugin-properties", XA)));

        // credential reference is added as a marker key and not part of the grouped form!
        attributes.put(CREDENTIAL_REFERENCE, null);

        // validation
        //noinspection HardCodedStringLiteral,DuplicateStringLiteralInspection
        attributes.putAll(CONSTANTS.validation(), asList(new Attribute("check-valid-connection-sql"),
                new Attribute("valid-connection-checker-class-name"),
                new Attribute("valid-connection-checker-properties"), new Attribute("validate-on-match"),
                new Attribute("background-validation"), new Attribute("background-validation-millis"),
                new Attribute("stale-connection-checker-class-name"),
                new Attribute("stale-connection-checker-properties"), new Attribute("exception-sorter-class-name"),
                new Attribute("exception-sorter-properties")));

        // timeouts
        //noinspection HardCodedStringLiteral,DuplicateStringLiteralInspection
        attributes.putAll(CONSTANTS.timeouts(),
                asList(new Attribute("use-try-lock"), new Attribute("blocking-timeout-wait-millis"),
                        new Attribute("idle-timeout-minutes"), new Attribute("set-tx-query-timeout"),
                        new Attribute("query-timeout"), new Attribute("allocation-retry"),
                        new Attribute("allocation-retry-wait-millis"), new Attribute("xa-resource-timeout", XA)));

        // statements / tracking
        //noinspection HardCodedStringLiteral,DuplicateStringLiteralInspection
        attributes.putAll(CONSTANTS.statements() + " / " + CONSTANTS.tracking(),
                asList(new Attribute("spy"), new Attribute("tracking"), new Attribute("track-statements"),
                        new Attribute("share-prepared-statements"), new Attribute("prepared-statements-cache-size"),
                        new Attribute("enlistment-trace")));
    }

    private final Resources resources;
    private final HTMLElement header;
    private final HTMLElement nonXaInfo;
    private final HTMLElement xaInfo;
    private Form<DataSource> nonXaForm;
    private Form<ModelNode> nonXaCrForm;
    private Form<DataSource> xaForm;
    private Form<ModelNode> xaCrForm;
    private DataSourcePresenter presenter;
    private Map<String, String> originalConnectionProperties;
    private StaticAutoComplete xaAutoCompleteValues = new StaticAutoComplete(Collections.emptyList());
    private StaticAutoComplete nonXaAutoCompleteValues = new StaticAutoComplete(Collections.emptyList());

    @Inject
    public DataSourceView(MetadataRegistry metadataRegistry, CredentialReference credentialReference,
            Resources resources) {
        this.resources = resources;

        Form.SaveCallback<DataSource> saveCallback = (f, changedValues) -> presenter.saveDataSource(f,
                changedValues, originalConnectionProperties);
        Form.PrepareReset<DataSource> prepareReset = (f) -> presenter.resetDataSource(f);

        Metadata nonXaMeta = metadataRegistry.lookup(DATA_SOURCE_TEMPLATE);
        nonXaInfo = p().textContent(nonXaMeta.getDescription().getDescription()).get();
        GroupedForm.Builder<DataSource> nonXaFormBuilder = new GroupedForm.Builder<DataSource>(Ids.DATA_SOURCE_FORM,
                nonXaMeta).onSave(saveCallback).prepareReset(prepareReset);

        Metadata xaMeta = metadataRegistry.lookup(XA_DATA_SOURCE_TEMPLATE);
        xaInfo = p().textContent(xaMeta.getDescription().getDescription()).get();
        GroupedForm.Builder<DataSource> xaFormBuilder = new GroupedForm.Builder<DataSource>(Ids.XA_DATA_SOURCE_FORM,
                xaMeta).onSave(saveCallback);

        for (String group : attributes.keySet()) {
            String nonXaId = Ids.build(Ids.DATA_SOURCE_CONFIGURATION, group);
            String xaId = Ids.build(Ids.XA_DATA_SOURCE, group);

            if (CREDENTIAL_REFERENCE.equals(group)) {
                nonXaCrForm = credentialReference.form(Ids.DATA_SOURCE_CONFIGURATION, nonXaMeta, PASSWORD,
                        () -> nonXaForm.<String>getFormItem(PASSWORD).getValue(), () -> presenter.resourceAddress(),
                        () -> presenter.reload());
                registerAttachable(nonXaCrForm);
                nonXaFormBuilder.customGroup(nonXaId, Names.CREDENTIAL_REFERENCE).add(nonXaCrForm).end();

                xaCrForm = credentialReference.form(Ids.XA_DATA_SOURCE, xaMeta, PASSWORD,
                        () -> xaForm.<String>getFormItem(PASSWORD).getValue(), () -> presenter.resourceAddress(),
                        () -> presenter.reload());
                registerAttachable(xaCrForm);
                xaFormBuilder.customGroup(xaId, Names.CREDENTIAL_REFERENCE).add(xaCrForm).end();

            } else {
                List<Attribute> groupAttributes = attributes.get(group);

                // non xa form and tab
                List<String> nonXaNames = groupAttributes.stream()
                        .filter(attribute -> attribute.scope == BOTH || attribute.scope == NON_XA)
                        .map(attribute -> attribute.name).collect(toList());
                nonXaFormBuilder.customGroup(nonXaId, group).include(nonXaNames);

                // xa form and tab
                List<String> xaNames = groupAttributes.stream()
                        .filter(attribute -> attribute.scope == BOTH || attribute.scope == XA)
                        .map(attribute -> attribute.name).collect(toList());
                xaFormBuilder.customGroup(xaId, group).include(xaNames);

                if (group.equals(CONSTANTS.connection())) {
                    nonXaFormBuilder.unboundFormItem(new PropertiesItem(CONNECTION_PROPERTIES));
                    xaFormBuilder.unboundFormItem(new PropertiesItem(XA_DATASOURCE_PROPERTIES));
                }
                nonXaFormBuilder.end();
                xaFormBuilder.end();
            }
        }

        nonXaForm = nonXaFormBuilder.build();
        nonXaForm.addFormValidation(new AlternativeValidation<>(PASSWORD, () -> nonXaCrForm.getModel(), resources));
        xaForm = xaFormBuilder.build();
        xaForm.getFormItem(XA_DATASOURCE_PROPERTIES).registerSuggestHandler(xaAutoCompleteValues);
        nonXaForm.getFormItem(CONNECTION_PROPERTIES).registerSuggestHandler(nonXaAutoCompleteValues);
        xaForm.addFormValidation(new AlternativeValidation<>(PASSWORD, () -> xaCrForm.getModel(), resources));
        registerAttachable(nonXaForm);
        registerAttachable(xaForm);

        initElement(row().add(column().add(header = h(1).textContent(Names.DATASOURCE).get()).add(nonXaInfo)
                .add(xaInfo).add(nonXaForm).add(xaForm)).get());
    }

    @Override
    public void setPresenter(DataSourcePresenter presenter) {
        this.presenter = presenter;
    }

    @Override
    public void clear(boolean xa) {
        showHide(xa);
        if (xa) {
            header.textContent = Names.XA_DATASOURCE;
            xaForm.clear();
            if (xaCrForm != null) {
                xaCrForm.clear();
            }
        } else {
            header.textContent = Names.DATASOURCE;
            nonXaForm.clear();
            if (nonXaCrForm != null) {
                nonXaCrForm.clear();
            }
        }
    }

    @Override
    public void update(DataSource dataSource) {
        // TODO Add a suggestion handler for the DRIVER_NAME field
        showHide(dataSource.isXa());
        //noinspection HardCodedStringLiteral
        header.innerHTML = new SafeHtmlBuilder().appendEscaped(dataSource.getName()).appendHtmlConstant("<small>")
                .appendEscaped(" (")
                .appendEscaped(
                        dataSource.isEnabled() ? resources.constants().enabled() : resources.constants().disabled())
                .appendEscaped(")").appendHtmlConstant("</small>").toSafeHtml().asString();
        if (dataSource.isXa()) {
            xaForm.view(dataSource);
            Map<String, String> p = failSafePropertyList(dataSource, XA_DATASOURCE_PROPERTIES).stream()
                    .collect(toMap(Property::getName, property -> property.getValue().get(VALUE).asString()));
            originalConnectionProperties = p;
            xaForm.getFormItem(XA_DATASOURCE_PROPERTIES).setValue(p);
            String dsClassname = dataSource.hasDefined(XA_DATASOURCE_CLASS)
                    ? dataSource.get(XA_DATASOURCE_CLASS).asString()
                    : null;
            String driverName = dataSource.get(DRIVER_NAME).asString();
            presenter.readJdbcDriverProperties(true, dsClassname, driverName,
                    dsProperties -> xaAutoCompleteValues.update(dsProperties));
            if (xaCrForm != null) {
                xaCrForm.view(failSafeGet(dataSource, CREDENTIAL_REFERENCE));
            }
        } else {
            nonXaForm.view(dataSource);
            Map<String, String> p = failSafePropertyList(dataSource, CONNECTION_PROPERTIES).stream()
                    .collect(toMap(Property::getName, property -> property.getValue().get(VALUE).asString()));
            originalConnectionProperties = p;
            nonXaForm.getFormItem(CONNECTION_PROPERTIES).setValue(p);
            String dsClassname = dataSource.hasDefined(DATASOURCE_CLASS)
                    ? dataSource.get(DATASOURCE_CLASS).asString()
                    : null;
            String driverName = dataSource.get(DRIVER_NAME).asString();
            presenter.readJdbcDriverProperties(false, dsClassname, driverName,
                    dsProperties -> nonXaAutoCompleteValues.update(dsProperties));

            if (nonXaCrForm != null) {
                nonXaCrForm.view(failSafeGet(dataSource, CREDENTIAL_REFERENCE));
            }
        }
    }

    private void showHide(boolean xa) {
        Elements.setVisible(nonXaInfo, !xa);
        Elements.setVisible(xaInfo, xa);
        Elements.setVisible(nonXaForm.element(), !xa);
        Elements.setVisible(xaForm.element(), xa);
    }
}