/*
* 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.dqp.internal.process.multisource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.teiid.adminapi.impl.ModelMetaData;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.metadata.BaseColumn.NullType;
import org.teiid.metadata.Column;
import org.teiid.metadata.Column.SearchType;
import org.teiid.metadata.Table;
import org.teiid.query.QueryPlugin;
import org.teiid.query.metadata.BasicQueryMetadataWrapper;
import org.teiid.query.metadata.QueryMetadataInterface;
/**
* This class is a proxy to QueryMetadataInterface.
*/
public class MultiSourceMetadataWrapper extends BasicQueryMetadataWrapper {
public static final String MULTISOURCE_COLUMN_NAME = "multisource.columnName"; //$NON-NLS-1$
private static class MultiSourceGroup {
Object multiSourceElement;
List<?> columns;
}
private Map<String, String> multiSourceModels;
private Map<Object, MultiSourceGroup> groups = new ConcurrentHashMap<Object, MultiSourceGroup>();
public static Map<String, String> getMultiSourceModels(VDBMetaData vdb) {
HashMap<String, String> result = new HashMap<String, String>();
for (ModelMetaData mmd : vdb.getModelMetaDatas().values()) {
if (!mmd.isSupportsMultiSourceBindings()) {
continue;
}
String columnName = mmd.getPropertyValue(MULTISOURCE_COLUMN_NAME);
if (columnName == null) {
columnName = MultiSourceElement.DEFAULT_MULTI_SOURCE_ELEMENT_NAME;
}
result.put(mmd.getName(), columnName);
}
return result;
}
public MultiSourceMetadataWrapper(final QueryMetadataInterface actualMetadata, Map<String, String> multiSourceModels){
super(actualMetadata);
this.multiSourceModels = multiSourceModels;
}
public MultiSourceMetadataWrapper(QueryMetadataInterface metadata,
Set<String> multiSourceModels) {
this(metadata, new HashMap<String, String>());
for (String string : multiSourceModels) {
this.multiSourceModels.put(string, MultiSourceElement.DEFAULT_MULTI_SOURCE_ELEMENT_NAME);
}
}
@Override
public List<?> getElementIDsInGroupID(Object groupID)
throws TeiidComponentException, QueryMetadataException {
MultiSourceGroup msg = getMultiSourceGroup(groupID);
if (msg != null) {
return msg.columns;
}
return actualMetadata.getElementIDsInGroupID(groupID);
}
public MultiSourceGroup getMultiSourceGroup(Object groupID)
throws TeiidComponentException, QueryMetadataException {
MultiSourceGroup msg = groups.get(groupID);
if (msg != null) {
return msg;
}
if (isVirtualGroup(groupID)) {
return null;
}
Object modelId = getModelID(groupID);
String multiSourceElementName = this.multiSourceModels.get(getFullName(modelId));
if (multiSourceElementName == null) {
return null;
}
List<?> elements = actualMetadata.getElementIDsInGroupID(groupID);
// Check whether a source_name column was modeled in the group already
Object mse = null;
for(int i = 0; i<elements.size() && mse == null; i++) {
Object elemID = elements.get(i);
if(actualMetadata.getName(elemID).equalsIgnoreCase(multiSourceElementName)) {
if (!actualMetadata.getElementRuntimeTypeName(elemID).equalsIgnoreCase(DataTypeManager.DefaultDataTypes.STRING)) {
throw new QueryMetadataException(QueryPlugin.Event.TEIID31128, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31128, multiSourceElementName, groupID));
}
mse = elemID;
}
}
if (mse == null) {
List<Object> result = new ArrayList<Object>(elements);
MultiSourceElement e = new MultiSourceElement();
e.setName(multiSourceElementName);
e.setParent((Table)groupID);
e.setPosition(elements.size()+1);
e.setRuntimeType(DataTypeManager.DefaultDataTypes.STRING);
setMultiSourceElementMetadata(e);
result.add(e);
mse = e;
elements = result;
}
msg = new MultiSourceGroup();
msg.columns = elements;
msg.multiSourceElement = mse;
this.groups.put(groupID, msg);
return msg;
}
public static void setMultiSourceElementMetadata(Column e) {
e.setNullValues(0);
e.setNullType(NullType.No_Nulls);
e.setSearchType(SearchType.Searchable);
e.setUpdatable(true);
e.setLength(255);
}
@Override
public Object getElementID(String elementName)
throws TeiidComponentException, QueryMetadataException {
try {
return super.getElementID(elementName);
} catch (QueryMetadataException e) {
//could be pseudo-column
int index = elementName.lastIndexOf('.');
if(index <= 0 || elementName.length() <= index) {
throw e;
}
String group = elementName.substring(0, index);
elementName = elementName.substring(index + 1, elementName.length());
MultiSourceGroup msg = getMultiSourceGroup(getGroupID(group));
if (msg != null && elementName.equalsIgnoreCase(getName(msg.multiSourceElement))) {
return msg.multiSourceElement;
}
throw e;
}
}
@Override
public boolean isMultiSource(Object modelId) throws QueryMetadataException, TeiidComponentException {
return multiSourceModels.containsKey(getFullName(modelId));
}
@Override
public boolean isMultiSourceElement(Object elementId) throws QueryMetadataException, TeiidComponentException {
if (elementId instanceof MultiSourceElement) {
return true;
}
Object gid = getGroupIDForElementID(elementId);
if (isVirtualGroup(gid)) {
return false;
}
Object modelID = this.getModelID(gid);
String modelName = this.getFullName(modelID);
String multiSourceColumnName = multiSourceModels.get(modelName);
if(multiSourceColumnName == null) {
return false;
}
return multiSourceColumnName.equalsIgnoreCase(getName(elementId));
}
@Override
protected QueryMetadataInterface createDesignTimeMetadata() {
return new MultiSourceMetadataWrapper(actualMetadata.getDesignTimeMetadata(), multiSourceModels);
}
@Override
public boolean isPseudo(Object elementId) {
if (elementId instanceof MultiSourceElement) {
return true;
}
return actualMetadata.isPseudo(elementId);
}
}