/*
* 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.deployers;
import java.util.List;
import org.teiid.adminapi.AdminProcessingException;
import org.teiid.adminapi.VDB.ConnectionType;
import org.teiid.adminapi.impl.DataPolicyMetadata;
import org.teiid.adminapi.impl.ModelMetaData;
import org.teiid.adminapi.impl.SourceMappingMetadata;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.dqp.internal.datamgr.ConnectorManager;
import org.teiid.dqp.internal.datamgr.ConnectorManagerRepository;
import org.teiid.runtime.RuntimePlugin;
public abstract class RuntimeVDB {
private VDBMetaData vdb;
private VDBModificationListener listener;
private volatile boolean restartInProgress = false;
public static class ReplaceResult {
public boolean isNew;
public String removedDs;
}
public interface VDBModificationListener {
void dataRoleChanged(String policyName) throws AdminProcessingException;
void connectionTypeChanged() throws AdminProcessingException;
void dataSourceChanged(String modelName, String sourceName, String translatorName, String dsName) throws AdminProcessingException;
void onRestart(List<String> modelNames) throws AdminProcessingException;
}
public RuntimeVDB(VDBMetaData vdb, VDBModificationListener listener) {
this.vdb = vdb;
this.listener = listener;
}
public void addDataRole(String policyName, String mappedRole) throws AdminProcessingException {
synchronized (this.vdb) {
DataPolicyMetadata policy = getPolicy(policyName);
List<String> previous = policy.getMappedRoleNames();
policy.addMappedRoleName(mappedRole);
try {
this.listener.dataRoleChanged(policyName);
} catch(AdminProcessingException e) {
policy.setMappedRoleNames(previous);
throw e;
}
}
}
public void remoteDataRole(String policyName, String mappedRole) throws AdminProcessingException{
synchronized (this.vdb) {
DataPolicyMetadata policy = getPolicy(policyName);
List<String> previous = policy.getMappedRoleNames();
policy.removeMappedRoleName(mappedRole);
try {
this.listener.dataRoleChanged(policyName);
} catch(AdminProcessingException e) {
policy.setMappedRoleNames(previous);
throw e;
}
}
}
public void addAnyAuthenticated(String policyName) throws AdminProcessingException{
synchronized (this.vdb) {
DataPolicyMetadata policy = getPolicy(policyName);
boolean previous = policy.isAnyAuthenticated();
policy.setAnyAuthenticated(true);
try {
this.listener.dataRoleChanged(policyName);
} catch(AdminProcessingException e) {
policy.setAnyAuthenticated(previous);
throw e;
}
}
}
public void removeAnyAuthenticated(String policyName) throws AdminProcessingException{
synchronized (this.vdb) {
DataPolicyMetadata policy = getPolicy(policyName);
boolean previous = policy.isAnyAuthenticated();
policy.setAnyAuthenticated(false);
try {
this.listener.dataRoleChanged(policyName);
} catch(AdminProcessingException e) {
policy.setAnyAuthenticated(previous);
throw e;
}
}
}
public void changeConnectionType(ConnectionType type) throws AdminProcessingException {
synchronized (this.vdb) {
ConnectionType previous = this.vdb.getConnectionType();
this.vdb.setConnectionType(type);
try {
this.listener.connectionTypeChanged();
} catch(AdminProcessingException e) {
this.vdb.setConnectionType(previous);
throw e;
}
}
}
public ReplaceResult updateSource(String sourceName, String translatorName, String dsName) throws AdminProcessingException{
synchronized (this.vdb) {
ConnectorManagerRepository cmr = vdb.getAttachment(ConnectorManagerRepository.class);
ConnectorManager cr = cmr.getConnectorManager(sourceName);
if(cr == null) {
throw new AdminProcessingException(RuntimePlugin.Event.TEIID40091, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40091, sourceName, this.vdb.getName(), this.vdb.getVersion()));
}
String previousTranslatorName = cr.getTranslatorName();
String previousDsName = cr.getConnectionName();
//modify all source elements in all models
for (ModelMetaData m : this.vdb.getModelMetaDatas().values()) {
SourceMappingMetadata mapping = m.getSourceMapping(sourceName);
if (mapping != null) {
mapping.setTranslatorName(translatorName);
mapping.setConnectionJndiName(dsName);
}
}
boolean success = false;
try {
this.listener.dataSourceChanged(null, sourceName, translatorName, dsName);
ReplaceResult rr = new ReplaceResult();
if (dsName != null) {
rr.isNew = !dsExists(dsName, cmr);
}
boolean replaced = getVDBStatusChecker().dataSourceReplaced(vdb.getName(), vdb.getVersion(), null, sourceName, translatorName, dsName);
if (replaced && previousDsName != null && !dsExists(previousDsName, cmr)) {
rr.removedDs = previousDsName;
}
success = true;
return rr;
} finally {
if (!success) {
for (ModelMetaData m : this.vdb.getModelMetaDatas().values()) {
SourceMappingMetadata mapping = m.getSourceMapping(sourceName);
if (mapping != null) {
mapping.setTranslatorName(previousTranslatorName);
mapping.setConnectionJndiName(previousDsName);
}
}
}
}
}
}
public ReplaceResult addSource(String modelName, String sourceName, String translatorName, String dsName) throws AdminProcessingException{
synchronized (this.vdb) {
ModelMetaData model = this.vdb.getModel(modelName);
if (model == null) {
throw new AdminProcessingException(RuntimePlugin.Event.TEIID40090, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40090, modelName, this.vdb.getName(), this.vdb.getVersion()));
}
if (!model.isSupportsMultiSourceBindings()) {
throw new AdminProcessingException(RuntimePlugin.Event.TEIID40108, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40108, modelName, this.vdb.getName(), this.vdb.getVersion()));
}
SourceMappingMetadata source = model.getSourceMapping(sourceName);
if(source != null) {
throw new AdminProcessingException(RuntimePlugin.Event.TEIID40107, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40107, sourceName, modelName, this.vdb.getName(), this.vdb.getVersion()));
}
boolean success = false;
try {
SourceMappingMetadata mapping = new SourceMappingMetadata(sourceName, translatorName, dsName);
boolean updated = getVDBStatusChecker().updateSource(vdb.getName(), vdb.getVersion(), mapping, false);
model.addSourceMapping(mapping);
this.listener.dataSourceChanged(modelName, sourceName, translatorName, dsName);
ReplaceResult rr = new ReplaceResult();
if (dsName != null && updated) {
ConnectorManagerRepository cmr = vdb.getAttachment(ConnectorManagerRepository.class);
rr.isNew = !dsExists(dsName, cmr);
}
success = true;
return rr;
} finally {
if (!success) {
model.getSources().remove(sourceName);
}
}
}
}
public ReplaceResult removeSource(String modelName, String sourceName) throws AdminProcessingException{
synchronized (this.vdb) {
ModelMetaData model = this.vdb.getModel(modelName);
if (model == null) {
throw new AdminProcessingException(RuntimePlugin.Event.TEIID40090, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40090, modelName, this.vdb.getName(), this.vdb.getVersion()));
}
if (!model.isSupportsMultiSourceBindings()) {
throw new AdminProcessingException(RuntimePlugin.Event.TEIID40108, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40108, modelName, this.vdb.getName(), this.vdb.getVersion()));
}
if (model.getSources().size() == 1) {
throw new AdminProcessingException(RuntimePlugin.Event.TEIID40109, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40109, modelName, this.vdb.getName(), this.vdb.getVersion()));
}
SourceMappingMetadata source = model.getSources().remove(sourceName);
if(source == null) {
throw new AdminProcessingException(RuntimePlugin.Event.TEIID40091, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40091, sourceName, modelName, this.vdb.getName(), this.vdb.getVersion()));
}
if (model.getSources().size() == 1) {
//we default to multi-source with multiple sources, so now we need to explicitly set to true
model.setSupportsMultiSourceBindings(true);
}
String previousDsName = source.getConnectionJndiName();
boolean success = false;
try {
this.listener.dataSourceChanged(modelName, sourceName, null, null);
ConnectorManagerRepository cmr = vdb.getAttachment(ConnectorManagerRepository.class);
//detect if the ConnectorManager is still used
boolean exists = false;
for (ModelMetaData m : this.vdb.getModelMetaDatas().values()) {
if (m == model) {
continue;
}
if (m.getSourceMapping(sourceName) != null) {
exists = true;
break;
}
}
if (!exists) {
cmr.removeConnectorManager(sourceName);
}
ReplaceResult rr = new ReplaceResult();
if (!dsExists(previousDsName, cmr)) {
rr.removedDs = previousDsName;
}
success = true;
return rr;
} finally {
if (!success) {
//TODO: this means that the order has changed
model.addSourceMapping(source);
}
}
}
}
private boolean dsExists(String dsName, ConnectorManagerRepository cmr) {
String baseDsName = VDBStatusChecker.stripContext(dsName);
for (ConnectorManager cm : cmr.getConnectorManagers().values()) {
if (baseDsName.equals(VDBStatusChecker.stripContext(cm.getConnectionName()))) {
return true;
}
}
return false;
}
public void restart(List<String> modelNames) throws AdminProcessingException {
synchronized(this.vdb) {
this.restartInProgress = true;
this.listener.onRestart(modelNames);
}
}
private DataPolicyMetadata getPolicy(String policyName)
throws AdminProcessingException {
DataPolicyMetadata policy = vdb.getDataPolicyMap().get(policyName);
if (policy == null) {
throw new AdminProcessingException(RuntimePlugin.Event.TEIID40092, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40092, policyName, vdb.getName(), vdb.getVersion()));
}
return policy;
}
public boolean isRestartInProgress() {
return this.restartInProgress;
}
public VDBMetaData getVdb() {
return vdb;
}
protected abstract VDBStatusChecker getVDBStatusChecker();
}