/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.adminapi.jboss;
import static org.jboss.as.controller.client.helpers.ClientConstants.*;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.UnknownHostException;
import java.util.*;
import java.util.logging.Logger;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.RealmCallback;
import javax.security.sasl.RealmChoiceCallback;
import org.jboss.as.cli.Util;
import org.jboss.as.cli.batch.impl.DefaultBatch;
import org.jboss.as.cli.batch.impl.DefaultBatchedCommand;
import org.jboss.as.cli.operation.OperationFormatException;
import org.jboss.as.cli.operation.impl.DefaultOperationRequestAddress;
import org.jboss.as.cli.operation.impl.DefaultOperationRequestBuilder;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.teiid.adminapi.*;
import org.teiid.adminapi.PropertyDefinition.RestartType;
import org.teiid.adminapi.VDB.ConnectionType;
import org.teiid.adminapi.impl.AdminObjectImpl;
import org.teiid.adminapi.impl.PropertyDefinitionMetadata;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.adminapi.impl.VDBTranslatorMetaData;
import org.teiid.adminapi.jboss.VDBMetadataMapper.RequestMetadataMapper;
import org.teiid.adminapi.jboss.VDBMetadataMapper.SessionMetadataMapper;
import org.teiid.adminapi.jboss.VDBMetadataMapper.TransactionMetadataMapper;
import org.teiid.core.util.ObjectConverterUtil;
/**
* Singleton factory for class for creating Admin connections to the Teiid
*/
@SuppressWarnings("nls")
public class AdminFactory {
private static final Logger LOGGER = Logger.getLogger(AdminFactory.class.getName());
private static AdminFactory INSTANCE = new AdminFactory();
public static AdminFactory getInstance() {
return INSTANCE;
}
/**
* Creates a ServerAdmin with the specified connection properties.
* @param userName
* @param password
* @param serverURL
* @param applicationName
* @param profileName - Name of the domain mode profile
* @return
* @throws AdminException
*/
public Admin createAdmin(String host, int port, String userName, char[] password, String profileName) throws AdminException {
AdminImpl admin = (AdminImpl)createAdmin(host, port, userName, password);
admin.setProfileName(profileName);
return admin;
}
/**
* Creates a ServerAdmin with the specified connection properties.
* @param userName
* @param password
* @param serverURL
* @param applicationName
* @return
* @throws AdminException
*/
public Admin createAdmin(String host, int port, String userName, char[] password) throws AdminException {
if(host == null) {
host = "localhost"; //$NON-NLS-1$
}
if(port < 0) {
port = 9990;
}
try {
CallbackHandler cbh = new AuthenticationCallbackHandler(userName, password);
ModelControllerClient newClient = ModelControllerClient.Factory.create(host, port, cbh);
List<String> nodeTypes = Util.getNodeTypes(newClient, new DefaultOperationRequestAddress());
if (!nodeTypes.isEmpty()) {
boolean domainMode = nodeTypes.contains("server-group"); //$NON-NLS-1$
LOGGER.info("Connected to " //$NON-NLS-1$
+ (domainMode ? "domain controller at " : "standalone controller at ") //$NON-NLS-1$ //$NON-NLS-2$
+ host + ":" + port); //$NON-NLS-1$
return new AdminImpl(newClient);
}
LOGGER.info(AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70051, host, port));
} catch (UnknownHostException e) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70000, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70000, host, e.getLocalizedMessage()));
}
return null;
}
public Admin createAdmin(ModelControllerClient connection) {
return new AdminImpl(connection);
}
/**
* Name of the domain mode profile.
* @param connection
* @param profileName
* @return
*/
public Admin createAdmin(ModelControllerClient connection, String profileName) {
AdminImpl admin = new AdminImpl(connection);
admin.setProfileName(profileName);
return admin;
}
private class AuthenticationCallbackHandler implements CallbackHandler {
private boolean realmShown = false;
private String userName = null;
private char[] password = null;
public AuthenticationCallbackHandler(String user, char[] password) {
this.userName = user;
this.password = password;
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
// Special case for anonymous authentication to avoid prompting user for their name.
if (callbacks.length == 1 && callbacks[0] instanceof NameCallback) {
((NameCallback)callbacks[0]).setName("anonymous CLI user"); //$NON-NLS-1$
return;
}
for (Callback current : callbacks) {
if (current instanceof RealmCallback) {
RealmCallback rcb = (RealmCallback) current;
String defaultText = rcb.getDefaultText();
rcb.setText(defaultText); // For now just use the realm suggested.
if (this.realmShown == false) {
this.realmShown = true;
}
} else if (current instanceof RealmChoiceCallback) {
throw new UnsupportedCallbackException(current, "Realm choice not currently supported."); //$NON-NLS-1$
} else if (current instanceof NameCallback) {
NameCallback ncb = (NameCallback) current;
ncb.setName(this.userName);
} else if (current instanceof PasswordCallback) {
PasswordCallback pcb = (PasswordCallback) current;
pcb.setPassword(this.password);
} else {
throw new UnsupportedCallbackException(current);
}
}
}
}
private class ResultCallback {
void onSuccess(ModelNode outcome, ModelNode result) throws AdminException {
}
void onFailure(String msg) throws AdminProcessingException {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70006, msg);
}
}
private static final MetadataMapper<String> STRINGMAPPER = new MetadataMapper<String>() {
@Override
public String unwrap(ModelNode node) {
return node.asString();
}
@Override
public ModelNode describe(ModelNode node) {
return null;
}
@Override
public ModelNode wrap(String obj, ModelNode node) {
return null;
}
};
public class AdminImpl implements Admin{
private static final long CACHE_TIME = 5*1000;
private static final String CLASS_NAME = "class-name";
private static final String JAVA_CONTEXT = "java:/";
private ModelControllerClient connection;
private boolean domainMode = false;
private String profileName = "ha";
Expirable<Map<String, String>> connectionFactoryNames = new Expirable<Map<String,String>>();
Expirable<Set<String>> installedResourceAdaptorNames = new Expirable<Set<String>>();
Expirable<Set<String>> deployedResourceAdaptorNames = new Expirable<Set<String>>();
public AdminImpl (ModelControllerClient connection) {
this.connection = connection;
List<String> nodeTypes = Util.getNodeTypes(connection, new DefaultOperationRequestAddress());
if (!nodeTypes.isEmpty()) {
this.domainMode = nodeTypes.contains("server-group"); //$NON-NLS-1$
}
}
@Override
public void setProfileName(String name) {
if (name == null) {
this.profileName = "ha";
} else {
this.profileName = name;
}
}
@Override
public void clearCache(String cacheType) throws AdminException {
cliCall("clear-cache",
new String[] { "subsystem", "teiid" },
new String[] { "cache-type", cacheType},
new ResultCallback());
}
@Override
public void clearCache(String cacheType, String vdbName, String vdbVersion) throws AdminException {
cliCall("clear-cache",
new String[] { "subsystem", "teiid" },
new String[] { "cache-type", cacheType, "vdb-name",vdbName, "vdb-version", vdbVersion },
new ResultCallback());
}
@Override
public void close() {
if (this.connection != null) {
try {
this.connection.close();
} catch (Throwable t) {
//ignore
}
this.connection = null;
this.domainMode = false;
}
}
private void createConnectionFactory(String deploymentName, String rarName, Properties properties) throws AdminException {
if (!getInstalledResourceAdaptorNames().contains(rarName)) {
///subsystem=resource-adapters/resource-adapter=fileDS:add
addArchiveResourceAdapter(rarName);
}
//AS-4776 HACK - BEGIN
else {
// add duplicate resource adapter AS-4776 Workaround
String moduleName = getResourceAdapterModuleName(rarName);
addModuleResourceAdapter(deploymentName, moduleName);
rarName = deploymentName;
}
//AS-4776 HACK - END
BuildPropertyDefinitions bpd = new BuildPropertyDefinitions();
buildResourceAdpaterProperties(rarName, bpd);
ArrayList<PropertyDefinition> jcaSpecific = bpd.getPropertyDefinitions();
///subsystem=resource-adapters/resource-adapter=fileDS/connection-definitions=fileDS:add(jndi-name=java\:\/fooDS)
ArrayList<String> parameters = new ArrayList<String>();
parameters.add("jndi-name");
parameters.add(addJavaContext(deploymentName));
parameters.add("enabled");
parameters.add("true");
if (properties.getProperty(CLASS_NAME) != null) {
parameters.add(CLASS_NAME);
parameters.add(properties.getProperty(CLASS_NAME));
}
// add jca specific proeprties
for (PropertyDefinition pd:jcaSpecific) {
if (properties.getProperty(pd.getName()) != null) {
parameters.add(pd.getName());
parameters.add(properties.getProperty(pd.getName()));
}
}
cliCall("add", new String[] { "subsystem", "resource-adapters",
"resource-adapter", rarName,
"connection-definitions", deploymentName },
parameters.toArray(new String[parameters.size()]), new ResultCallback());
// add all the config properties
Enumeration keys = properties.propertyNames();
while (keys.hasMoreElements()) {
boolean add = true;
String key = (String)keys.nextElement();
if (key.equals(CLASS_NAME)) {
add = false;
}
for (PropertyDefinition pd:jcaSpecific) {
if (key.equals(pd.getName())) {
add = false;
break;
}
}
if (add) {
addConfigProperty(rarName, deploymentName, key, properties.getProperty(key));
}
}
// activate
activateConnectionFactory(rarName);
}
// /subsystem=resource-adapters/resource-adapter=fileDS/connection-definitions=fileDS/config-properties=ParentDirectory2:add(value=/home/rareddy/testing)
private void addConfigProperty(String rarName, String deploymentName, String key, String value) throws AdminException {
if (value == null || value.trim().isEmpty()) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70054, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70054, key));
}
cliCall("add", new String[] { "subsystem", "resource-adapters",
"resource-adapter", rarName,
"connection-definitions", deploymentName,
"config-properties", key},
new String[] {"value", value}, new ResultCallback());
}
// /subsystem=resource-adapters/resource-adapter=fileDS:activate
private void activateConnectionFactory(String rarName) throws AdminException {
cliCall("activate", new String[] { "subsystem", "resource-adapters",
"resource-adapter", rarName },
null, new ResultCallback());
}
private void addProfileNode(DefaultOperationRequestBuilder builder) throws AdminException {
if (this.domainMode) {
String profile = getProfileName();
if (profile != null) {
builder.addNode("profile",profile);
}
}
}
// /subsystem=resource-adapters/resource-adapter=teiid-connector-ws.rar:add(archive=teiid-connector-ws.rar, transaction-support=NoTransaction)
private void addArchiveResourceAdapter(String rarName) throws AdminException {
cliCall("add", new String[] { "subsystem", "resource-adapters",
"resource-adapter", rarName },
new String[] { "archive", rarName, "transaction-support","NoTransaction" },
new ResultCallback());
}
private void addModuleResourceAdapter(String rarName, String moduleName) throws AdminException {
cliCall("add", new String[] { "subsystem", "resource-adapters",
"resource-adapter", rarName },
new String[] { "module", moduleName, "transaction-support","NoTransaction" },
new ResultCallback());
}
private String getResourceAdapterModuleName(String rarName)
throws AdminException {
final List<String> props = new ArrayList<String>();
cliCall("read-resource",
new String[] { "subsystem", "resource-adapters", "resource-adapter", rarName},
null, new ResultCallback() {
@Override
void onSuccess(ModelNode outcome, ModelNode result) throws AdminException {
List<ModelNode> properties = outcome.get("result").asList();
for (ModelNode prop:properties) {
if (!prop.getType().equals(ModelType.PROPERTY)) {
continue;
}
org.jboss.dmr.Property p = prop.asProperty();
if (p.getName().equals("module")) {
props.add(p.getValue().asString());
}
}
}
});
return props.get(0);
}
class AbstractMetadatMapper implements MetadataMapper<String>{
@Override
public ModelNode wrap(String obj, ModelNode node) {
return null;
}
@Override
public String unwrap(ModelNode node) {
return null;
}
@Override
public ModelNode describe(ModelNode node) {
return null;
}
}
public Set<String> getInstalledJDBCDrivers() throws AdminException {
HashSet<String> driverList = new LinkedHashSet<String>();
driverList.addAll(getChildNodeNames("datasources", "jdbc-driver"));
if (!this.domainMode) {
//'installed-driver-list' not available in the domain mode.
final ModelNode request = buildRequest("datasources", "installed-drivers-list");
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
List<String> drivers = getList(outcome, new AbstractMetadatMapper() {
@Override
public String unwrap(ModelNode node) {
if (node.hasDefined("driver-name")) {
return node.get("driver-name").asString();
}
return null;
}
});
List<String> xadrivers = getList(outcome, new AbstractMetadatMapper() {
@Override
public String unwrap(ModelNode node) {
if (node.hasDefined("driver-name") && node.hasDefined("driver-xa-datasource-class-name")) {
return node.get("driver-name").asString()+"-xa";
}
return null;
}
});
driverList.addAll(drivers);
driverList.addAll(xadrivers);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70052, e);
}
}
else {
// TODO: AS7 needs to provide better way to query the deployed JDBC drivers
List<String> deployments = getChildNodeNames(null, "deployment");
for (String deployment:deployments) {
if (!deployment.contains("translator") && deployment.endsWith(".jar")) {
driverList.add(deployment);
}
}
}
return driverList;
}
public String getProfileName() {
if (!this.domainMode) {
return null;
}
return this.profileName;
}
/**
* Use this method to create JDBC driver based connection, XA-datasource or Resource Adapter.
* Template Name defines the type of connection, if the template name is ends with "-xa" it is
* considered to be a XA based data source.
*
* @param deploymentName This becomes the pool name, as well as the jndi name of the source
* @param templateName type of source. See {@link getDataSourceNames} for all available types.
* @param properties All properties needed to create a data source, like connection-url, user, password
* to see all the properties use {@link getTemplatePropertyDefinitions} to retrieve the full list
*/
@Override
public void createDataSource(String deploymentName, String templateName, Properties properties) throws AdminException {
flush();
deploymentName = removeJavaContext(deploymentName);
Map<String, String> connectionFactoryNames = getConnectionFactoryNames();
Collection<String> dsNames = getDataSourceNames(connectionFactoryNames);
if (dsNames.contains(deploymentName)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70003, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70003, deploymentName));
}
Set<String> resourceAdapters = getResourceAdapterNames(connectionFactoryNames);
if (resourceAdapters.contains(templateName)) {
createConnectionFactory(deploymentName, templateName, properties);
flush();
return;
}
Set<String> drivers = getInstalledJDBCDrivers();
if (!drivers.contains(templateName)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70004, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70004, templateName));
}
// build properties
Collection<PropertyDefinition> dsProperties = getTemplatePropertyDefinitions(templateName);
ArrayList<String> parameters = new ArrayList<String>();
if (properties != null) {
if (!isXA(templateName)) {
parameters.add("connection-url");
parameters.add(properties.getProperty("connection-url"));
}
for (PropertyDefinition prop : dsProperties) {
if (getCustomDatasourceProperties().contains(prop.getName())) {
continue;
}
String value = properties.getProperty(prop.getName());
if (value != null) {
parameters.add(prop.getName());
parameters.add(value);
}
}
}
else {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70005, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70005));
}
parameters.add("jndi-name");
parameters.add(addJavaContext(deploymentName));
parameters.add("driver-name");
parameters.add(stripXA(templateName));
parameters.add("pool-name");
parameters.add(deploymentName);
DefaultBatch batch = new DefaultBatch();
try {
if (isXA(templateName)) {
batch.add(new DefaultBatchedCommand("add",
buildRequest("add", new String[] { "subsystem", "datasources","xa-data-source", deploymentName },
parameters.toArray(new String[parameters.size()]))));
if (properties.getProperty("connection-url") != null) {
batch.add(new DefaultBatchedCommand("add", addXADatasourceProperty(deploymentName, "connection-url", properties.getProperty("connection-url"))));
} else {
batch.add(new DefaultBatchedCommand("add", addXADatasourceProperty(deploymentName, "DatabaseName", properties.getProperty("DatabaseName"))));
if (properties.getProperty("PortNumber") != null) {
batch.add(new DefaultBatchedCommand("add", addXADatasourceProperty(deploymentName, "PortNumber", properties.getProperty("PortNumber"))));
}
batch.add(new DefaultBatchedCommand("add", addXADatasourceProperty(deploymentName, "ServerName", properties.getProperty("ServerName"))));
}
// add connection properties that are specific to driver
String cp = properties.getProperty("connection-properties");
if (cp != null) {
StringTokenizer st = new StringTokenizer(cp, ",");
while(st.hasMoreTokens()) {
String prop = st.nextToken();
String key = prop.substring(0, prop.indexOf('='));
String value = prop.substring(prop.indexOf('=')+1);
batch.add(new DefaultBatchedCommand("add", addXADatasourceProperty(deploymentName, key, value)));
}
}
} else {
// add data source
batch.add(new DefaultBatchedCommand("add",
buildRequest("add", new String[] { "subsystem", "datasources","data-source", deploymentName },
parameters.toArray(new String[parameters.size()]))));
// add connection properties that are specific to driver
String cp = properties.getProperty("connection-properties");
if (cp != null) {
StringTokenizer st = new StringTokenizer(cp, ",");
while(st.hasMoreTokens()) {
String prop = st.nextToken();
String key = prop.substring(0, prop.indexOf('='));
String value = prop.substring(prop.indexOf('=')+1);
batch.add(new DefaultBatchedCommand("add", addConnectionProperty(deploymentName, key, value)));
}
}
}
} catch (OperationFormatException e) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70057,
AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70057, batch.toRequest()));
}
cliCall(batch.toRequest(), new ResultCallback());
flush();
}
// /subsystem=datasources/data-source=DS/connection-properties=foo:add(value=/home/rareddy/testing)
private ModelNode addConnectionProperty(String deploymentName, String key, String value)
throws AdminException, OperationFormatException {
if (value == null || value.trim().isEmpty()) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70054, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70054, key));
}
return buildRequest("add", new String[] { "subsystem", "datasources",
"data-source", deploymentName,
"connection-properties", key },
new String[] {"value", value });
}
// /subsystem=datasources/data-source=DS/connection-properties=foo:add(value=/home/rareddy/testing)
private ModelNode addXADatasourceProperty(String deploymentName,
String key, String value) throws AdminException, OperationFormatException {
if (value == null || value.trim().isEmpty()) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70054,
AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70054, key));
}
return buildRequest("add", new String[] { "subsystem", "datasources",
"xa-data-source", deploymentName,
"xa-datasource-properties", key },
new String[] {"value", value });
}
private void execute(final ModelNode request) throws AdminException {
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70006, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70007, e);
}
}
@Override
public Properties getDataSource(String deployedName) throws AdminException {
deployedName = removeJavaContext(deployedName);
Map<String, String> connectionFactoryNames = getConnectionFactoryNames();
Collection<String> dsNames = getDataSourceNames(connectionFactoryNames);
if (!dsNames.contains(deployedName)) {
flush(); //just in case we were using old info, flush
connectionFactoryNames = getConnectionFactoryNames();
dsNames = getDataSourceNames(connectionFactoryNames);
if (!dsNames.contains(deployedName)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70008, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70008, deployedName));
}
}
Properties dsProperties = new Properties();
// check regular data-source
cliCall("read-resource",
new String[] { "subsystem", "datasources", "data-source", deployedName}, null,
new DataSourceProperties(dsProperties));
// check xa connections
if (dsProperties.isEmpty()) {
cliCall("read-resource",
new String[] {"subsystem", "datasources", "xa-data-source", deployedName}, null,
new DataSourceProperties(dsProperties));
}
// check connection factories
if (dsProperties.isEmpty()) {
// deployed rar name, may be it is == deployedName or if server restarts it will be rar name or rar->[1..n] name
String rarName = connectionFactoryNames.get(deployedName);
if (rarName != null) {
cliCall("read-resource",
new String[] { "subsystem", "resource-adapters", "resource-adapter", rarName, "connection-definitions", deployedName},
null, new ConnectionFactoryProperties(dsProperties, rarName, deployedName, null));
}
// figure out driver-name
if (dsProperties.getProperty("driver-name") == null) {
String moduleName = getResourceAdapterModuleName(rarName);
Set<String> installedRars = getResourceAdapterNames(connectionFactoryNames);
for (String installedRar:installedRars) {
if (getResourceAdapterModuleName(installedRar).equals(moduleName)) {
dsProperties.setProperty("driver-name", installedRar);
break;
}
}
}
}
return dsProperties;
}
private class DataSourceProperties extends ResultCallback {
private Properties dsProperties;
DataSourceProperties(Properties props){
this.dsProperties = props;
}
@Override
public void onSuccess(ModelNode outcome, ModelNode result) throws AdminProcessingException {
List<ModelNode> props = outcome.get("result").asList();
for (ModelNode prop:props) {
if (prop.getType().equals(ModelType.PROPERTY)) {
org.jboss.dmr.Property p = prop.asProperty();
ModelType type = p.getValue().getType();
if (p.getValue().isDefined() && !type.equals(ModelType.LIST) && !type.equals(ModelType.OBJECT)) {
if (p.getName().equals("driver-name")
|| p.getName().equals("jndi-name")
|| !excludeProperty(p.getName())) {
this.dsProperties.setProperty(p.getName(), p.getValue().asString());
}
}
}
}
}
@Override
public void onFailure(String msg) throws AdminProcessingException {
}
}
private class ConnectionFactoryProperties extends ResultCallback {
private Properties dsProperties;
private String deployedName;
private String rarName;
private String configName;
ConnectionFactoryProperties(Properties props, String rarName, String deployedName, String configName){
this.dsProperties = props;
this.rarName = rarName;
this.deployedName = deployedName;
this.configName = configName;
}
@Override
public void onSuccess(ModelNode outcome, ModelNode result) throws AdminException {
List<ModelNode> props = outcome.get("result").asList();
for (ModelNode prop:props) {
if (!prop.getType().equals(ModelType.PROPERTY)) {
continue;
}
org.jboss.dmr.Property p = prop.asProperty();
if (p.getName().equals("jndi-name")) {
this.dsProperties.setProperty("jndi-name", p.getValue().asString());
}
if (!p.getValue().isDefined() || excludeProperty(p.getName())) {
continue;
}
if (p.getName().equals("archive")) {
this.dsProperties.setProperty("driver-name", p.getValue().asString());
}
if (p.getName().equals("value")) {
this.dsProperties.setProperty(this.configName, p.getValue().asString());
}
else if (p.getName().equals("config-properties")) {
List<ModelNode> configs = p.getValue().asList();
for (ModelNode config:configs) {
if (config.getType().equals(ModelType.PROPERTY)) {
org.jboss.dmr.Property p1 = config.asProperty();
//getConnectionFactoryProperties(rarName, dsProps, subsystem[0], subsystem[1], subsystem[2], subsystem[3], );
cliCall("read-resource",
new String[] {"subsystem","resource-adapters",
"resource-adapter",this.rarName,
"connection-definitions",this.deployedName,
"config-properties",p1.getName()}, null,
new ConnectionFactoryProperties(this.dsProperties, this.rarName, this.deployedName, p1.getName()));
}
}
}
else {
this.dsProperties.setProperty(p.getName(), p.getValue().asString());
}
}
}
@Override
public void onFailure(String msg) throws AdminProcessingException {
}
}
@Override
public void deleteDataSource(String deployedName) throws AdminException {
flush();
deployedName = removeJavaContext(deployedName);
Map<String, String> connectionFactoryNames = getConnectionFactoryNames();
Collection<String> dsNames = getDataSourceNames(connectionFactoryNames);
if (!dsNames.contains(deployedName)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70008, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70008, deployedName));
}
boolean deleted = deleteDS(deployedName,"datasources", "data-source");
// check xa connections
if (!deleted) {
deleted = deleteDS(deployedName,"datasources", "xa-data-source");
}
// check connection factories
if (!deleted) {
// deployed rar name, may be it is == deployedName or if server restarts it will be rar name or rar->[1..n] name
String rarName = connectionFactoryNames.get(deployedName);
if (rarName != null) {
cliCall("remove", new String[] { "subsystem",
"resource-adapters", "resource-adapter", rarName,
"connection-definitions", deployedName }, null,
new ResultCallback());
//AS-4776 HACK - BEGIN
if (getInstalledResourceAdaptorNames().contains(deployedName)) {
cliCall("remove", new String[] { "subsystem",
"resource-adapters", "resource-adapter", deployedName}, null,
new ResultCallback());
}
//AS-4776 HACK - END
}
}
flush();
dsNames = getDataSourceNames();
if (dsNames.contains(deployedName)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70056, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70056, deployedName));
}
}
private String removeJavaContext(String deployedName) {
if (deployedName.startsWith(JAVA_CONTEXT)) {
deployedName = deployedName.substring(6);
}
return deployedName;
}
private String addJavaContext(String deployedName) {
if (!deployedName.startsWith(JAVA_CONTEXT)) {
deployedName = JAVA_CONTEXT+deployedName;
}
return deployedName;
}
private boolean deleteDS(String deployedName, String... subsystem) throws AdminException {
DefaultOperationRequestBuilder builder = new DefaultOperationRequestBuilder();
final ModelNode request;
try {
addProfileNode(builder);
builder.addNode("subsystem", subsystem[0]); //$NON-NLS-1$
builder.addNode(subsystem[1], deployedName);
builder.setOperationName("remove");
request = builder.buildRequest();
} catch (OperationFormatException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70010, e, "Failed to build operation"); //$NON-NLS-1$
}
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
return false;
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70009, e);
}
return true;
}
@Override
public void undeploy(String deployedName) throws AdminException {
ModelNode request;
try {
request = buildUndeployRequest(deployedName, false);
} catch (OperationFormatException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70010, e, "Failed to build operation"); //$NON-NLS-1$
}
execute(request);
}
public void undeploy(String deployedName, boolean force) throws AdminException {
ModelNode request;
try {
request = buildUndeployRequest(deployedName, force);
} catch (OperationFormatException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70010, e, "Failed to build operation"); //$NON-NLS-1$
}
execute(request);
}
public ModelNode buildUndeployRequest(String name, boolean force) throws OperationFormatException {
ModelNode composite = new ModelNode();
composite.get("operation").set("composite");
composite.get("address").setEmptyList();
ModelNode steps = composite.get("steps");
DefaultOperationRequestBuilder builder;
if(this.domainMode) {
final List<String> serverGroups = Util.getServerGroups(this.connection);
for (String group : serverGroups){
ModelNode groupStep = Util.configureDeploymentOperation(DEPLOYMENT_UNDEPLOY_OPERATION, name, group);
steps.add(groupStep);
}
for (String group : serverGroups) {
ModelNode groupStep = Util.configureDeploymentOperation(DEPLOYMENT_REMOVE_OPERATION, name, group);
steps.add(groupStep);
}
} else if(Util.isDeployedAndEnabledInStandalone(name, this.connection)||force) {
builder = new DefaultOperationRequestBuilder();
builder.setOperationName("undeploy");
builder.addNode("deployment", name);
steps.add(builder.buildRequest());
}
// remove content
builder = new DefaultOperationRequestBuilder();
builder.setOperationName("remove");
builder.addNode("deployment", name);
steps.add(builder.buildRequest());
return composite;
}
@Override
public void deploy(String deployName, InputStream vdb) throws AdminException {
ModelNode request = buildDeployVDBRequest(deployName, vdb, true);
execute(request);
}
@Override
public void deploy(String deployName, InputStream vdb, boolean persist) throws AdminException {
ModelNode request = buildDeployVDBRequest(deployName, vdb, persist);
execute(request);
}
private ModelNode buildDeployVDBRequest(String fileName, InputStream vdb, boolean persist) throws AdminException {
try {
if (Util.isDeploymentInRepository(fileName, this.connection)){
// replace
DefaultOperationRequestBuilder builder = new DefaultOperationRequestBuilder();
builder = new DefaultOperationRequestBuilder();
builder.setOperationName("full-replace-deployment");
builder.addProperty("name", fileName);
byte[] bytes = ObjectConverterUtil.convertToByteArray(vdb);
builder.getModelNode().get("content").get(0).get("bytes").set(bytes);
return builder.buildRequest();
}
//add
ModelNode composite = new ModelNode();
composite.get("operation").set("composite");
composite.get("address").setEmptyList();
ModelNode steps = composite.get("steps");
DefaultOperationRequestBuilder builder = new DefaultOperationRequestBuilder();
builder.setOperationName("add");
builder.addNode("deployment", fileName);
byte[] bytes = ObjectConverterUtil.convertToByteArray(vdb);
builder.getModelNode().get("content").get(0).get("bytes").set(bytes);
ModelNode request = builder.buildRequest();
if (!persist) {
request.get("persistent").set(false); // prevents writing this deployment out to standalone.xml
}
request.get("enabled").set(true);
steps.add(request);
// deploy
if (this.domainMode) {
List<String> serverGroups = Util.getServerGroups(this.connection);
for (String serverGroup : serverGroups) {
steps.add(Util.configureDeploymentOperation("add", fileName, serverGroup));
}
for (String serverGroup : serverGroups) {
steps.add(Util.configureDeploymentOperation("deploy", fileName, serverGroup));
}
} else {
builder = new DefaultOperationRequestBuilder();
builder.setOperationName("deploy");
builder.addNode("deployment", fileName);
request = builder.buildRequest();
if (!persist) {
request.get("persistent").set(false); // prevents writing this deployment out to standalone.xml
}
request.get("enabled").set(true);
steps.add(request);
}
return composite;
} catch (OperationFormatException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70010, e, "Failed to build operation"); //$NON-NLS-1$
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70011, e);
}
}
@Override
public Collection<? extends CacheStatistics> getCacheStats(String cacheType) throws AdminException {
final ModelNode request = buildRequest("teiid", "cache-statistics", "cache-type", cacheType);//$NON-NLS-1$ //$NON-NLS-2$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, VDBMetadataMapper.CacheStatisticsMetadataMapper.INSTANCE, false, false);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70013, e);
}
}
@Override
public Collection<? extends EngineStatistics> getEngineStats() throws AdminException {
final ModelNode request = buildRequest("teiid", "engine-statistics");//$NON-NLS-1$ //$NON-NLS-2$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, VDBMetadataMapper.EngineStatisticsMetadataMapper.INSTANCE, false, false);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70013, e);
}
}
@Override
public Collection<String> getCacheTypes() throws AdminException {
final ModelNode request = buildRequest("teiid", "cache-types");//$NON-NLS-1$ //$NON-NLS-2$
return new LinkedHashSet<String>(executeList(request));
}
private Collection<String> executeList(final ModelNode request) throws AdminException {
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, STRINGMAPPER, true, true);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70014, e);
}
}
private List<String> getChildNodeNames(String subsystem, String childNode) throws AdminException {
final ModelNode request = buildRequest(subsystem, "read-children-names", "child-type", childNode);//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return Util.getList(outcome);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70015, e);
}
}
/**
* /subsystem=datasources:read-children-names(child-type=data-source)
* /subsystem=resource-adapters/resource-adapter={rar-file}:read-resource
* @see org.teiid.adminapi.Admin#getDataSourceNames()
*/
@Override
public Collection<String> getDataSourceNames() throws AdminException {
flush();
Map<String, String> connectionFactoryNames = getConnectionFactoryNames();
return getDataSourceNames(connectionFactoryNames);
}
private Collection<String> getDataSourceNames(
Map<String, String> connectionFactoryNames)
throws AdminException {
Set<String> datasourceNames = new LinkedHashSet<String>();
datasourceNames.addAll(getChildNodeNames("datasources", "data-source"));
datasourceNames.addAll(getChildNodeNames("datasources", "xa-data-source"));
if (connectionFactoryNames == null) {
connectionFactoryNames = getConnectionFactoryNames();
}
datasourceNames.addAll(connectionFactoryNames.keySet());
Set<String> dsNames = new LinkedHashSet<String>();
for (String s:datasourceNames) {
if (s.startsWith(JAVA_CONTEXT)) {
dsNames.add(s.substring(6));
}
else {
dsNames.add(s);
}
}
return dsNames;
}
private Map<String, String> getConnectionFactoryNames() throws AdminException {
Map<String, String> datasourceNames = this.connectionFactoryNames.get();
if (datasourceNames == null) {
datasourceNames = new LinkedHashMap<String, String>();
Set<String> resourceAdapters = getInstalledResourceAdaptorNames();
for (String resource:resourceAdapters) {
getRAConnections(datasourceNames, resource);
}
this.connectionFactoryNames.set(datasourceNames, CACHE_TIME);
}
return datasourceNames;
}
private void getRAConnections(final Map<String, String> datasourceNames, final String rarName) throws AdminException {
cliCall("read-resource", new String[] {"subsystem", "resource-adapters", "resource-adapter", rarName}, null, new ResultCallback() {
@Override
public void onSuccess(ModelNode outcome, ModelNode result) throws AdminProcessingException {
if (result.hasDefined("connection-definitions")) {
List<ModelNode> connDefs = result.get("connection-definitions").asList();
for (ModelNode conn:connDefs) {
Iterator<String> it = conn.keys().iterator();
if (it.hasNext()) {
datasourceNames.put(it.next(), rarName);
}
}
}
}
@Override
public void onFailure(String msg) throws AdminProcessingException {
// no-op
}
});
}
/**
* This will get all deployed RAR names
* /subsystem=resource-adapters:read-children-names(child-type=resource-adapter)
* @return
* @throws AdminException
*/
private Set<String> getInstalledResourceAdaptorNames() throws AdminException {
Set<String> templates = this.installedResourceAdaptorNames.get();
if (templates == null) {
templates = new LinkedHashSet<String>();
templates.addAll(getChildNodeNames("resource-adapters", "resource-adapter"));
this.installedResourceAdaptorNames.set(templates, CACHE_TIME);
}
return templates;
}
// :read-children-names(child-type=deployment)
private Set<String> getResourceAdapterNames(Map<String, String> connFactoryMap) throws AdminException {
Set<String> templates = getDeployedResourceAdaptorNames();
templates.addAll(getInstalledResourceAdaptorNames());
//AS-4776 HACK - BEGIN
if (connFactoryMap == null) {
connFactoryMap = getConnectionFactoryNames();
}
for (String key:connFactoryMap.keySet()) {
templates.remove(key);
}
//AS-4776 HACK - END
return templates;
}
private Set<String> getDeployedResourceAdaptorNames() throws AdminException {
Set<String> templates = this.deployedResourceAdaptorNames.get();
if (templates == null) {
templates = new LinkedHashSet<String>();
List<String> deployments = getChildNodeNames(null, "deployment");
for (String deployment:deployments) {
if (deployment.endsWith(".rar")) {
templates.add(deployment);
}
}
this.deployedResourceAdaptorNames.set(templates, CACHE_TIME);
}
return templates;
}
@Override
public List<String> getDeployments(){
return Util.getDeployments(this.connection);
}
@Override
public Set<String> getDataSourceTemplateNames() throws AdminException {
Set<String> templates = new LinkedHashSet<String>();
templates.addAll(getInstalledJDBCDrivers());
templates.addAll(getResourceAdapterNames(null));
return templates;
}
@Override
public Collection<? extends WorkerPoolStatistics> getWorkerPoolStats() throws AdminException {
final ModelNode request = buildRequest("teiid", "workerpool-statistics");//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, VDBMetadataMapper.WorkerPoolStatisticsMetadataMapper.INSTANCE, false, false);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70020, e);
}
}
@Override
public void cancelRequest(String sessionId, long executionId) throws AdminException {
final ModelNode request = buildRequest("teiid", "cancel-request", "session", sessionId, "execution-id", String.valueOf(executionId));//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70021, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70022, e);
}
}
@Override
public Collection<? extends Request> getRequests() throws AdminException {
final ModelNode request = buildRequest("teiid", "list-requests");//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, RequestMetadataMapper.INSTANCE, false, true);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70023, e);
}
}
@Override
public Collection<? extends Request> getRequestsForSession(String sessionId) throws AdminException {
final ModelNode request = buildRequest("teiid", "list-requests-per-session", "session", sessionId);//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, RequestMetadataMapper.INSTANCE, false, true);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70024, e);
}
}
@Override
public Collection<? extends Session> getSessions() throws AdminException {
final ModelNode request = buildRequest("teiid", "list-sessions");//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, SessionMetadataMapper.INSTANCE, false, true);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70025, e);
}
}
/**
* /subsystem=resource-adapters/resource-adapter=teiid-connector-ws.rar/connection-definitions=foo:read-resource-description
*/
private void buildResourceAdpaterProperties(String rarName, BuildPropertyDefinitions builder) throws AdminException {
cliCall("read-resource-description", new String[] { "subsystem","resource-adapters",
"resource-adapter", rarName,
"connection-definitions", "any" }, null, builder);
}
private boolean isXA(String templateName) {
return templateName.endsWith("-xa");
}
private String stripXA(String templateName) {
if (isXA(templateName)) {
return templateName.substring(0, templateName.length()-3);
}
return templateName;
}
private Set<String> getCustomDatasourceProperties(){
Set<String> props = new HashSet<String>();
props.add("connection-properties");
props.add("DatabaseName");
props.add("PortNumber");
props.add("ServerName");
props.add("connection-url");
return props;
}
/**
* pattern on CLI
* /subsystem=datasources/data-source=foo:read-resource-description
*/
@Override
public Collection<PropertyDefinition> getTemplatePropertyDefinitions(
String templateName) throws AdminException {
BuildPropertyDefinitions builder = new BuildPropertyDefinitions();
ArrayList<PropertyDefinition> props = builder.getPropertyDefinitions();
// RAR properties
Set<String> resourceAdapters = getResourceAdapterNames(null);
if (resourceAdapters.contains(templateName)) {
cliCall("read-rar-description", new String[] {"subsystem", "teiid"}, new String[] {"rar-name",
templateName}, builder);
buildResourceAdpaterProperties(templateName, builder);
return builder.getPropertyDefinitions();
}
// get JDBC properties
if (isXA(templateName)) {
cliCall("read-resource-description", new String[] {"subsystem", "datasources", "data-source",
stripXA(templateName)}, null, builder);
addXAProperties(props);
} else {
cliCall("read-resource-description", new String[] {"subsystem", "datasources", "data-source",
templateName}, null, builder);
addDriverproperties(props);
}
return props;
}
private void addProperty(String name, String displayName,
String description, boolean required, boolean advanced,
ArrayList<PropertyDefinition> props) {
PropertyDefinitionMetadata cp = new PropertyDefinitionMetadata();
cp.setName(name);
cp.setDisplayName(displayName);
cp.setDescription(description); //$NON-NLS-1$
cp.setRequired(required);
cp.setAdvanced(advanced);
props.add(cp);
}
private void addXAProperties(ArrayList<PropertyDefinition> props) {
addProperty("connection-properties", "Addtional XA Datasource Properties",
"The connection-properties element allows you to pass in arbitrary connection "
+ "properties to the Data Source setters methods. "
+ "Supply comma separated name-value pairs. ex:p1=v1,p2=v2",
false, true, props);
addProperty("DatabaseName", "Database Name", "Name of the Database",
true, false, props);
addProperty("ServerName", "Server Name", "Server host name where database exists",
true, false, props);
addProperty("PortNumber", "Port Number", "Port number of the database server",
false, false, props);
addProperty("connection-url", "Connection URL", "Connection URL to the data source",
false, false, props);
}
private void addDriverproperties(ArrayList<PropertyDefinition> props) {
// add driver specific properties
addProperty("connection-properties", "Addtional Driver Properties",
"The connection-properties element allows you to pass in arbitrary connection "
+ "properties to the Driver.connect(url, props) method. "
+ "Supply comma separated name-value pairs. ex:p1=v1,p2=v2",
false, true, props);
}
@Override
@Deprecated
public Collection<? extends PropertyDefinition> getTranslatorPropertyDefinitions(String translatorName) throws AdminException{
BuildPropertyDefinitions builder = new BuildPropertyDefinitions();
Collection<? extends Translator> translators = getTranslators();
for (Translator t:translators) {
if (t.getName().equalsIgnoreCase(translatorName)) {
cliCall("read-translator-properties", new String[] {"subsystem", "teiid"}, new String[] {"translator-name", translatorName, "type", TranlatorPropertyType.OVERRIDE.name()}, builder);
return builder.getPropertyDefinitions();
}
}
throw new AdminProcessingException(AdminPlugin.Event.TEIID70055,
AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70055, translatorName));
}
@Override
public Collection<? extends PropertyDefinition> getTranslatorPropertyDefinitions(
String translatorName, TranlatorPropertyType type) throws AdminException {
BuildPropertyDefinitions builder = new BuildPropertyDefinitions();
Translator translator = getTranslator(translatorName);
if (translator != null) {
if (translator.getName().equalsIgnoreCase(translatorName)) {
cliCall("read-translator-properties", new String[] {"subsystem", "teiid"},
new String[] {"translator-name", translatorName, "type", type.name()}, builder);
return builder.getPropertyDefinitions();
}
}
throw new AdminProcessingException(AdminPlugin.Event.TEIID70055,
AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70055, translatorName));
}
private class BuildPropertyDefinitions extends ResultCallback{
private ArrayList<PropertyDefinition> propDefinitions = new ArrayList<PropertyDefinition>();
@Override
public void onSuccess(ModelNode outcome, ModelNode result) throws AdminProcessingException {
if (result.getType().equals(ModelType.LIST)) {
buildPropertyDefinitions(result.asList());
}
else if (result.get("attributes").isDefined()) {
buildPropertyDefinitions(result.get("attributes").asList());
}
}
@Override
public void onFailure(String msg) throws AdminProcessingException {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70026, msg);
}
ArrayList<PropertyDefinition> getPropertyDefinitions() {
return this.propDefinitions;
}
private void buildPropertyDefinitions(List<ModelNode> propsNodes) {
for (ModelNode node:propsNodes) {
PropertyDefinitionMetadata def = new PropertyDefinitionMetadata();
Set<String> keys = node.keys();
String name = keys.iterator().next();
if (excludeProperty(name)) {
continue;
}
def.setName(name);
node = node.get(name);
if (node.hasDefined("display")) {
def.setDisplayName(node.get("display").asString());
}
else {
def.setDisplayName(name);
}
if (node.hasDefined("description")) {
def.setDescription(node.get("description").asString());
}
if (node.hasDefined("allowed")) {
List<ModelNode> allowed = node.get("allowed").asList();
ArrayList<String> list = new ArrayList<String>();
for(ModelNode m:allowed) {
list.add(m.asString());
}
def.setAllowedValues(list);
}
if (node.hasDefined("required")) {
def.setRequired(node.get("required").asBoolean());
}
if (node.hasDefined("owner")) {
def.addProperty("owner", node.get("owner").asString());
}
if (node.hasDefined("read-only")) {
String access = node.get("read-only").asString();
def.setModifiable(!Boolean.parseBoolean(access));
}
if (node.hasDefined("access-type")) {
String access = node.get("access-type").asString();
if ("read-write".equals(access)) {
def.setModifiable(true);
}
else {
def.setModifiable(false);
}
}
if (node.hasDefined("advanced")) {
String advanced = node.get("advanced").asString();
def.setAdvanced(Boolean.parseBoolean(advanced));
}
if (node.hasDefined("masked")) {
String masked = node.get("masked").asString();
def.setMasked(Boolean.parseBoolean(masked));
}
if (node.hasDefined("category")) {
def.setCategory(node.get("category").asString());
}
if (node.hasDefined("restart-required")) {
def.setRequiresRestart(RestartType.NONE);
}
String type = node.get("type").asString();
if (ModelType.STRING.name().equals(type)) {
def.setPropertyTypeClassName(String.class.getName());
}
else if (ModelType.INT.name().equals(type)) {
def.setPropertyTypeClassName(Integer.class.getName());
}
else if (ModelType.LONG.name().equals(type)) {
def.setPropertyTypeClassName(Long.class.getName());
}
else if (ModelType.BOOLEAN.name().equals(type)) {
def.setPropertyTypeClassName(Boolean.class.getName());
}
else if (ModelType.BIG_INTEGER.name().equals(type)) {
def.setPropertyTypeClassName(BigInteger.class.getName());
}
else if (ModelType.BIG_DECIMAL.name().equals(type)) {
def.setPropertyTypeClassName(BigDecimal.class.getName());
}
if (node.hasDefined("default")) {
if (ModelType.STRING.name().equals(type)) {
def.setDefaultValue(node.get("default").asString());
}
else if (ModelType.INT.name().equals(type)) {
def.setDefaultValue(node.get("default").asInt());
}
else if (ModelType.LONG.name().equals(type)) {
def.setDefaultValue(node.get("default").asLong());
}
else if (ModelType.BOOLEAN.name().equals(type)) {
def.setDefaultValue(node.get("default").asBoolean());
}
else if (ModelType.BIG_INTEGER.name().equals(type)) {
def.setDefaultValue(node.get("default").asBigInteger());
}
else if (ModelType.BIG_DECIMAL.name().equals(type)) {
def.setDefaultValue(node.get("default").asBigDecimal());
}
}
this.propDefinitions.add(def);
}
}
}
private boolean excludeProperty(String name) {
String[] names = { "jndi-name",
"pool-name",
"driver-name",
"reauth-plugin-class-name", "enabled",
"valid-connection-checker-class-name",
"valid-connection-checker-properties",
"stale-connection-checker-class-name",
"stale-connection-checker-properties",
"exception-sorter-class-name",
"exception-sorter-properties",
"use-try-lock",
"allocation-retry",
"allocation-retry-wait-millis",
"jta",
"use-java-context",
"url-selector-strategy-class-name",
"driver-class",
"datasource-class",
"use-ccm"};
for (String n:names) {
if (n.equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
@Override
public Collection<? extends Transaction> getTransactions() throws AdminException {
final ModelNode request = buildRequest("teiid", "list-transactions");//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, TransactionMetadataMapper.INSTANCE, false, true);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70028, e);
}
}
@Override
public void terminateSession(String sessionId) throws AdminException {
final ModelNode request = buildRequest("teiid", "terminate-session", "session", sessionId);//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70029, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70030, e);
}
}
@Override
public void terminateTransaction(String transactionId) throws AdminException {
final ModelNode request = buildRequest("teiid", "terminate-transaction", "xid", transactionId);//$NON-NLS-1$
if (request == null) {
return;
}
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70031, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70032, e);
}
}
@Override
public Translator getTranslator(String deployedName) throws AdminException {
final ModelNode request = buildRequest("teiid", "get-translator", "translator-name", deployedName);//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
List<VDBTranslatorMetaData> list = getDomainAwareList(outcome, VDBMetadataMapper.VDBTranslatorMetaDataMapper.INSTANCE, true, false);
if (!list.isEmpty()) {
return list.get(0);
}
return null;
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70033, e);
}
}
@Override
public Collection<? extends Translator> getTranslators() throws AdminException {
final ModelNode request = buildRequest("teiid", "list-translators");//$NON-NLS-1$ //$NON-NLS-2$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, VDBMetadataMapper.VDBTranslatorMetaDataMapper.INSTANCE, true, true);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70034, e);
}
}
private ModelNode buildRequest(String subsystem, String operationName, String... params) throws AdminException {
DefaultOperationRequestBuilder builder = new DefaultOperationRequestBuilder();
final ModelNode request;
try {
if (subsystem != null) {
addProfileNode(builder);
builder.addNode("subsystem", subsystem); //$NON-NLS-1$
}
builder.setOperationName(operationName);
request = builder.buildRequest();
if (params != null && params.length % 2 == 0) {
for (int i = 0; i < params.length; i+=2) {
builder.addProperty(params[i], params[i+1]);
}
}
} catch (OperationFormatException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70010, e, "Failed to build operation"); //$NON-NLS-1$
}
return request;
}
private void cliCall(String operationName, String[] address, String[] params, ResultCallback callback) throws AdminException {
try {
ModelNode request = buildRequest(operationName, address, params);
ModelNode outcome = this.connection.execute(request);
ModelNode result = null;
if (Util.isSuccess(outcome)) {
if (outcome.hasDefined("result")) {
result = outcome.get("result");
}
callback.onSuccess(outcome, result);
}
else {
callback.onFailure(Util.getFailureDescription(outcome));
}
} catch (OperationFormatException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70010, e, "Failed to build operation"); //$NON-NLS-1$
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70007, e);
}
}
private void cliCall(ModelNode request, ResultCallback callback) throws AdminException {
try {
ModelNode outcome = this.connection.execute(request);
ModelNode result = null;
if (Util.isSuccess(outcome)) {
if (outcome.hasDefined("result")) {
result = outcome.get("result");
}
callback.onSuccess(outcome, result);
}
else {
callback.onFailure(Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70007, e);
}
}
private ModelNode buildRequest(String operationName, String[] address, String[] params)
throws AdminException, OperationFormatException {
if (address.length % 2 != 0) {
throw new IllegalArgumentException("Failed to build operation"); //$NON-NLS-1$
}
DefaultOperationRequestBuilder builder = new DefaultOperationRequestBuilder();
addProfileNode(builder);
for (int i = 0; i < address.length; i+=2) {
builder.addNode(address[i], address[i+1]);
}
builder.setOperationName(operationName);
ModelNode request = builder.buildRequest();
if (params != null && params.length % 2 == 0) {
for (int i = 0; i < params.length; i+=2) {
builder.addProperty(params[i], params[i+1]);
}
}
return request;
}
private <T> List<T> getDomainAwareList(ModelNode operationResult, MetadataMapper<T> mapper, boolean singleInstance, boolean listResult) throws AdminComponentException {
if (this.domainMode) {
List<T> returnList = new ArrayList<T>();
if (!operationResult.has("server-groups")) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70058, AdminPlugin.Util.gs(AdminPlugin.Event.TEIID70058, operationResult));
}
ModelNode serverGroups = operationResult.get("server-groups");
Set<String> serverGroupNames = serverGroups.keys();
outer: for (String serverGroupName:serverGroupNames) {
ModelNode serverGroup = serverGroups.get(serverGroupName);
ModelNode hostGroups = serverGroup.get("host");
Set<String> hostKeys = hostGroups.keys();
for(String hostName:hostKeys) {
ModelNode hostGroup = hostGroups.get(hostName);
Set<String> serverNames = hostGroup.keys();
for (String serverName:serverNames) {
ModelNode server = hostGroup.get(serverName);
if (server.get("response", "outcome").asString().equals(Util.SUCCESS)) {
ModelNode result = server.get("response", RESULT);
if (result.isDefined()) {
if (listResult) {
List<ModelNode> nodeList = result.asList();
for(ModelNode node : nodeList) {
T anObj = mapper.unwrap(node);
if (anObj instanceof DomainAware) {
((AdminObjectImpl)anObj).setServerGroup(serverGroupName);
((AdminObjectImpl)anObj).setServerName(serverName);
((AdminObjectImpl)anObj).setHostName(hostName);
}
returnList.add(anObj);
}
} else {
returnList.add(mapper.unwrap(result));
}
if (singleInstance) {
break outer;
}
}
}
}
}
}
return returnList;
}
if (!listResult) {
if(!operationResult.hasDefined(RESULT)) {
return Collections.emptyList();
}
return Arrays.asList(mapper.unwrap(operationResult.get(RESULT)));
}
return getList(operationResult, mapper);
}
private <T> List<T> getList(ModelNode operationResult, MetadataMapper<T> mapper) {
if(!operationResult.hasDefined(RESULT)) {
return Collections.emptyList();
}
List<ModelNode> nodeList = operationResult.get(RESULT).asList(); //$NON-NLS-1$
if(nodeList.isEmpty()) {
return Collections.emptyList();
}
List<T> list = new ArrayList<T>(nodeList.size());
for(ModelNode node : nodeList) {
list.add(mapper.unwrap(node));
}
return list;
}
@Override
public VDB getVDB(String vdbName, String vdbVersion) throws AdminException {
final ModelNode request = buildRequest("teiid", "get-vdb", "vdb-name", vdbName, "vdb-version", vdbVersion);//$NON-NLS-1$
if (request == null) {
return null;
}
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
List<VDBMetaData> list = getDomainAwareList(outcome, VDBMetadataMapper.INSTANCE, true, false);
if (!list.isEmpty()) {
return list.get(0);
}
return null;
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70035, e);
}
}
@Override
public List<? extends VDB> getVDBs() throws AdminException {
final ModelNode request = buildRequest("teiid", "list-vdbs");//$NON-NLS-1$ //$NON-NLS-2$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
return getDomainAwareList(outcome, VDBMetadataMapper.INSTANCE, true, true);
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70036, e);
}
}
@Override
public void addDataRoleMapping(String vdbName, String vdbVersion, String dataRole, String mappedRoleName) throws AdminException {
final ModelNode request = buildRequest("teiid", "add-data-role",
"vdb-name", vdbName,
"vdb-version", vdbVersion,
"data-role", dataRole,
"mapped-role", mappedRoleName);//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70039, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70040, e);
}
}
@Override
public void clearCache(String cacheType, String vdbName, int vdbVersion)
throws AdminException {
clearCache(cacheType, vdbName, String.valueOf(vdbVersion));
}
@Override
public void addDataRoleMapping(String vdbName, int vdbVersion,
String dataRole, String mappedRoleName) throws AdminException {
addDataRoleMapping(vdbName, String.valueOf(vdbVersion), dataRole, mappedRoleName);
}
@Override
public void removeDataRoleMapping(String vdbName, int vdbVersion,
String dataRole, String mappedRoleName) throws AdminException {
removeDataRoleMapping(vdbName, String.valueOf(vdbVersion), dataRole, mappedRoleName);
}
@Override
public void setAnyAuthenticatedForDataRole(String vdbName,
int vdbVersion, String dataRole, boolean anyAuthenticated)
throws AdminException {
setAnyAuthenticatedForDataRole(vdbName, String.valueOf(vdbVersion), dataRole, anyAuthenticated);
}
@Override
public void changeVDBConnectionType(String vdbName, int vdbVersion,
ConnectionType type) throws AdminException {
changeVDBConnectionType(vdbName, String.valueOf(vdbVersion), type);
}
@Override
public void updateSource(String vdbName, int vdbVersion,
String sourceName, String translatorName, String dsName)
throws AdminException {
updateSource(vdbName, String.valueOf(vdbVersion), sourceName, translatorName, dsName);
}
@Override
public void addSource(String vdbName, int vdbVersion, String modelName,
String sourceName, String translatorName, String dsName)
throws AdminException {
addSource(vdbName, String.valueOf(vdbVersion), modelName, sourceName, translatorName, dsName);
}
@Override
public VDB getVDB(String vdbName, int vdbVersion) throws AdminException {
return getVDB(vdbName, String.valueOf(vdbVersion));
}
@Override
public void removeSource(String vdbName, int vdbVersion,
String modelName, String sourceName) throws AdminException {
removeSource(vdbName, String.valueOf(vdbVersion), modelName, sourceName);
}
@Override
public void restartVDB(String vdbName, int vdbVersion, String... models)
throws AdminException {
restartVDB(vdbName, String.valueOf(vdbVersion), models);
}
@Override
public String getSchema(String vdbName, int vdbVersion,
String modelName, EnumSet<SchemaObjectType> allowedTypes,
String typeNamePattern) throws AdminException {
return getSchema(vdbName, String.valueOf(vdbVersion), modelName, allowedTypes, typeNamePattern);
}
@Override
public void removeDataRoleMapping(String vdbName, String vdbVersion, String dataRole, String mappedRoleName) throws AdminException {
final ModelNode request = buildRequest("teiid", "remove-data-role",
"vdb-name", vdbName,
"vdb-version", vdbVersion,
"data-role", dataRole,
"mapped-role", mappedRoleName);//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70041, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70042, e);
}
}
@Override
public void setAnyAuthenticatedForDataRole(String vdbName, String vdbVersion, String dataRole, boolean anyAuthenticated) throws AdminException {
ModelNode request = buildRequest("teiid", "add-anyauthenticated-role",
"vdb-name", vdbName,
"vdb-version", vdbVersion,
"data-role", dataRole); //$NON-NLS-1$
if (!anyAuthenticated) {
request = buildRequest("teiid", "remove-anyauthenticated-role",
"vdb-name", vdbName,
"vdb-version", vdbVersion,
"data-role", dataRole); //$NON-NLS-1$
}
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70043, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70044, e);
}
}
@Override
public void changeVDBConnectionType(String vdbName, String vdbVersion, ConnectionType type) throws AdminException {
final ModelNode request = buildRequest("teiid", "change-vdb-connection-type",
"vdb-name", vdbName,
"vdb-version", vdbVersion,
"connection-type", type.name());//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70045, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70046, e);
}
}
@Override
public void updateSource(String vdbName, String vdbVersion, String sourceName, String translatorName,
String dsName) throws AdminException {
final ModelNode request = buildRequest("teiid", "update-source",
"vdb-name", vdbName,
"vdb-version", vdbVersion,
"source-name", sourceName,
"translator-name", translatorName,
"ds-name", dsName);//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70047, Util.getFailureDescription(outcome));
}
} catch (Exception e) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70048, e);
}
}
@Override
public void addSource(String vdbName, String vdbVersion, String modelName, String sourceName, String translatorName,
String dsName) throws AdminException {
final ModelNode request = buildRequest("teiid", "add-source",
"vdb-name", vdbName,
"vdb-version", vdbVersion,
"model-name", modelName,
"source-name", sourceName,
"translator-name", translatorName,
"ds-name", dsName);//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70047, Util.getFailureDescription(outcome));
}
} catch (Exception e) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70048, e);
}
}
@Override
public void removeSource(String vdbName, String vdbVersion, String modelName, String sourceName) throws AdminException {
final ModelNode request = buildRequest("teiid", "remove-source",
"vdb-name", vdbName,
"vdb-version", vdbVersion,
"model-name", modelName,
"source-name", sourceName);//$NON-NLS-1$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70047, Util.getFailureDescription(outcome));
}
} catch (Exception e) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70048, e);
}
}
@Override
public void markDataSourceAvailable(String jndiName) throws AdminException {
final ModelNode request = buildRequest("teiid", "mark-datasource-available","ds-name", jndiName);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70049, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70050, e);
}
}
@Override
public void restartVDB(String vdbName, String vdbVersion, String... models) throws AdminException {
ModelNode request = null;
String modelNames = null;
if (models != null && models.length > 0) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < models.length-1; i++) {
sb.append(models[i]).append(",");
}
sb.append(models[models.length-1]);
modelNames = sb.toString();
}
if (modelNames != null) {
request = buildRequest("teiid", "restart-vdb",
"vdb-name", vdbName,
"vdb-version", vdbVersion,
"model-names", modelNames);//$NON-NLS-1$
}
else {
request = buildRequest("teiid", "restart-vdb",
"vdb-name", vdbName,
"vdb-version", vdbVersion);//$NON-NLS-1$
}
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70045, Util.getFailureDescription(outcome));
}
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70046, e);
}
}
@Override
public String getSchema(String vdbName, String vdbVersion,
String modelName, EnumSet<SchemaObjectType> allowedTypes,
String typeNamePattern) throws AdminException {
ModelNode request = null;
ArrayList<String> params = new ArrayList<String>();
params.add("vdb-name");
params.add(vdbName);
params.add("vdb-version");
params.add(vdbVersion);
params.add("model-name");
params.add(modelName);
if (allowedTypes != null) {
params.add("entity-type");
StringBuilder sb = new StringBuilder();
for (SchemaObjectType type:allowedTypes) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(type.name());
}
params.add(sb.toString());
}
if (typeNamePattern != null) {
params.add("entity-pattern");
params.add(typeNamePattern);
}
request = buildRequest("teiid", "get-schema", params.toArray(new String[params.size()]));//$NON-NLS-1$ //$NON-NLS-2$
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70045, Util.getFailureDescription(outcome));
}
List<String> vals = getDomainAwareList(outcome, STRINGMAPPER, true, false);
if (!vals.isEmpty()) {
return vals.get(0);
}
return null;
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70046, e);
}
}
@Override
public String getQueryPlan(String sessionId, long executionId) throws AdminException {
final ModelNode request = buildRequest("teiid", "get-query-plan", "session", sessionId, "execution-id", String.valueOf(executionId));//$NON-NLS-1$
if (request == null) {
return null;
}
try {
ModelNode outcome = this.connection.execute(request);
if (!Util.isSuccess(outcome)) {
throw new AdminProcessingException(AdminPlugin.Event.TEIID70021, Util.getFailureDescription(outcome));
}
List<String> vals = getDomainAwareList(outcome, STRINGMAPPER, true, false);
if (!vals.isEmpty()) {
return vals.get(0);
}
return null;
} catch (IOException e) {
throw new AdminComponentException(AdminPlugin.Event.TEIID70022, e);
}
}
@Override
public void restart() {
try {
cliCall("reload", new String[] {}, new String[] {}, new ResultCallback());
} catch (AdminException e) {
//ignore
}
}
public void flush() {
this.connectionFactoryNames.set(null, 0);
this.deployedResourceAdaptorNames.set(null, 0);
this.installedResourceAdaptorNames.set(null, 0);
}
}
static class Expirable<T> {
private long expires;
private T t;
public T get() {
if (this.t == null || System.currentTimeMillis() >= this.expires) {
this.t = null;
}
return this.t;
}
public void set(T t, long cacheTimeInMillis) {
this.expires = System.currentTimeMillis()+cacheTimeInMillis;
this.t = t;
}
}
}