/* * 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.vdb; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Map; import java.util.Properties; import java.util.concurrent.CopyOnWriteArrayList; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.validation.Schema; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.FileUtils; import org.teiid.core.designer.util.StringUtilities; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.util.KeyInValueHashMap; import org.teiid.designer.core.util.KeyInValueHashMap.KeyFromValueAdapter; import org.teiid.designer.roles.DataRole; import org.teiid.designer.vdb.dynamic.DynamicVdb; import org.teiid.designer.vdb.manifest.VdbElement; import org.xml.sax.SAXException; /** * @author blafond * */ public abstract class BasicVdb extends AbstractVdbObject implements Vdb { private class TranslatorOverrideKeyAdapter implements KeyFromValueAdapter<String, TranslatorOverride> { @Override public String getKey(TranslatorOverride value) { return value.getName(); } } private class VdbEntryKeyAdapter implements KeyFromValueAdapter<String, VdbEntry> { @Override public String getKey(VdbEntry value) { return value.getName(); } } private class DataRoleKeyAdapter implements KeyFromValueAdapter<String, DataRole> { @Override public String getKey(DataRole value) { return value.getName(); } } private class ImportVdbKeyAdapter implements KeyFromValueAdapter<String, VdbImportVdbEntry> { @Override public String getKey(VdbImportVdbEntry value) { return value.getName(); } } private IFile sourceFile; // VDBs have the following possible structure /* ATTRIBUTES <xs:attribute name="name" type="xs:string" use="required"/> <xs:attribute name="version" type="xs:int" use="required"/> */ private String version = "1"; /* Elements: <xs:element name="description" type="xs:string" minOccurs="0"/> <xs:element name="connection-type" type="xs:string" minOccurs="0" default="BY_VERSION"/> <xs:element name="property" type="property" minOccurs="0" maxOccurs="unbounded"/> */ private String connectionType; // known properties /* <property name="preview" value="false"/> <property name="query-timeout" value="23000"/> <property name="allowed-languages" value="ddddd, sssss"/> <property name="security-domain" value="ssdfsdf"/> <property name="gss-pattern" value="aaaaadddd"/> <property name="password-pattern" value="asdfasdfasdf*.xyz"/> <property name="authentication-type" value="none"/> <property name="validationDateTime" value="Mon Mar 16 09:16:10 CDT 2015"/> <property name="validationVersion" value="8.7.0"/> */ private boolean preview; private int queryTimeout = DEFAULT_TIMEOUT; private AllowedLanguages allowedLanguages = new AllowedLanguages(this); private String securityDomain; private String gssPattern; private String passwordPattern; private String authenticationType; private Date validateDateTime; private String validationVersion; private boolean autoGenerateRESTWar; private KeyInValueHashMap<String, VdbImportVdbEntry> importVdbs = new KeyInValueHashMap<String, VdbImportVdbEntry>(new ImportVdbKeyAdapter()); private KeyInValueHashMap<String, TranslatorOverride> translatorOverrides = new KeyInValueHashMap<String, TranslatorOverride>(new TranslatorOverrideKeyAdapter()); private KeyInValueHashMap<String, DataRole> dataRoles = new KeyInValueHashMap<String, DataRole>(new DataRoleKeyAdapter()); private final CopyOnWriteArrayList<PropertyChangeListener> listeners = new CopyOnWriteArrayList<PropertyChangeListener>(); private IStatus currentStatus; /** * Default constructor */ protected BasicVdb() { super(); } /** * @param sourceFile the source file of the vdb * * <p> * <li>The name of the vdb is the source file name WITHOUT the extension * <li>The file name ({@link #getFileName()}) is the source file name WITH the extension * <li>The path of the vdb can be extracted from {@link #getSourceFile()} * @throws Exception */ protected BasicVdb(IFile sourceFile) throws Exception { super(); this.sourceFile = sourceFile; setName(FileUtils.getNameWithoutExtension(sourceFile)); // Create folder for VDB in state folder File stagingFolder = getStagingFolder(); if (stagingFolder != null) stagingFolder.mkdirs(); read(sourceFile); setChanged(false); currentStatus = Status.OK_STATUS; } /** * This will import the contents of the vdb from the given file and * replace the point this vdb at the given file * * @param file * * @throws Exception */ public abstract void read(final IFile file) throws Exception; @Override public void setDescription(String newDescription) { if (StringUtilities.isEmpty(newDescription)) newDescription = null; String oldDescription = getDescription(); if (StringUtilities.isEmpty(newDescription)) oldDescription = null; if (StringUtilities.areDifferent(oldDescription, newDescription)) { super.setDescription(newDescription); setModified(this, Event.DESCRIPTION, oldDescription, newDescription); } } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#addDataRole(DataRole) */ @Override public boolean addDataRole(DataRole dataRole) { if (dataRoles.add(dataRole)) { dataRole.setVdb(this); setModified(this, Event.DATA_POLICY_ADDED, null, dataRole); return true; } return false; } /** * (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#addImport(java.lang.String) */ @Override public VdbImportVdbEntry addImport(String vdbName, String version) { VdbImportVdbEntry importVdbEntry = new VdbImportVdbEntry(this, vdbName); importVdbEntry.setVersion(version); importVdbs.add(importVdbEntry); setModified(this, Event.IMPORT_VDB_ENTRY_ADDED, null, importVdbEntry); return importVdbEntry; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#addImport(org.teiid.designer.vdb.VdbImportVdbEntry) */ @Override public boolean addImport(VdbImportVdbEntry vdbImport) { if (importVdbs.add(vdbImport)) { vdbImport.setVdb(this); setModified(this, Event.IMPORT_VDB_ENTRY_ADDED, null, vdbImport); return true; } return false; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#addTranslator(org.teiid.designer.vdb.TranslatorOverride) */ @Override public boolean addTranslator(final TranslatorOverride translatorOverride) { if (this.translatorOverrides.add(translatorOverride)) { translatorOverride.setVdb(this); setModified(this, Event.TRANSLATOR_OVERRIDE_ADDED, null, translatorOverride); return true; } return false; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getJaxbContext() */ @Override public JAXBContext getJaxbContext() throws JAXBException { return JAXBContext.newInstance(new Class<?>[] { VdbElement.class }); } /** (non-Javadoc) * @return schema * @throws SAXException * @see org.teiid.designer.vdb.Vdb#getManifestSchema() */ @Override public Schema getManifestSchema() throws SAXException { return VdbUtil.getManifestSchema(); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getConnectionType() */ @Override public String getConnectionType() { return connectionType; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getDataRoles() */ @Override public Collection<DataRole> getDataRoles() { return Collections.unmodifiableCollection(dataRoles.values()); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getImports() */ @Override public Collection<VdbImportVdbEntry> getImports() { return Collections.unmodifiableCollection(importVdbs.values()); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getStagingFolder() */ @Override public File getStagingFolder() { return VdbPlugin.singleton().getStateLocation().append(getSourceFile().getFullPath()).toFile(); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getSourceFile() */ @Override public IFile getSourceFile() { return sourceFile; } /** (non-Javadoc) * @param file */ protected void setSourceFile(IFile file) { this.sourceFile = file; } @Override public String getFileName() { if (sourceFile == null) return null; return sourceFile.getName(); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getTranslators() */ @Override public Collection<TranslatorOverride> getTranslators() { return Collections.unmodifiableCollection(translatorOverrides.values()); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getVersion() */ @Override public String getVersion() { return version; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#isPreview() */ @Override public boolean isPreview() { return preview; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#removeDataRole(java.lang.String) */ @Override public boolean removeDataRole(String dataRoleToRemove) { DataRole dataRole = this.dataRoles.get(dataRoleToRemove); if (dataRole == null) return false; dataRole = this.dataRoles.remove(dataRole); if (dataRole != null) { setModified(this, Event.DATA_POLICY_REMOVED, dataRole, null); return true; } return false; } @Override public boolean removeImport(VdbImportVdbEntry importToRemove) { if (importVdbs.remove(importToRemove) != null) { setModified(this, Event.IMPORT_VDB_ENTRY_REMOVED, importToRemove, null); return true; } return false; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#removeImport(java.lang.String) */ @Override public boolean removeImport(String importToRemove) { VdbImportVdbEntry importEntry = this.importVdbs.get(importToRemove); if (importEntry == null) return false; return removeImport(importEntry); } @Override public void removeAllImports() { Collection<VdbImportVdbEntry> entries = new ArrayList<VdbImportVdbEntry>(this.importVdbs.values()); if (entries.isEmpty()) return; this.importVdbs.clear(); setModified(this, Event.IMPORT_VDB_ENTRY_REMOVED, entries, null); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#removeTranslator(java.lang.String) */ @Override public boolean removeTranslator( TranslatorOverride translatorOverride) { if (this.translatorOverrides.remove(translatorOverride) != null) { setModified(this, Event.TRANSLATOR_OVERRIDE_REMOVED, translatorOverride, null); return true; } return false; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#removeTranslator(java.lang.String) */ @Override public boolean removeTranslator(String name) { TranslatorOverride translatorOverride = this.translatorOverrides.get(name); if (translatorOverride == null) return false; return removeTranslator(translatorOverride); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#setConnectionType(java.lang.String) */ @Override public void setConnectionType(String newConnectionType) { if( StringUtilities.areDifferent(this.connectionType, newConnectionType)) { this.connectionType = newConnectionType; setChanged(true); } } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#setPreview(boolean) */ @Override public void setPreview(boolean newPreview) { if( this.preview != newPreview) { this.preview = newPreview; setChanged(true); } } /** * @param intVersion version of vdb */ @Override public void setVersion( String intVersion ) { final String oldVersion = this.version; if( oldVersion.equals(intVersion) ) return; this.version = intVersion; setModified(this, Event.VERSION, oldVersion, intVersion); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getQueryTimeout() */ @Override public int getQueryTimeout() { return this.queryTimeout; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#setQueryTimeout(int) */ @Override public void setQueryTimeout( int valueInSeconds ) { final int oldTimeout = this.queryTimeout; if( oldTimeout == valueInSeconds ) return; this.queryTimeout = valueInSeconds; setModified(this, Event.QUERY_TIMEOUT, oldTimeout, valueInSeconds); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getSecurityDomain() */ @Override public String getSecurityDomain() { return this.securityDomain; } /** * @param newValue Sets security-domain to the specified value. */ @Override public void setSecurityDomain( String newValue ) { final String old = this.securityDomain; if( (old == null && (newValue == null || newValue.length() == 0)) || newValue.equals(old) ) return; if( newValue.length() == 0 ) { this.securityDomain = null; } else { this.securityDomain = newValue; } setModified(this, Event.SECURITY_DOMAIN, old, newValue); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getGssPattern() */ @Override public String getGssPattern() { return this.gssPattern; } /** * @param newValue Sets gss-pattern to the specified value. */ @Override public void setGssPattern( String newValue ) { final String old = this.gssPattern; if( (old == null && (newValue == null || newValue.length() == 0)) || newValue.equals(old) ) return; if( newValue.length() == 0 ) { this.gssPattern = null; } else { this.gssPattern = newValue; } setModified(this, Event.GSS_PATTERN, old, newValue); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getPasswordPattern() */ @Override public String getPasswordPattern() { return this.passwordPattern; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#setPasswordPattern(java.lang.String) */ @Override public void setPasswordPattern( String newValue ) { final String old = this.passwordPattern; if( (old == null && (newValue == null || newValue.length() == 0)) || newValue.equals(old) ) return; if( newValue.length() == 0 ) { this.passwordPattern = null; } else { this.passwordPattern = newValue; } setModified(this, Event.PASSWORD_PATTERN, old, newValue); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getAuthenticationType() */ @Override public String getAuthenticationType() { return this.authenticationType; } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#setAuthenticationType(java.lang.String) */ @Override public void setAuthenticationType( String newValue ) { final String old = this.authenticationType; if( (old == null && (newValue == null || newValue.length() == 0)) || newValue.equals(old) ) return; if( newValue.length() == 0 ) { this.authenticationType = null; } else { this.authenticationType = newValue; } setModified(this, Event.AUTHENTICATION_TYPE, old, newValue); } /** (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getAllowedLanguages() */ @Override public AllowedLanguages getAllowedLanguages() { return this.allowedLanguages; } @Override public boolean addAllowedLanguage(String name) { this.allowedLanguages.addAllowedLanguage(name); if(this.allowedLanguages.isChanged()) { setModified(this, Event.ALLOWED_LANGUAGES, name, name); return true; } return false; } @Override public boolean removeAllowedLanguage(String name) { this.allowedLanguages.removeAllowedLanguage(name); if (allowedLanguages.isChanged()) { setModified(this, Event.ALLOWED_LANGUAGES, name, null); return true; } return false; } @Override public boolean isAutoGenerateRESTWar() { return autoGenerateRESTWar; } @Override public void setAutoGenerateRESTWar(boolean autoGenerateRESTWar) { final boolean oldValue = this.autoGenerateRESTWar; if( oldValue == autoGenerateRESTWar ) return; this.autoGenerateRESTWar = autoGenerateRESTWar; setModified(this, Event.AUTO_GENERATE_REST_WAR, oldValue, autoGenerateRESTWar); } /** * @param valVersion Sets validatationVersion to the specified value. */ @Override public void setValidationVersion( String valVersion ) { final String oldVersion = this.validationVersion; if( StringUtilities.equals(oldVersion, valVersion)) return; this.validationVersion = valVersion; setModified(this, Event.GENERAL_PROPERTY, oldVersion, valVersion); } /** * @return the VDB validation date-time */ @Override public Date getValidationDateTime() { return validateDateTime; } /** * @param dateTime Sets validatationDateTime to the specified value. */ @Override public void setValidationDateTime( Date dateTime ) { final Date oldDateTime = this.validateDateTime; if( oldDateTime != null && oldDateTime.equals(dateTime)) return; this.validateDateTime = dateTime; setModified(this, Event.GENERAL_PROPERTY, oldDateTime, dateTime); } /** * @return the VDB validation version */ @Override public String getValidationVersion() { return validationVersion; } /** * @param key * @param value */ @Override public void setProperty(String key, String value) { super.setProperty(key, value); setModified(this, Event.GENERAL_PROPERTY, null, value); } /** * @param key * @return removed property */ @Override public String removeProperty(String key) { String prop = super.removeProperty(key); setModified(this, Event.GENERAL_PROPERTY, null, prop); return prop; } /* (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#getStatus() */ @Override public IStatus getStatus() { return currentStatus; } /* (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#setStatus(org.eclipse.core.runtime.IStatus) */ @Override public void setStatus(IStatus currentStatus) { this.currentStatus = currentStatus; } /* (non-Javadoc) * @see org.teiid.designer.vdb.Vdb#notifyChangeListeners(java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object) */ @Override public void notifyChangeListeners( final Object source, final String propertyName, final Object oldValue, final Object newValue ) { PropertyChangeEvent event = null; if (!isPreview()) { for (final PropertyChangeListener listener : listeners) { if (event == null) event = new PropertyChangeEvent(this, propertyName, oldValue, newValue); listener.propertyChange(event); } } } /** * @param listener */ @Override public void addChangeListener( final PropertyChangeListener listener ) { listeners.addIfAbsent(listener); } /** * @param listener */ @Override public void removeChangeListener( final PropertyChangeListener listener ) { listeners.remove(listener); } @Override public boolean isModified() { return isChanged(); } @Override public void setModified( final Object source, final String propertyName, final Object oldValue, final Object newValue ) { setChanged(true); notifyChangeListeners(source, propertyName, oldValue, newValue); } @Override public void close() { setDescription(EMPTY_STRING); // Mark VDB as unmodified if (isModified()) setChanged(false); // Notify change listeners VDB is closed notifyChangeListeners(this, Event.CLOSED, null, null); listeners.clear(); } /** * @return the problem markers (never <code>null</code>) * @throws Exception if there is a problem obtaining the problem markers */ @Override public IMarker[] getProblems() throws Exception { IFile file = getSourceFile(); if (file == null) return new IMarker[0]; return file.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE); } /** * Populate the given vdb with the basic properties and settings * * @param vdb */ protected void populateVdb(BasicVdb vdb) { // Note that at this time, the input VDB would have validation version and validation date defined as properties. // So need to either copy them instead of generating them. // {validationVersion=8.7.1, validationDateTime=Thu Aug 06 14:29:43 CDT 2015} Properties existingProps = this.getProperties(); vdb.setName(getName()); vdb.setDescription(getDescription()); String validationVersion = existingProps.getProperty("validationVersion"); if( validationVersion != null ) { vdb.setValidationVersion(validationVersion); existingProps.remove("validationVersion"); } else { vdb.setValidationVersion(ModelerCore.getTeiidServerVersion().toString()); } String validationDateTime = existingProps.getProperty("validationDateTime"); if( validationDateTime != null ) { existingProps.remove("validationDateTime"); try { SimpleDateFormat inFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"); // Mon Aug 10 15:21:50 CDT 2015 Date dtIn = inFormat.parse(validationDateTime); vdb.setValidationDateTime(dtIn); } catch (ParseException e) { e.printStackTrace(); vdb.setValidationDateTime(new Date()); } } else { vdb.setValidationDateTime(new Date()); } for (Map.Entry<Object, Object> entry : existingProps.entrySet()) { if( ! entry.getKey().toString().equals("validationVersion") && ! entry.getKey().toString().equals("validationDateTime") ) { vdb.setProperty(entry.getKey().toString(), entry.getValue().toString()); } } if (vdb.getSourceFile() == null) vdb.setSourceFile(sourceFile); vdb.setVersion(getVersion()); vdb.setConnectionType(getConnectionType()); vdb.setPreview(isPreview()); vdb.setQueryTimeout(getQueryTimeout()); for (String language : getAllowedLanguages().getAllowedLanguageValues()) { vdb.addAllowedLanguage(language); } vdb.setSecurityDomain(getSecurityDomain()); vdb.setGssPattern(getGssPattern()); vdb.setPasswordPattern(getPasswordPattern()); vdb.setAuthenticationType(getAuthenticationType()); vdb.setValidationDateTime(getValidationDateTime()); vdb.setAutoGenerateRESTWar(isAutoGenerateRESTWar()); // Look for other specific VDB properties if(getProperties().keySet().contains(Vdb.Xml.USE_CONNECTOR_METADATA) ) { vdb.setProperty(Vdb.Xml.USE_CONNECTOR_METADATA, getProperties().getProperty(Vdb.Xml.USE_CONNECTOR_METADATA)); } for (VdbImportVdbEntry entry : getImports()) { VdbImportVdbEntry clone = entry.clone(); vdb.addImport(clone); } for (TranslatorOverride translator : getTranslators()) { TranslatorOverride clone = translator.clone(); vdb.addTranslator(clone); } for (DataRole dataRole : getDataRoles()) { DataRole clone = dataRole.clone(); vdb.addDataRole(clone); } vdb.setChanged(isChanged()); } /** * @param destination location for the conversion * @param options options being passed to the conversion implimentations * @return an {@link XmiVdb} of this vdb * @throws Exception */ public abstract XmiVdb xmiVdbConvert(IFile destination, Properties options) throws Exception; /** * @param destination location for the conversion * @param options options being passed to the conversion implimentations * @return a {@link DynamicVdb} of this vdb * @throws Exception */ public abstract DynamicVdb dynVdbConvert(IFile destination, Properties options) throws Exception; @Override public <V extends Vdb> V convert(final Class<V> vdbType, final IFile destination, Properties options) throws Exception { CoreArgCheck.isNotNull(vdbType); CoreArgCheck.isNotNull(destination); if (DynamicVdb.class.equals(vdbType)) return (V) dynVdbConvert(destination, options); else if (XmiVdb.class.equals(vdbType)) return (V) xmiVdbConvert(destination, options); throw new UnsupportedOperationException(); } }