blob: bf3d989adfa8612ff11373f6a1b88f0627779524 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You 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.apache.geode.management.internal.cli.commands;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.apache.logging.log4j.Logger;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.apache.geode.cache.configuration.CacheConfig;
import org.apache.geode.cache.configuration.CacheElement;
import org.apache.geode.cache.configuration.JndiBindingsType;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.management.cli.CliMetaData;
import org.apache.geode.management.cli.SingleGfshCommand;
import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
import org.apache.geode.management.internal.cli.functions.CreateJndiBindingFunction;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.result.model.ResultModel;
import org.apache.geode.management.internal.security.ResourceOperation;
import org.apache.geode.security.ResourcePermission;
public class CreateJndiBindingCommand extends SingleGfshCommand {
private static final Logger logger = LogService.getLogger();
static final String CREATE_JNDIBINDING = "create jndi-binding";
static final String CREATE_JNDIBINDING__HELP =
"Create a jndi binding that holds the configuration for the XA datasource.";
static final String BLOCKING_TIMEOUT_SECONDS = "blocking-timeout-seconds";
static final String BLOCKING_TIMEOUT_SECONDS__HELP =
"This element specifies the maximum time to block while waiting for a connection before throwing an exception.";
static final String CONNECTION_POOLED_DATASOURCE_CLASS = "conn-pooled-datasource-class";
static final String CONNECTION_POOLED_DATASOURCE_CLASS__HELP =
"This is the fully qualified name of the connection pool implementation to hold XA datasource connections."
+ " When used with --type=POOLED this class must implement org.apache.geode.datasource.PooledDataSourceFactory.";
static final String CONNECTION_URL = "connection-url";
static final String URL = "url";
static final String CONNECTION_URL__HELP =
"This is the JDBC driver connection URL string, for example, jdbc:hsqldb:hsql://localhost:1701.";
static final String IDLE_TIMEOUT_SECONDS = "idle-timeout-seconds";
static final String IDLE_TIMEOUT_SECONDS__HELP =
"This element specifies the time a connection may be idle before being closed.";
static final String INIT_POOL_SIZE = "init-pool-size";
static final String INIT_POOL_SIZE__HELP =
"This element specifies the initial number of connections the pool should hold.";
static final String JDBC_DRIVER_CLASS = "jdbc-driver-class";
static final String JDBC_DRIVER_CLASS__HELP =
"This is the fully qualified name of the JDBC driver class.";
static final String JNDI_NAME = "name";
static final String JNDI_NAME__HELP = "Name of the binding to be created.";
static final String LOGIN_TIMEOUT_SECONDS = "login-timeout-seconds";
static final String LOGIN_TIMEOUT_SECONDS__HELP =
"Time in seconds after which the client thread for retrieving connection will experience timeout.";
static final String MANAGED_CONN_FACTORY_CLASS = "managed-conn-factory-class";
static final String MANAGED_CONN_FACTORY_CLASS__HELP =
"This is the fully qualified name of the connection factory implementation.";
static final String MAX_POOL_SIZE = "max-pool-size";
static final String MAX_POOL_SIZE__HELP =
"This element specifies the maximum number of connections for a pool. No more than the max-pool-size number of connections will be created in a pool.";
static final String PASSWORD = "password";
static final String PASSWORD__HELP =
"This element specifies the default password used when creating a new connection.";
static final String TRANSACTION_TYPE = "transaction-type";
static final String TRANSACTION_TYPE__HELP = "Type of the transaction.";
static final String TYPE = "type";
static final String TYPE__HELP =
"Type of the XA datasource. The following types are pre-defined by the product: MANAGED, SIMPLE, POOLED, XAPOOLED.";
static final String USERNAME = "username";
static final String USERNAME__HELP =
"This element specifies the default username used when creating a new connection.";
static final String XA_DATASOURCE_CLASS = "xa-datasource-class";
static final String XA_DATASOURCE_CLASS__HELP =
"The fully qualified name of the javax.sql.XADataSource implementation class.";
static final String IFNOTEXISTS__HELP =
"Skip the create operation when a jndi binding with the same name already exists. Without specifying this option, this command execution results into an error.";
static final String DATASOURCE_CONFIG_PROPERTIES = "datasource-config-properties";
static final String DATASOURCE_CONFIG_PROPERTIES_HELP =
"Properties for the data source. When used with the --type==POOLED, these properties will be used to configure the database data source unless the name begins with \"pool.\"."
+ " If that prefix is used it will be used to configure the pool data source. Append json string containing (name, type, value) to set any property. "
+ "For example: --datasource-config-properties={'name':'name1','type':'type1','value':'value1'},{'name':'name2','type':'type2','value':'value2'}";
@CliCommand(value = CREATE_JNDIBINDING, help = CREATE_JNDIBINDING__HELP)
@CliMetaData(relatedTopic = CliStrings.TOPIC_GEODE_REGION,
interceptor = "org.apache.geode.management.internal.cli.commands.UsernamePasswordInterceptor")
@ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
operation = ResourcePermission.Operation.MANAGE)
public ResultModel createJDNIBinding(
@CliOption(key = BLOCKING_TIMEOUT_SECONDS,
help = BLOCKING_TIMEOUT_SECONDS__HELP) Integer blockingTimeout,
@CliOption(key = CONNECTION_POOLED_DATASOURCE_CLASS,
help = CONNECTION_POOLED_DATASOURCE_CLASS__HELP) String connectionPooledDatasource,
@CliOption(key = {URL, CONNECTION_URL}, mandatory = true,
help = CONNECTION_URL__HELP) String connectionUrl,
@CliOption(key = IDLE_TIMEOUT_SECONDS, help = IDLE_TIMEOUT_SECONDS__HELP) Integer idleTimeout,
@CliOption(key = INIT_POOL_SIZE, help = INIT_POOL_SIZE__HELP) Integer initPoolSize,
@CliOption(key = JDBC_DRIVER_CLASS,
help = JDBC_DRIVER_CLASS__HELP) String jdbcDriver,
@CliOption(key = JNDI_NAME, mandatory = true, help = JNDI_NAME__HELP) String jndiName,
@CliOption(key = LOGIN_TIMEOUT_SECONDS,
help = LOGIN_TIMEOUT_SECONDS__HELP) Integer loginTimeout,
@CliOption(key = MANAGED_CONN_FACTORY_CLASS,
help = MANAGED_CONN_FACTORY_CLASS__HELP) String managedConnFactory,
@CliOption(key = MAX_POOL_SIZE, help = MAX_POOL_SIZE__HELP) Integer maxPoolSize,
@CliOption(key = USERNAME, help = USERNAME__HELP) String username,
@CliOption(key = PASSWORD, help = PASSWORD__HELP) String password,
@CliOption(key = TRANSACTION_TYPE, help = TRANSACTION_TYPE__HELP) String transactionType,
@CliOption(key = TYPE, unspecifiedDefaultValue = "SIMPLE",
help = TYPE__HELP) DATASOURCE_TYPE type,
@CliOption(key = XA_DATASOURCE_CLASS, help = XA_DATASOURCE_CLASS__HELP) String xaDataSource,
@CliOption(key = CliStrings.IFNOTEXISTS, help = IFNOTEXISTS__HELP,
specifiedDefaultValue = "true", unspecifiedDefaultValue = "false") boolean ifNotExists,
@CliOption(key = DATASOURCE_CONFIG_PROPERTIES, optionContext = "splittingRegex=,(?![^{]*\\})",
help = DATASOURCE_CONFIG_PROPERTIES_HELP) JndiBindingsType.JndiBinding.ConfigProperty[] dsConfigProperties) {
JndiBindingsType.JndiBinding configuration = new JndiBindingsType.JndiBinding();
configuration.setBlockingTimeoutSeconds(Objects.toString(blockingTimeout, null));
configuration.setConnPooledDatasourceClass(connectionPooledDatasource);
configuration.setConnectionUrl(connectionUrl);
configuration.setIdleTimeoutSeconds(Objects.toString(idleTimeout, null));
configuration.setInitPoolSize(Objects.toString(initPoolSize, null));
configuration.setJdbcDriverClass(jdbcDriver);
configuration.setJndiName(jndiName);
configuration.setLoginTimeoutSeconds(Objects.toString(loginTimeout, null));
configuration.setManagedConnFactoryClass(managedConnFactory);
configuration.setMaxPoolSize(Objects.toString(maxPoolSize, null));
configuration.setPassword(password);
configuration.setTransactionType(transactionType);
configuration.setType(type.getType());
configuration.setUserName(username);
configuration.setXaDatasourceClass(xaDataSource);
if (dsConfigProperties != null && dsConfigProperties.length > 0)
configuration.getConfigProperties().addAll(Arrays.asList(dsConfigProperties));
InternalConfigurationPersistenceService service = getConfigurationPersistenceService();
if (service != null) {
CacheConfig cacheConfig = service.getCacheConfig("cluster");
if (cacheConfig != null && CacheElement.exists(cacheConfig.getJndiBindings(), jndiName)) {
String message =
CliStrings.format("Jndi binding with jndi-name \"{0}\" already exists.", jndiName);
return ifNotExists ? ResultModel.createInfo("Skipping: " + message)
: ResultModel.createError(message);
}
}
Set<DistributedMember> targetMembers = findMembers(null, null);
if (targetMembers.size() > 0) {
Object[] arguments = new Object[] {configuration, false};
List<CliFunctionResult> jndiCreationResult = executeAndGetFunctionResult(
new CreateJndiBindingFunction(), arguments, targetMembers);
ResultModel result = ResultModel.createMemberStatusResult(jndiCreationResult);
result.setConfigObject(configuration);
return result;
} else {
return ResultModel.createInfo("No members found.");
}
}
@Override
public boolean updateConfigForGroup(String group, CacheConfig config, Object element) {
config.getJndiBindings().add((JndiBindingsType.JndiBinding) element);
return true;
}
public enum DATASOURCE_TYPE {
MANAGED("ManagedDataSource"),
SIMPLE("SimpleDataSource"),
POOLED("PooledDataSource"),
XAPOOLED("XAPooledDataSource");
private final String type;
DATASOURCE_TYPE(String type) {
this.type = type;
}
public String getType() {
return this.type;
}
public String getName() {
return name();
}
}
}