/* * 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.query.metadata; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeMap; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import org.teiid.adminapi.impl.DataPolicyMetadata; import org.teiid.adminapi.impl.VDBMetaData; import org.teiid.core.types.BlobImpl; import org.teiid.core.types.ClobImpl; import org.teiid.core.types.DataTypeManagerService; import org.teiid.core.types.InputStreamFactory; import org.teiid.core.types.SQLXMLImpl; import org.teiid.core.util.ArgCheck; import org.teiid.core.util.LRUCache; import org.teiid.core.util.ObjectConverterUtil; import org.teiid.core.util.StringUtil; import org.teiid.designer.query.metadata.IQueryMetadataInterface; import org.teiid.designer.runtime.version.spi.ITeiidServerVersion; import org.teiid.metadata.AbstractMetadataRecord; import org.teiid.metadata.BaseColumn.NullType; import org.teiid.metadata.Column; import org.teiid.metadata.Column.SearchType; import org.teiid.metadata.ColumnSet; import org.teiid.metadata.ForeignKey; import org.teiid.metadata.FunctionParameter; import org.teiid.metadata.KeyRecord; import org.teiid.metadata.Procedure; import org.teiid.metadata.ProcedureParameter; import org.teiid.metadata.ProcedureParameter.Type; import org.teiid.metadata.Schema; import org.teiid.metadata.Table; import org.teiid.query.function.FunctionLibrary; import org.teiid.query.function.FunctionTree; import org.teiid.query.mapping.relational.QueryNode; import org.teiid.query.mapping.xml.MappingDocument; import org.teiid.query.mapping.xml.MappingLoader; import org.teiid.query.mapping.xml.MappingNode; import org.teiid.query.parser.TeiidParser; import org.teiid.query.sql.lang.ObjectTable; import org.teiid.query.sql.lang.SPParameter; import org.teiid.runtime.client.Messages; import org.teiid.runtime.client.TeiidClientException; /** * Teiid's implementation of the QueryMetadataInterface that reads columns, groups, models etc. * from the metadata object model. */ public class TransformationMetadata extends BasicQueryMetadata implements Serializable { public static final String ALLOWED_LANGUAGES = "allowed-languages"; //$NON-NLS-1$ private static final class LiveQueryNode extends QueryNode { Procedure p; private LiveQueryNode(Procedure p) { super(null); this.p = p; } public String getQuery() { return p.getQueryPlan(); } } private static final class LiveTableQueryNode extends QueryNode { Table t; private LiveTableQueryNode(Table t) { super(null); this.t = t; } public String getQuery() { return t.getSelectTransformation(); } } private final class VirtualFileInputStreamFactory extends InputStreamFactory { private final VDBResources.Resource r; private VirtualFileInputStreamFactory(VDBResources.Resource r) { this.r = r; } @Override public InputStream getInputStream() throws IOException { return r.openStream(); } @Override public long getLength() { return r.getSize(); } @Override public StorageMode getStorageMode() { return StorageMode.PERSISTENT; } } private static final long serialVersionUID = 1058627332954475287L; /** Delimiter character used when specifying fully qualified entity names */ public static final char DELIMITER_CHAR = StringUtil.Constants.DOT_CHAR; public static final String DELIMITER_STRING = String.valueOf(DELIMITER_CHAR); // error message cached to avoid i18n lookup each time public static String NOT_EXISTS_MESSAGE = StringUtil.Constants.SPACE+Messages.getString(Messages.TransformationMetadata.doesNotExist); public static Properties EMPTY_PROPS = new Properties(); private final CompositeMetadataStore store; private DataTypeManagerService dataTypeManager; private Map<String, VDBResources.Resource> vdbEntries; private FunctionLibrary functionLibrary; private VDBMetaData vdbMetaData; private ScriptEngineManager scriptEngineManager; private Map<String, ScriptEngineFactory> scriptEngineFactories = Collections.synchronizedMap(new HashMap<String, ScriptEngineFactory>()); private Set<String> importedModels; private Set<String> allowedLanguages; private Map<String, DataPolicyMetadata> policies = new TreeMap<String, DataPolicyMetadata>(String.CASE_INSENSITIVE_ORDER); private boolean useOutputNames = true; /* * TODO: move caching to jboss cache structure */ private Map<String, Object> metadataCache = Collections.synchronizedMap(new LRUCache<String, Object>(250)); private Map<String, Object> groupInfoCache = Collections.synchronizedMap(new LRUCache<String, Object>(250)); private Map<String, Collection<Table>> partialNameToFullNameCache = Collections.synchronizedMap(new LRUCache<String, Collection<Table>>(1000)); private Map<String, Collection<StoredProcedureInfo>> procedureCache = Collections.synchronizedMap(new LRUCache<String, Collection<StoredProcedureInfo>>(200)); private boolean widenComparisonToString = true; /** * TransformationMetadata constructor * @param teiidVersion * @param vdbMetadata * @param store * @param vdbEntries * @param systemFunctions * @param functionTrees */ public TransformationMetadata(ITeiidServerVersion teiidVersion, VDBMetaData vdbMetadata, final CompositeMetadataStore store, Map<String, VDBResources.Resource> vdbEntries, FunctionTree systemFunctions, Collection<FunctionTree> functionTrees) { super(teiidVersion); ArgCheck.isNotNull(store); this.vdbMetaData = vdbMetadata; if (this.vdbMetaData !=null) { this.scriptEngineManager = vdbMetadata.getAttachment(ScriptEngineManager.class); this.importedModels = this.vdbMetaData.getImportedModels(); this.allowedLanguages = StringUtil.valueOf(vdbMetadata.getPropertyValue(ALLOWED_LANGUAGES), Set.class); if (this.allowedLanguages == null) { this.allowedLanguages = Collections.emptySet(); } for (DataPolicyMetadata policy : vdbMetadata.getDataPolicyMap().values()) { policy = policy.clone(); policies.put(policy.getName(), policy); } store.processGrants(policies); } else { this.importedModels = Collections.emptySet(); } this.store = store; if (vdbEntries == null) { this.vdbEntries = Collections.emptyMap(); } else { this.vdbEntries = vdbEntries; } if (functionTrees == null) { this.functionLibrary = new FunctionLibrary(teiidVersion, systemFunctions); } else { this.functionLibrary = new FunctionLibrary(teiidVersion, systemFunctions, functionTrees.toArray(new FunctionTree[functionTrees.size()])); } } private TransformationMetadata(ITeiidServerVersion teiidVersion, final CompositeMetadataStore store, FunctionLibrary functionLibrary) { super(teiidVersion); this.store = store; this.vdbEntries = Collections.emptyMap(); this.functionLibrary = functionLibrary; } /** * @return the dataTypeManager */ public DataTypeManagerService getDataTypeManager() { if (dataTypeManager == null) dataTypeManager = DataTypeManagerService.getInstance(getTeiidVersion()); return this.dataTypeManager; } //================================================================================== // I N T E R F A C E M E T H O D S //================================================================================== public Column getElementID(final String elementName) throws Exception { int columnIndex = elementName.lastIndexOf(TransformationMetadata.DELIMITER_STRING); if (columnIndex == -1) { throw new TeiidClientException(elementName+TransformationMetadata.NOT_EXISTS_MESSAGE); } Table table = this.store.findGroup(elementName.substring(0, columnIndex)); String shortElementName = elementName.substring(columnIndex + 1); return getColumn(elementName, table, shortElementName); } public static Column getColumn(final String elementName, Table table, String shortElementName) throws Exception { Column c = table.getColumnByName(shortElementName); if (c != null) { return c; } throw new TeiidClientException(elementName+TransformationMetadata.NOT_EXISTS_MESSAGE); } public Table getGroupID(String groupName) throws Exception { return getMetadataStore().findGroup(groupName); } public Collection<String> getGroupsForPartialName(final String partialGroupName) throws Exception { ArgCheck.isNotEmpty(partialGroupName); Collection<Table> matches = this.partialNameToFullNameCache.get(partialGroupName); if (matches == null) { matches = getMetadataStore().getGroupsForPartialName(partialGroupName); this.partialNameToFullNameCache.put(partialGroupName, matches); } if (matches.isEmpty()) { return Collections.emptyList(); } Collection<String> filteredResult = new ArrayList<String>(matches.size()); for (Table table : matches) { if (vdbMetaData == null || vdbMetaData.isVisible(table.getParent().getName())) { filteredResult.add(table.getFullName()); } } return filteredResult; } public Object getModelID(final Object groupOrElementID) throws Exception { AbstractMetadataRecord metadataRecord = (AbstractMetadataRecord) groupOrElementID; AbstractMetadataRecord parent = metadataRecord.getParent(); if (parent instanceof Schema) { return parent; } if (parent == null) { throw createInvalidRecordTypeException(groupOrElementID); } parent = parent.getParent(); if (parent instanceof Schema) { return parent; } throw createInvalidRecordTypeException(groupOrElementID); } public String getFullName(final Object metadataID) throws Exception { AbstractMetadataRecord metadataRecord = (AbstractMetadataRecord) metadataID; if (metadataRecord instanceof Column) { Column c = (Column)metadataRecord; if (c.getParent() != null && c.getParent().getParent() instanceof Procedure) { return c.getParent().getParent().getFullName() + '.' + c.getName(); } } return metadataRecord.getFullName(); } @Override public String getName(Object metadataID) throws Exception, TeiidClientException { AbstractMetadataRecord metadataRecord = (AbstractMetadataRecord) metadataID; return metadataRecord.getName(); } public List<Column> getElementIDsInGroupID(final Object groupID) throws Exception { List<Column> columns = ((Table)groupID).getColumns(); if (columns == null || columns.isEmpty()) { throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID31071, ((Table)groupID).getName())); } return columns; } public Object getGroupIDForElementID(final Object elementID) throws Exception { if(elementID instanceof Column) { Column columnRecord = (Column) elementID; AbstractMetadataRecord parent = columnRecord.getParent(); if (parent instanceof Table) { return parent; } if (parent instanceof ColumnSet) { parent = ((ColumnSet<?>)parent).getParent(); if (parent instanceof Procedure) { return parent; } } } if(elementID instanceof ProcedureParameter) { ProcedureParameter columnRecord = (ProcedureParameter) elementID; return columnRecord.getParent(); } throw createInvalidRecordTypeException(elementID); } public boolean hasProcedure(String name) throws Exception { try { return getStoredProcInfoDirect(name) != null; } catch (TeiidClientException e) { return true; } } public StoredProcedureInfo getStoredProcedureInfoForProcedure(final String name) throws Exception { StoredProcedureInfo result = getStoredProcInfoDirect(name); if (result == null) { throw new TeiidClientException(name+NOT_EXISTS_MESSAGE); } return result; } private StoredProcedureInfo getStoredProcInfoDirect( final String name) throws Exception { ArgCheck.isNotEmpty(name); String canonicalName = name.toUpperCase(); Collection<StoredProcedureInfo> results = this.procedureCache.get(canonicalName); if (results == null) { Collection<Procedure> procRecords = getMetadataStore().getStoredProcedure(canonicalName); if (procRecords.isEmpty()) { return null; } results = new ArrayList<StoredProcedureInfo>(procRecords.size()); for (Procedure procRecord : procRecords) { String procedureFullName = procRecord.getFullName(); // create the storedProcedure info object that would hold procedure's metadata StoredProcedureInfo procInfo = new StoredProcedureInfo(); procInfo.setProcedureCallableName(procedureFullName); procInfo.setProcedureID(procRecord); // modelID for the procedure procInfo.setModelID(procRecord.getParent()); // get the parameter metadata info for (ProcedureParameter paramRecord : procRecord.getParameters()) { String runtimeType = paramRecord.getRuntimeType(); int direction = this.convertParamRecordTypeToStoredProcedureType(paramRecord.getType()); // create a parameter and add it to the procedure object SPParameter spParam = new SPParameter(getTeiidVersion(), paramRecord.getPosition(), direction, paramRecord.getFullName()); spParam.setMetadataID(paramRecord); spParam.setClassType(getDataTypeManager().getDataTypeClass(runtimeType)); if (paramRecord.isVarArg()) { spParam.setVarArg(true); spParam.setClassType(getDataTypeManager().getDataType(spParam.getClassType()).getTypeArrayClass()); } procInfo.addParameter(spParam); } // if the procedure returns a resultSet, obtain resultSet metadata if(procRecord.getResultSet() != null) { ColumnSet<Procedure> resultRecord = procRecord.getResultSet(); // resultSet is the last parameter in the procedure int lastParamIndex = procInfo.getParameters().size() + 1; SPParameter param = new SPParameter(getTeiidVersion(), lastParamIndex, SPParameter.RESULT_SET, resultRecord.getFullName()); param.setClassType(java.sql.ResultSet.class); param.setMetadataID(resultRecord); for (Column columnRecord : resultRecord.getColumns()) { String colType = columnRecord.getRuntimeType(); param.addResultSetColumn(columnRecord.getFullName(), getDataTypeManager().getDataTypeClass(colType), columnRecord); } procInfo.addParameter(param); } // if this is a virtual procedure get the procedure plan if(procRecord.isVirtual()) { QueryNode queryNode = new LiveQueryNode(procRecord); procInfo.setQueryPlan(queryNode); } //subtract 1, to match up with the server procInfo.setUpdateCount(procRecord.getUpdateCount() -1); results.add(procInfo); } this.procedureCache.put(canonicalName, results); } StoredProcedureInfo result = null; for (StoredProcedureInfo storedProcedureInfo : results) { Schema schema = (Schema)storedProcedureInfo.getModelID(); if(name.equalsIgnoreCase(storedProcedureInfo.getProcedureCallableName()) || vdbMetaData == null || vdbMetaData.isVisible(schema.getName())){ if (result != null) { throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30358, name)); } result = storedProcedureInfo; } } return result; } /** * Method to convert the parameter type returned from a ProcedureParameterRecord * to the parameter type expected by StoredProcedureInfo * @param parameterType * @return */ private int convertParamRecordTypeToStoredProcedureType(final ProcedureParameter.Type parameterType) { switch (parameterType) { case In : return SPParameter.IN; case Out : return SPParameter.OUT; case InOut : return SPParameter.INOUT; case ReturnValue : return SPParameter.RETURN_VALUE; default : return -1; } } public String getElementType(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getRuntimeType(); } else if(elementID instanceof ProcedureParameter){ return ((ProcedureParameter) elementID).getRuntimeType(); } else { throw createInvalidRecordTypeException(elementID); } } public String getDefaultValue(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getDefaultValue(); } else if(elementID instanceof ProcedureParameter){ return ((ProcedureParameter) elementID).getDefaultValue(); } else { throw createInvalidRecordTypeException(elementID); } } public Object getMinimumValue(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getMinimumValue(); } else if(elementID instanceof ProcedureParameter){ return null; } else { throw createInvalidRecordTypeException(elementID); } } public Object getMaximumValue(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getMaximumValue(); } else if(elementID instanceof ProcedureParameter){ return null; } else { throw createInvalidRecordTypeException(elementID); } } public boolean isVirtualGroup(final Object groupID) throws Exception { if (groupID instanceof Table) { return ((Table) groupID).isVirtual(); } if (groupID instanceof Procedure) { return ((Procedure) groupID).isVirtual(); } throw createInvalidRecordTypeException(groupID); } public boolean isProcedure(final Object groupID) throws Exception { if(groupID instanceof Procedure) { return true; } if(groupID instanceof Table){ return false; } throw createInvalidRecordTypeException(groupID); } public boolean isVirtualModel(final Object modelID) throws Exception { Schema modelRecord = (Schema) modelID; return !modelRecord.isPhysical(); } public QueryNode getVirtualPlan(final Object groupID) throws Exception { Table tableRecord = (Table) groupID; if (!tableRecord.isVirtual()) { throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30359, tableRecord.getFullName(), "Query")); //$NON-NLS-1$ } LiveTableQueryNode queryNode = new LiveTableQueryNode(tableRecord); // get any bindings and add them onto the query node List<String> bindings = tableRecord.getBindings(); if(bindings != null) { for(Iterator<String> bindIter = bindings.iterator();bindIter.hasNext();) { queryNode.addBinding(bindIter.next()); } } return queryNode; } public String getInsertPlan(final Object groupID) throws Exception { Table tableRecordImpl = (Table)groupID; if (!tableRecordImpl.isVirtual()) { throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30359, tableRecordImpl.getFullName(), "Insert")); //$NON-NLS-1$ } return tableRecordImpl.isInsertPlanEnabled()?tableRecordImpl.getInsertPlan():null; } public String getUpdatePlan(final Object groupID) throws Exception { Table tableRecordImpl = (Table)groupID; if (!tableRecordImpl.isVirtual()) { throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30359, tableRecordImpl.getFullName(), "Update")); //$NON-NLS-1$ } return tableRecordImpl.isUpdatePlanEnabled()?tableRecordImpl.getUpdatePlan():null; } public String getDeletePlan(final Object groupID) throws Exception { Table tableRecordImpl = (Table)groupID; if (!tableRecordImpl.isVirtual()) { throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30359, tableRecordImpl.getFullName(), "Delete")); //$NON-NLS-1$ } return tableRecordImpl.isDeletePlanEnabled()?tableRecordImpl.getDeletePlan():null; } public boolean modelSupports(final Object modelID, final int modelConstant) throws Exception { switch(modelConstant) { default: throw new UnsupportedOperationException(Messages.getString(Messages.TransformationMetadata.unknownSupportConstant12) + modelConstant); } } public boolean groupSupports(final Object groupID, final int groupConstant) throws Exception { Table tableRecord = (Table) groupID; switch(groupConstant) { case SupportConstants.Group.UPDATE: return tableRecord.supportsUpdate(); default: throw new UnsupportedOperationException(Messages.getString(Messages.TransformationMetadata.unknownSupportConstant12) + groupConstant); } } public boolean elementSupports(final Object elementID, final int elementConstant) throws Exception { if(elementID instanceof Column) { Column columnRecord = (Column) elementID; switch(elementConstant) { case SupportConstants.Element.NULL: return columnRecord.getNullType() == NullType.Nullable; case SupportConstants.Element.NULL_UNKNOWN: return columnRecord.getNullType() == NullType.Unknown; case SupportConstants.Element.SEARCHABLE_COMPARE: return (columnRecord.getSearchType() == SearchType.Searchable || columnRecord.getSearchType() == SearchType.All_Except_Like); case SupportConstants.Element.SEARCHABLE_LIKE: return (columnRecord.getSearchType() == SearchType.Searchable || columnRecord.getSearchType() == SearchType.Like_Only); case SupportConstants.Element.SEARCHABLE_EQUALITY: return (columnRecord.getSearchType() == SearchType.Equality_Only || columnRecord.getSearchType() == SearchType.Searchable || columnRecord.getSearchType() == SearchType.All_Except_Like); case SupportConstants.Element.SELECT: return columnRecord.isSelectable(); case SupportConstants.Element.UPDATE: return columnRecord.isUpdatable(); case SupportConstants.Element.DEFAULT_VALUE: Object defaultValue = columnRecord.getDefaultValue(); if(defaultValue == null) { return false; } return true; case SupportConstants.Element.AUTO_INCREMENT: return columnRecord.isAutoIncremented(); case SupportConstants.Element.CASE_SENSITIVE: return columnRecord.isCaseSensitive(); case SupportConstants.Element.SIGNED: return columnRecord.isSigned(); default: throw new UnsupportedOperationException(Messages.getString(Messages.TransformationMetadata.unknownSupportConstant12) + elementConstant); } } else if(elementID instanceof ProcedureParameter) { ProcedureParameter columnRecord = (ProcedureParameter) elementID; switch(elementConstant) { case SupportConstants.Element.NULL: return columnRecord.getNullType() == NullType.Nullable; case SupportConstants.Element.NULL_UNKNOWN: return columnRecord.getNullType() == NullType.Unknown; case SupportConstants.Element.SEARCHABLE_COMPARE: case SupportConstants.Element.SEARCHABLE_LIKE: return false; case SupportConstants.Element.SELECT: return columnRecord.getType() != Type.In; case SupportConstants.Element.UPDATE: return false; case SupportConstants.Element.DEFAULT_VALUE: Object defaultValue = columnRecord.getDefaultValue(); if(defaultValue == null) { return false; } return true; case SupportConstants.Element.AUTO_INCREMENT: return false; case SupportConstants.Element.CASE_SENSITIVE: return false; case SupportConstants.Element.SIGNED: return true; default: throw new UnsupportedOperationException(Messages.getString(Messages.TransformationMetadata.unknownSupportConstant12) + elementConstant); } } else { throw createInvalidRecordTypeException(elementID); } } private IllegalArgumentException createInvalidRecordTypeException(Object elementID) { return new IllegalArgumentException(Messages.getString(Messages.TransformationMetadata.invalidType, elementID!=null?elementID.getClass().getName():null)); } public int getMaxSetSize(final Object modelID) throws Exception { return 0; } public Collection<KeyRecord> getIndexesInGroup(final Object groupID) throws Exception { return ((Table)groupID).getIndexes(); } public Collection<KeyRecord> getUniqueKeysInGroup(final Object groupID) throws Exception { Table tableRecordImpl = (Table)groupID; ArrayList<KeyRecord> result = new ArrayList<KeyRecord>(tableRecordImpl.getUniqueKeys()); if (tableRecordImpl.getPrimaryKey() != null) { result.add(tableRecordImpl.getPrimaryKey()); } for (KeyRecord key : tableRecordImpl.getIndexes()) { if (key.getType() == KeyRecord.Type.Unique) { result.add(key); } } return result; } public Collection<ForeignKey> getForeignKeysInGroup(final Object groupID) throws Exception { return ((Table)groupID).getForeignKeys(); } public Object getPrimaryKeyIDForForeignKeyID(final Object foreignKeyID) throws Exception { ForeignKey fkRecord = (ForeignKey) foreignKeyID; return fkRecord.getPrimaryKey(); } public Collection<KeyRecord> getAccessPatternsInGroup(final Object groupID) throws Exception { return ((Table)groupID).getAccessPatterns(); } public List<Column> getElementIDsInIndex(final Object index) throws Exception { return ((ColumnSet<?>)index).getColumns(); } public List<Column> getElementIDsInKey(final Object key) throws Exception { return ((ColumnSet<?>)key).getColumns(); } public List<Column> getElementIDsInAccessPattern(final Object accessPattern) throws Exception { return ((ColumnSet<?>)accessPattern).getColumns(); } public boolean isXMLGroup(final Object groupID) throws Exception { Table tableRecord = (Table) groupID; return tableRecord.getTableType() == Table.Type.Document; } /** * @see org.teiid.query.metadata.QueryMetadataInterface#hasMaterialization(java.lang.Object) * @since 4.2 */ public boolean hasMaterialization(final Object groupID) throws Exception, TeiidClientException { Table tableRecord = (Table) groupID; return tableRecord.isMaterialized(); } /** * @see org.teiid.query.metadata.QueryMetadataInterface#getMaterialization(java.lang.Object) * @since 4.2 */ public Object getMaterialization(final Object groupID) throws Exception, TeiidClientException { Table tableRecord = (Table) groupID; if(tableRecord.isMaterialized()) { return tableRecord.getMaterializedTable(); } return null; } /** * @see org.teiid.query.metadata.QueryMetadataInterface#getMaterializationStage(java.lang.Object) * @since 4.2 */ public Object getMaterializationStage(final Object groupID) throws Exception, TeiidClientException { Table tableRecord = (Table) groupID; if(tableRecord.isMaterialized()) { return tableRecord.getMaterializedStageTable(); } return null; } public MappingNode getMappingNode(final Object groupID) throws Exception { Table tableRecord = (Table) groupID; MappingDocument mappingDoc = (MappingDocument) getFromMetadataCache(groupID, "xml-doc"); //$NON-NLS-1$ if (mappingDoc != null) { return mappingDoc; } final String groupName = tableRecord.getFullName(); if(tableRecord.isVirtual()) { // get mapping transform String document = tableRecord.getSelectTransformation(); InputStream inputStream = new ByteArrayInputStream(document.getBytes()); MappingLoader reader = new MappingLoader(getTeiidVersion()); try{ mappingDoc = reader.loadDocument(inputStream); mappingDoc.setName(groupName); } catch (Exception e){ throw new TeiidClientException(e, Messages.gs(Messages.TEIID.TEIID30363, groupName, mappingDoc)); } finally { try { inputStream.close(); } catch(Exception e) {} } addToMetadataCache(groupID, "xml-doc", mappingDoc); //$NON-NLS-1$ return mappingDoc; } return null; } /** * @see org.teiid.query.metadata.QueryMetadataInterface#getVirtualDatabaseName() */ public String getVirtualDatabaseName() throws Exception { if (vdbMetaData == null) { return null; } return vdbMetaData.getName(); } public String getVirtualDatabaseVersion() { if (vdbMetaData == null) { return "0"; } return vdbMetaData.getVersion(); } public VDBMetaData getVdbMetaData() { return vdbMetaData; } /** * @see org.teiid.query.metadata.QueryMetadataInterface#getXMLTempGroups(java.lang.Object) */ public Collection<Table> getXMLTempGroups(final Object groupID) throws Exception { Table tableRecord = (Table) groupID; if(tableRecord.getTableType() == Table.Type.Document) { return this.store.getXMLTempGroups(tableRecord); } return Collections.emptySet(); } public float getCardinality(final Object groupID) throws Exception { return ((Table) groupID).getCardinalityAsFloat(); } public List<SQLXMLImpl> getXMLSchemas(final Object groupID) throws Exception { Table tableRecord = (Table) groupID; // lookup transformation record for the group String groupName = tableRecord.getFullName(); // get the schema Paths List<String> schemaPaths = tableRecord.getSchemaPaths(); List<SQLXMLImpl> schemas = new LinkedList<SQLXMLImpl>(); if (schemaPaths == null) { return schemas; } String path = getParentPath(tableRecord.getResourcePath()); for (String string : schemaPaths) { String parentPath = path; boolean relative = false; while (string.startsWith("../")) { //$NON-NLS-1$ relative = true; string = string.substring(3); parentPath = getParentPath(parentPath); } SQLXMLImpl schema = null; if (!relative) { schema = getVDBResourceAsSQLXML(string); } if (schema == null) { if (!parentPath.endsWith("/")) { //$NON-NLS-1$ parentPath += "/"; //$NON-NLS-1$ } schema = getVDBResourceAsSQLXML(parentPath + string); } if (schema == null) { throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID30364,groupName)); } schemas.add(schema); } return schemas; } private String getParentPath(String path) { if (path == null) { return ""; //$NON-NLS-1$ } int index = path.lastIndexOf('/'); if (index > 0) { path = path.substring(0, index); } else { path = ""; //$NON-NLS-1$ } return path; } public String getNameInSource(final Object metadataID) throws Exception { return ((AbstractMetadataRecord) metadataID).getNameInSource(); } public int getElementLength(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getLength(); } else if(elementID instanceof ProcedureParameter){ return ((ProcedureParameter) elementID).getLength(); } else { throw createInvalidRecordTypeException(elementID); } } public int getPosition(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getPosition(); } else if(elementID instanceof ProcedureParameter) { return ((ProcedureParameter) elementID).getPosition(); } else { throw createInvalidRecordTypeException(elementID); } } public int getPrecision(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getPrecision(); } else if(elementID instanceof ProcedureParameter) { return ((ProcedureParameter) elementID).getPrecision(); } else { throw createInvalidRecordTypeException(elementID); } } public int getRadix(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getRadix(); } else if(elementID instanceof ProcedureParameter) { return ((ProcedureParameter) elementID).getRadix(); } else { throw createInvalidRecordTypeException(elementID); } } public String getFormat(Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getFormat(); } throw createInvalidRecordTypeException(elementID); } public int getScale(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getScale(); } else if(elementID instanceof ProcedureParameter) { return ((ProcedureParameter) elementID).getScale(); } else { throw createInvalidRecordTypeException(elementID); } } public float getDistinctValues(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getDistinctValuesAsFloat(); } else if(elementID instanceof ProcedureParameter) { return -1; } else { throw createInvalidRecordTypeException(elementID); } } public float getNullValues(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getNullValuesAsFloat(); } else if(elementID instanceof ProcedureParameter) { return -1; } else { throw createInvalidRecordTypeException(elementID); } } public String getNativeType(final Object elementID) throws Exception { if(elementID instanceof Column) { return ((Column) elementID).getNativeType(); } else if(elementID instanceof ProcedureParameter) { return null; } else { throw createInvalidRecordTypeException(elementID); } } public Properties getExtensionProperties(final Object metadataID) throws Exception { AbstractMetadataRecord metadataRecord = (AbstractMetadataRecord) metadataID; Map<String, String> result = metadataRecord.getProperties(); if (result == null) { return EMPTY_PROPS; } Properties p = new Properties(); p.putAll(result); return p; } @Override public String getExtensionProperty(Object metadataID, String key, boolean checkUnqualified) { return ((AbstractMetadataRecord)metadataID).getProperty(key, checkUnqualified); } /** * @see org.teiid.query.metadata.BasicQueryMetadata#getBinaryVDBResource(java.lang.String) * @since 4.3 */ public byte[] getBinaryVDBResource(String resourcePath) throws Exception { final VDBResources.Resource f = getFile(resourcePath); if (f == null) { return null; } try { return ObjectConverterUtil.convertToByteArray(f.openStream()); } catch (IOException e) { throw new TeiidClientException(e); } } public ClobImpl getVDBResourceAsClob(String resourcePath) { final VDBResources.Resource f = getFile(resourcePath); if (f == null) { return null; } return new ClobImpl(new VirtualFileInputStreamFactory(f), -1); } public SQLXMLImpl getVDBResourceAsSQLXML(String resourcePath) { final VDBResources.Resource f = getFile(resourcePath); if (f == null) { return null; } return new SQLXMLImpl(new VirtualFileInputStreamFactory(f)); } public BlobImpl getVDBResourceAsBlob(String resourcePath) { final VDBResources.Resource f = getFile(resourcePath); if (f == null) { return null; } return new BlobImpl(new VirtualFileInputStreamFactory(f)); } private VDBResources.Resource getFile(String resourcePath) { if (resourcePath == null) { return null; } return this.vdbEntries.get(resourcePath); } /** * @see org.teiid.query.metadata.BasicQueryMetadata#getCharacterVDBResource(java.lang.String) * @since 4.3 */ public String getCharacterVDBResource(String resourcePath) throws Exception { try { byte[] bytes = getBinaryVDBResource(resourcePath); if (bytes == null) { return null; } return ObjectConverterUtil.convertToString(new ByteArrayInputStream(bytes)); } catch (IOException e) { throw new TeiidClientException(e); } } public CompositeMetadataStore getMetadataStore() { return this.store; } /** * @see org.teiid.query.metadata.BasicQueryMetadata#getVDBResourcePaths() * @since 4.3 */ public String[] getVDBResourcePaths() throws Exception { LinkedList<String> paths = new LinkedList<String>(); for (Map.Entry<String, VDBResources.Resource> entry : this.vdbEntries.entrySet()) { paths.add(entry.getKey()); } return paths.toArray(new String[paths.size()]); } @Override public Object addToMetadataCache(Object metadataID, String key, Object value) { boolean groupInfo = key.startsWith(GroupInfo.CACHE_PREFIX); key = getCacheKey(key, (AbstractMetadataRecord)metadataID); if (groupInfo) { return this.groupInfoCache.put(key, value); } return this.metadataCache.put(key, value); } @Override public Object getFromMetadataCache(Object metadataID, String key) throws Exception { boolean groupInfo = key.startsWith(GroupInfo.CACHE_PREFIX); key = getCacheKey(key, (AbstractMetadataRecord)metadataID); if (groupInfo) { return this.groupInfoCache.get(key); } return this.metadataCache.get(key); } private String getCacheKey(String key, AbstractMetadataRecord record) { return record.getUUID() + "/" + key; //$NON-NLS-1$ } @Override public FunctionLibrary getFunctionLibrary() { return this.functionLibrary; } @Override public Object getPrimaryKey(Object metadataID) { Table table = (Table)metadataID; return table.getPrimaryKey(); } @Override public IQueryMetadataInterface getDesignTimeMetadata() { TransformationMetadata tm = new TransformationMetadata(getTeiidVersion(), store, functionLibrary); tm.groupInfoCache = this.groupInfoCache; tm.metadataCache = this.metadataCache; tm.partialNameToFullNameCache = this.partialNameToFullNameCache; tm.procedureCache = this.procedureCache; tm.scriptEngineManager = this.scriptEngineManager; tm.importedModels = this.importedModels; tm.allowedLanguages = this.allowedLanguages; tm.widenComparisonToString = this.widenComparisonToString; return tm; } @Override public Set<String> getImportedModels() { return this.importedModels; } @Override public ScriptEngine getScriptEngineDirect(String language) throws Exception { if (this.scriptEngineManager == null) { this.scriptEngineManager = new ScriptEngineManager(); } ScriptEngine engine = null; if (allowedLanguages == null || allowedLanguages.contains(language)) { /* * because of state caching in the engine, we'll return a new instance for each * usage. we can pool if needed and add a returnEngine method */ ScriptEngineFactory sef = this.scriptEngineFactories.get(language); if (sef != null) { try { engine = sef.getScriptEngine(); engine.setBindings(scriptEngineManager.getBindings(), ScriptContext.ENGINE_SCOPE); } catch (Exception e) { //just swallow the exception to mimic the jsr behavior } } engine = this.scriptEngineManager.getEngineByName(language); } if (engine == null) { Set<String> names = new LinkedHashSet<String>(); for (ScriptEngineFactory factory : this.scriptEngineManager.getEngineFactories()) { names.addAll(factory.getNames()); } if (allowedLanguages != null) { names.retainAll(allowedLanguages); } names.add(ObjectTable.DEFAULT_LANGUAGE); throw new TeiidClientException(Messages.gs(Messages.TEIID.TEIID31109, language, names)); } this.scriptEngineFactories.put(language, engine.getFactory()); return engine; } @Override public boolean isVariadic(Object metadataID) { if (metadataID instanceof ProcedureParameter) { return ((ProcedureParameter)metadataID).isVarArg(); } if (metadataID instanceof FunctionParameter) { return ((FunctionParameter)metadataID).isVarArg(); } return false; } @Override public Schema getModelID(String modelName) throws Exception { Schema s = this.getMetadataStore().getSchema(modelName); if (s == null) { throw new TeiidClientException(modelName+TransformationMetadata.NOT_EXISTS_MESSAGE); } return s; } public Map<String, DataPolicyMetadata> getPolicies() { return policies; } @Override public boolean useOutputName() { return useOutputNames; } public void setUseOutputNames(boolean useOutputNames) { this.useOutputNames = useOutputNames; } @Override public boolean widenComparisonToString() { return widenComparisonToString; } public void setWidenComparisonToString(boolean widenComparisonToString) { this.widenComparisonToString = widenComparisonToString; } }