/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.runtime.importer;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
import org.teiid.core.designer.util.CoreStringUtil;
import org.teiid.designer.common.xml.XmlUtil;
import org.teiid.designer.runtime.DqpPlugin;
import org.teiid.designer.runtime.PreferenceConstants;
import org.teiid.designer.runtime.spi.ExecutionConfigurationEvent;
import org.teiid.designer.runtime.spi.ExecutionConfigurationEvent.EventType;
import org.teiid.designer.runtime.spi.ExecutionConfigurationEvent.TargetType;
import org.teiid.designer.runtime.spi.IExecutionConfigurationListener;
import org.teiid.designer.runtime.spi.ITeiidDataSource;
import org.teiid.designer.runtime.spi.ITeiidServer;
import org.teiid.designer.runtime.spi.ITeiidTranslator;
import org.teiid.designer.runtime.spi.ITeiidVdb;
import org.teiid.designer.runtime.spi.TeiidPropertyDefinition;
import org.teiid.designer.runtime.version.spi.ITeiidServerVersion;
/**
*
*/
public final class ImportManager implements IExecutionConfigurationListener {
private static final String DYNAMIC_VDB_SUFFIX = "-vdb.xml"; //$NON-NLS-1$
public static final String IMPORT_SRC_MODEL = "SrcModel"; //$NON-NLS-1$
private static final String JNDI_PROPERTY_KEY = "jndi-name"; //$NON-NLS-1$
/**
* The Teiid Instance being used for importers (may be <code>null</code>).
*/
private volatile AtomicReference<ITeiidServer> importServer = new AtomicReference<ITeiidServer>();
private static ImportManager instance;
/**
* @return singleton instance
*/
public static ImportManager getInstance() {
if (instance == null) {
instance = new ImportManager();
}
return instance;
}
private ImportManager() {}
/**
* {@inheritDoc}
*
* @see org.teiid.designer.runtime.spi.IExecutionConfigurationListener#configurationChanged(org.teiid.designer.runtime.spi.ExecutionConfigurationEvent)
*/
@Override
public void configurationChanged( ExecutionConfigurationEvent event ) {
if (event.getEventType().equals(EventType.DEFAULT) && event.getTargetType().equals(TargetType.SERVER)) {
setImportServer(event.getUpdatedServer());
}
}
private void setImportServer( ITeiidServer teiidServer ) {
// set new server
this.importServer.set(teiidServer);
}
private ITeiidServer getImportServer() {
return this.importServer.get();
}
/**
* Determine if a valid server is available for dynamic vdb import. The server must be
* running, and it must be version 8.x or higher.
* @return 'true' if the server is valid
*/
public boolean isValidImportServer() {
ITeiidServer importServer = getImportServer();
// If no server, or not connected - invalid
if(importServer==null || !importServer.isConnected()) {
return false;
}
// If this is a Teiid 7 server, we cant do this type of import
ITeiidServerVersion version = importServer.getServerVersion();
if(version.isSevenServer()) {
return false;
}
return true;
}
public boolean vdbExists(String vdbName) {
try {
return getImportServer().getVdb(vdbName) != null;
} catch (Exception e) {
return false;
}
}
/**
* Get the dataSource with the specified Name. The supplied name is the 'pool-name' property specified on the datasource.
* @param sourceName datasource name
* @return the DataSource
* @throws Exception the exception
*/
private ITeiidDataSource getDataSource( String sourceName ) throws Exception {
return getImportServer().getDataSource(sourceName);
}
/**
* @param vdbName name to use for the VDB
* @param sourceName the dataSource to use for the import
* @param translatorName the name of the translator
* @param modelPropertyMap the Map of optional model properties
* @param monitor the progress monitor
* @return status of the deployment
*/
public IStatus deployDynamicVdb(String vdbName, String sourceName, String translatorName, Map<String,String> modelPropertyMap, IProgressMonitor monitor) {
// Work remaining for progress monitor
int workRemaining = 100;
IStatus resultStatus = Status.OK_STATUS;
// Deployment name for vdb must end in '-vdb.xml'
String deploymentName = vdbName+DYNAMIC_VDB_SUFFIX;
// Deploy the desired source
String importSourceModel = vdbName+IMPORT_SRC_MODEL;
// Get the DataSource
ITeiidDataSource dataSource;
try {
dataSource = getDataSource(sourceName);
} catch (Exception ex) {
resultStatus = new Status(IStatus.ERROR, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerGetDatasourceError, sourceName));
return resultStatus;
}
// data source could be null;
if( dataSource == null ) {
return new Status(IStatus.ERROR, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerGetDatasourceError, sourceName));
}
monitor.worked(10);
workRemaining -= 10;
String sourceJndiName = dataSource.getPropertyValue(JNDI_PROPERTY_KEY);
if(CoreStringUtil.isEmpty(sourceJndiName)) {
sourceJndiName=sourceName;
}
// Get Dynamic VDB string
String dynamicVdbString = createDynamicVdb(vdbName,1,translatorName,importSourceModel,sourceJndiName,modelPropertyMap);
// If an import VDB with the supplied name exists, undeploy it first
ITeiidVdb deployedImportVdb;
try {
deployedImportVdb = getImportServer().getVdb(vdbName);
if( deployedImportVdb != null ) {
getImportServer().undeployDynamicVdb(deployedImportVdb.getName());
}
} catch (Exception ex) {
resultStatus = new Status(IStatus.ERROR, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerUndeployVdbError, vdbName));
return resultStatus;
}
monitor.worked(10);
workRemaining -= 10;
// Deploy the Dynamic VDB
try {
getImportServer().deployDynamicVdb(deploymentName,new ByteArrayInputStream(dynamicVdbString.getBytes("UTF-8"))); //$NON-NLS-1$
} catch (Exception ex) {
resultStatus = new Status(IStatus.ERROR, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerDeployVdbError, vdbName));
return resultStatus;
}
monitor.worked(10);
workRemaining -= 10;
// Wait until vdb is done loading, up to timeout sec
int timeoutSec = DqpPlugin.getInstance().getPreferences().getInt(PreferenceConstants.TEIID_IMPORTER_TIMEOUT_SEC, PreferenceConstants.TEIID_IMPORTER_TIMEOUT_SEC_DEFAULT);
boolean finishedLoading = false;
try {
finishedLoading = waitForVDBLoad(vdbName,timeoutSec,monitor,workRemaining);
} catch (InterruptedException ie) {
resultStatus = new Status(IStatus.CANCEL, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerVdbLoadingInterruptedError, vdbName));
return resultStatus;
} catch (Exception ex) {
resultStatus = new Status(IStatus.ERROR, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerVdbLoadingError, vdbName));
return resultStatus;
}
// If the VDB finished loading, check Active state
if(finishedLoading) {
boolean isVDBActive;
try {
isVDBActive = getImportServer().isVdbActive(vdbName);
} catch (Exception ex) {
resultStatus = new Status(IStatus.ERROR, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerVdbGetStateError, vdbName));
return resultStatus;
}
// VDB Active = success
if(isVDBActive) {
resultStatus = Status.OK_STATUS;
} else {
resultStatus = new Status(IStatus.ERROR, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerVdbInactiveStateError, vdbName));
}
} else {
resultStatus = new Status(IStatus.ERROR, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerVdbLoadingNotCompleteError, timeoutSec));
}
return resultStatus;
}
public String createDynamicVdbString(String vdbName, String sourceName, String translatorName, Map<String,String> modelPropertyMap) {
// Deploy the desired source
String importSourceModel = vdbName+IMPORT_SRC_MODEL;
// Get the DataSource
ITeiidDataSource dataSource;
try {
dataSource = getDataSource(sourceName);
} catch (Exception ex) {
return Messages.ImportManagerDynamicVdbTextCannotBeGeneratedError;
}
String sourceJndiName = dataSource.getPropertyValue(JNDI_PROPERTY_KEY);
if(CoreStringUtil.isEmpty(sourceJndiName)) {
sourceJndiName=sourceName;
}
// Get Dynamic VDB string
return createDynamicVdb(vdbName,1,translatorName,importSourceModel,sourceJndiName,modelPropertyMap);
}
/**
* Get the Schema DDL for the import model in the supplied VDB
* @param vdbName the name of the VDB
* @return the Schema DDL for the import VDB Src Model
* @throws Exception the exception
*/
public String getSchema(String vdbName) throws Exception {
return getImportServer().getSchema(vdbName, "1", vdbName+IMPORT_SRC_MODEL);
}
/**
* Undeploy the importer vdb (and datasource)
* @param importerVdbName the vdb name
* @return status of the operations
*/
public IStatus undeployVdb(String importerVdbName) {
IStatus resultStatus = null;
// If an import VDB with the supplied name exists, undeploy it
ITeiidVdb deployedImportVdb;
try {
deployedImportVdb = getImportServer().getVdb(importerVdbName);
if( deployedImportVdb != null ) {
getImportServer().undeployDynamicVdb(deployedImportVdb.getName());
}
} catch (Exception ex) {
resultStatus = new Status(IStatus.ERROR, DqpPlugin.PLUGIN_ID, NLS.bind(Messages.ImportManagerUndeployVdbError, importerVdbName));
}
return resultStatus;
}
/*
* Get the deploymentName for the supplied VDB
* @param deployedVdb the vdb
* @return the vdb deployment name
*/
private String getVdbDeploymentName(ITeiidVdb deployedVdb) {
String fullVdbName = deployedVdb.getPropertyValue("deployment-name"); //$NON-NLS-1$
return fullVdbName;
}
/*
* Create a new, blank deployment for the provided vdbName and version
* @param vdbName name of the VDB
* @param vdbVersion the VDB version
* @param translatorName the translator
* @param datasourceName the dataSource name
* @param datasourceJndeName the dataSource jndi name
* @param modelProps the model properties
* @return the VDB deployment string
*/
public String createDynamicVdb(String vdbName, int vdbVersion, String translatorName, String datasourceName, String datasourceJndiName,
Map<String,String> modelProps) {
StringBuffer sb = new StringBuffer();
String deploymentName = vdbName+DYNAMIC_VDB_SUFFIX;
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"); //$NON-NLS-1$
sb.append("\n<vdb name=\""+vdbName+"\" version=\""+vdbVersion+"\">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
sb.append("\n\t<description>Importer VDB</description>"); //$NON-NLS-1$
sb.append("\n\t<property name=\"UseConnectorMetadata\" value=\"true\" />"); //$NON-NLS-1$
sb.append("\n\t<property name=\"deployment-name\" value=\""+deploymentName+"\" />"); //$NON-NLS-1$ //$NON-NLS-2$
sb.append("\n\t<model name=\""+datasourceName+"\" type=\"PHYSICAL\" visible=\"true\">"); //$NON-NLS-1$ //$NON-NLS-2$
Set<String> propNames = modelProps.keySet();
for(String propName : propNames) {
String propValue = XmlUtil.escapeCharacterData(modelProps.get(propName));
sb.append("\n\t\t<property name=\""+propName+"\" value=\""+propValue+"\" />"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
sb.append("\n\t\t<source name=\""+datasourceName+"\" translator-name=\""+translatorName+"\" connection-jndi-name=\""+datasourceJndiName+"\" />"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
sb.append("\n\t</model>"); //$NON-NLS-1$
sb.append("\n</vdb>"); //$NON-NLS-1$
return sb.toString();
}
/*
* Helper method - waits for the VDB to finish loading
* @param vdbName the name of the VDB
* @param timeoutInSecs time to wait before timeout
* @param monitor the progress monitor
* @param workRemaining the number of work units remaining
* @return 'true' if vdb found and is not 'Loading', 'false' otherwise.
*/
private boolean waitForVDBLoad(String vdbName, int timeoutInSecs, IProgressMonitor monitor, int workRemaining) throws Exception {
final int sleepDurationSec = 5;
int increments = timeoutInSecs / sleepDurationSec;
int workIncrement = Math.round((float)workRemaining / increments);
long waitUntil = System.currentTimeMillis() + timeoutInSecs*1000;
// Timeout of zero or less means no timeout...
if (timeoutInSecs < 1) {
waitUntil = Long.MAX_VALUE;
}
boolean first = true;
do {
// Pause 5 sec before subsequent attempts
if (!first) {
try {
Thread.sleep(sleepDurationSec*1000);
} catch (InterruptedException e) {
break;
}
} else {
first = false;
}
monitor.worked(workIncrement);
// Check for cancellation request. If cancelled, throw InterruptedException
if(monitor.isCanceled()) {
monitor.setCanceled(true);
throw new InterruptedException("The operation was cancelled"); //$NON-NLS-1$
}
boolean isActive = getImportServer().isVdbActive(vdbName);
boolean isLoading = getImportServer().isVdbLoading(vdbName);
boolean hasFailed = getImportServer().hasVdbFailed(vdbName);
boolean hasValidityErrors = !getImportServer().getVdb(vdbName).getValidityErrors().isEmpty();
if(!isLoading || hasFailed || hasValidityErrors || isActive) return true;
} while (System.currentTimeMillis() < waitUntil);
return false;
}
/**
* Get the server display name
* @return the display name
* @throws Exception the exception
*/
public String getDisplayName() throws Exception {
return getImportServer().getParentName();
}
/**
* Get the server translators
* @return the collection of translators
* @throws Exception the exception
*/
public Collection<ITeiidTranslator> getTranslators() throws Exception {
return getImportServer().getTranslators();
}
/**
* Get the translator
* @return the collection of translators
* @throws Exception the exception
*/
public ITeiidTranslator getTranslator(String name) throws Exception {
for( ITeiidTranslator translator : getTranslators() ) {
if( name.equalsIgnoreCase(translator.getName()) ) return translator;
}
return null;
}
/**
* Delete dataSource with the provided jndiName
* @param jndiName the source jndi name
* @throws Exception the exception
*/
public void deleteDataSource(String jndiName) throws Exception {
getImportServer().deleteDataSource(jndiName);
}
/**
* Deploy the specified driver file
* @param jarOrRarFile the driver file
* @throws Exception the exception
*/
public void deployDriver(File jarOrRarFile) throws Exception {
getImportServer().deployDriver(jarOrRarFile);
}
/**
* Get the model schema for the specified vdb
* @param vdbName the Vdb name
* @param vdbVersion the Vdb version
* @param modelName the model name
* @return the Schema DDL
* @throws Exception the exception
*/
public String getSchema(String vdbName,
String vdbVersion,
String modelName) throws Exception {
return getImportServer().getSchema(vdbName, vdbVersion, modelName);
}
/**
* Get the Teiid Instance data sources
* @return the collection of Data Sources
* @throws Exception the exception
*/
public Collection<ITeiidDataSource> getDataSources() throws Exception {
return getImportServer().getDataSources();
}
/**
* Get the Servers DataSource Template names
* @return the Set of Template names
* @throws Exception the exception
*/
public Set<String> getDataSourceTemplateNames() throws Exception {
return getImportServer().getDataSourceTemplateNames();
}
/**
* Get the property definitions for the provided template name
* @param templateName the template name
* @return the collection of TeiidPropertyDefinition
* @throws Exception the exception
*/
public Collection<TeiidPropertyDefinition> getTemplatePropertyDefns(String templateName) throws Exception {
return getImportServer().getTemplatePropertyDefns(templateName);
}
/**
* Get or create the specified datasource
* @param displayName the source display name
* @param jndiName the jndi name
* @param typeName the ds type
* @param properties the datasource properties
* @return the Created data source
* @throws Exception the exception
*/
public ITeiidDataSource getOrCreateDataSource(String displayName,
String jndiName,
String typeName,
Properties properties) throws Exception {
return getImportServer().getOrCreateDataSource(displayName, jndiName, typeName, properties);
}
/**
* Undeploy the specified VDB
* @param vdbName the vdb name
* @throws Exception the exception
*/
public void undeployDynamicVdb(String vdbName) throws Exception {
getImportServer().undeployDynamicVdb(vdbName);
}
/**
* Deploy the specified dynamic vdb
* @param deploymentName the deployment name
* @param inStream dynamic vdb inputStream
* @throws Exception the exception
*/
public void deployDynamicVdb(String deploymentName, InputStream inStream) throws Exception {
getImportServer().deployDynamicVdb(deploymentName, inStream);
}
/**
* Get the Properties for the specified DataSource
* @param dataSourceName the dataSource name
* @return the Properties for the data source
* @throws Exception the exception
*/
public Properties getDataSourceProperties(String dataSourceName) throws Exception {
return getImportServer().getDataSourceProperties(dataSourceName);
}
/**
* Return the version of the current import server - null if not defined or not connected
* @return the Teiid Instance version
*/
public ITeiidServerVersion getServerVersion() {
ITeiidServer importServer = getImportServer();
// If no server, or not connected - invalid
if(importServer==null || !importServer.isConnected()) {
return null;
}
return importServer.getServerVersion();
}
}