/*
 * 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.
 * Modified by
 * @author  Data Virtuality GmbH
 * @date    $Date$
 *  
 */
// https://issues.jboss.org/browse/TEIID-2235, 2661, 2178, 2297
// https://issues.jboss.org/browse/TEIID-247, 2166, 2151, 2234, 2581, 2571, 2369, 1386, 2226, 2233, 2224, 2225, 2257
// https://issues.jboss.org/browse/TEIID-2153
// https://issues.jboss.org/browse/TEIID-2171
// https://issues.jboss.org/browse/TEIID-2359
// https://issues.jboss.org/browse/TEIID-2149
// https://issues.jboss.org/browse/TEIID-2358
// https://issues.jboss.org/browse/TEIID-2410
// https://issues.jboss.org/browse/TEIID-2271
// https://issues.jboss.org/browse/TEIID-2467
// https://issues.jboss.org/browse/TEIID-2429
// https://issues.jboss.org/browse/TEIID-2363
// https://issues.jboss.org/browse/TEIID-2160
// https://issues.jboss.org/browse/TEIID-2461
// https://issues.jboss.org/browse/TEIID-2797
// https://issues.jboss.org/browse/TEIID-2326
// https://issues.jboss.org/browse/TEIID-1557
// https://issues.jboss.org/browse/TEIID-2368
// https://issues.jboss.org/browse/TEIID-2489
// https://issues.jboss.org/browse/TEIID-3519
// https://issues.redhat.com/browse/TEIID-5630
// https://issues.redhat.com/browse/TEIID-2655
// https://issues.redhat.com/browse/TEIID-3666
// https://issues.redhat.com/browse/TEIID-2116
package org.teiid.jboss;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;

import javax.xml.stream.XMLStreamException;

import org.jboss.as.controller.OperationFailedException;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceContainer;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;
import org.teiid.adminapi.AdminProcessingException;
import org.teiid.adminapi.Translator;
import org.teiid.adminapi.VDB.Status;
import org.teiid.adminapi.impl.ModelMetaData;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.adminapi.impl.VDBMetadataParser;
import org.teiid.adminapi.impl.VDBTranslatorMetaData;
import org.teiid.adminapi.impl.ModelMetaData.Message.Severity;
import org.teiid.common.buffer.BufferManager;
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.deployers.CompositeGlobalTableStore;
import org.teiid.deployers.CompositeVDB;
import org.teiid.deployers.RuntimeVDB;
import org.teiid.deployers.TranslatorUtil;
import org.teiid.deployers.UDFMetaData;
import org.teiid.deployers.VDBLifeCycleListener;
import org.teiid.deployers.VDBRepository;
import org.teiid.deployers.VDBStatusChecker;
import org.teiid.deployers.VirtualDatabaseException;
import org.teiid.dqp.internal.datamgr.ConnectorManager;
import org.teiid.dqp.internal.datamgr.ConnectorManagerRepository;
import org.teiid.dqp.internal.datamgr.TranslatorRepository;
import org.teiid.dqp.internal.datamgr.ConnectorManagerRepository.ConnectorManagerException;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.metadata.Datatype;
import org.teiid.metadata.MetadataFactory;
import org.teiid.metadata.MetadataRepository;
import org.teiid.metadata.MetadataStore;
import org.teiid.query.ObjectReplicator;
import org.teiid.query.metadata.TransformationMetadata.Resource;
import org.teiid.query.tempdata.GlobalTableStore;
import org.teiid.runtime.AbstractVDBDeployer;
import org.teiid.translator.DelegatingExecutionFactory;
import org.teiid.translator.ExecutionFactory;
import org.teiid.translator.TranslatorException;

class VDBService extends AbstractVDBDeployer implements Service<RuntimeVDB> {
	private VDBMetaData vdb;
	private RuntimeVDB runtimeVDB;
	protected final InjectedValue<VDBRepository> vdbRepositoryInjector = new InjectedValue<VDBRepository>();
	protected final InjectedValue<TranslatorRepository> translatorRepositoryInjector = new InjectedValue<TranslatorRepository>();
	protected final InjectedValue<Executor> executorInjector = new InjectedValue<Executor>();
	protected final InjectedValue<ObjectSerializer> serializerInjector = new InjectedValue<ObjectSerializer>();
	protected final InjectedValue<BufferManager> bufferManagerInjector = new InjectedValue<BufferManager>();
	protected final InjectedValue<ObjectReplicator> objectReplicatorInjector = new InjectedValue<ObjectReplicator>();
	protected final InjectedValue<VDBStatusChecker> vdbStatusCheckInjector = new InjectedValue<VDBStatusChecker>();
	
	private VDBLifeCycleListener vdbListener;
	private LinkedHashMap<String, Resource> visibilityMap;
	
	public VDBService(VDBMetaData metadata, LinkedHashMap<String, Resource> visibilityMap) {
		this.vdb = metadata;
		this.visibilityMap = visibilityMap;
	}

	private static class LifecycleListener implements VDBLifeCycleListener, Serializable {
		private static final long serialVersionUID = -4543272838289506381L;

		private final transient VDBService service;
		private final transient StartContext context;

		private LifecycleListener(VDBService service, StartContext context) {
			this.service = service;
			this.context = context;
		}

		@Override
		public void added(String name, int version, CompositeVDB cvdb) {
		}
		@Override
		public void removed(String name, int version, CompositeVDB cvdb) {
		}

		@Override
		public void finishedDeployment(String name, int version, CompositeVDB cvdb) {
			if (!name.equals(service.vdb.getName()) || version != service.vdb.getVersion()) {
				return;
			}
			VDBMetaData vdbInstance = cvdb.getVDB();
			// add object replication to temp/matview tables
			GlobalTableStore gts = CompositeGlobalTableStore.createInstance(cvdb, service.getBuffermanager(), service.objectReplicatorInjector.getValue());

			vdbInstance.addAttchment(GlobalTableStore.class, gts);
			//need to construct/install the service in a single thread
			final ServiceBuilder<Void> vdbService = service.addVDBFinishedService(context);
			vdbService.install();
		}
	}

	@Override
	public void start(final StartContext context) throws StartException {
		
		ConnectorManagerRepository cmr = new ConnectorManagerRepository();
		TranslatorRepository repo = new TranslatorRepository();
		
		this.vdb.addAttchment(TranslatorRepository.class, repo);

		// check if this is a VDB with index files, if there are then build the TransformationMetadata
		UDFMetaData udf = this.vdb.getAttachment(UDFMetaData.class);
		
		// add required connector managers; if they are not already there
		for (Translator t: this.vdb.getOverrideTranslators()) {
			VDBTranslatorMetaData data = (VDBTranslatorMetaData)t;
			
			String type = data.getType();
			VDBTranslatorMetaData parent = getTranslatorRepository().getTranslatorMetaData(type);
			data.setModuleName(parent.getModuleName());
			data.addAttchment(ClassLoader.class, parent.getAttachment(ClassLoader.class));
			data.setParent(parent);
			repo.addTranslatorMetadata(data.getName(), data);
		}

		createConnectorManagers(cmr, repo, this.vdb);
		this.vdbListener = new VDBLifeCycleListener() {
			@Override
			public void added(String name, int version, CompositeVDB cvdb) {
			}
			@Override
			public void removed(String name, int version, CompositeVDB cvdb) {
			}

			@Override
			public void finishedDeployment(String name, int version, CompositeVDB cvdb) {
				if (!name.equals(VDBService.this.vdb.getName()) || version != VDBService.this.vdb.getVersion()) {
					return;
				}
				VDBMetaData vdbInstance = cvdb.getVDB();
				// add object replication to temp/matview tables
				GlobalTableStore gts = CompositeGlobalTableStore.createInstance(cvdb, getBuffermanager(), objectReplicatorInjector.getValue());

				vdbInstance.addAttchment(GlobalTableStore.class, gts);
				//need to construct/install the service in a single thread
				final ServiceBuilder<Void> vdbService = addVDBFinishedService(context);
				vdbService.install();
			}
		};
		
		getVDBRepository().addListener(this.vdbListener);
				
		MetadataStore store = new MetadataStore();
		
		try {
			this.assignMetadataRepositories(vdb, super.getMetadataRepository("index")); //$NON-NLS-1$
			// add transformation metadata to the repository.
			getVDBRepository().addVDB(this.vdb, store, visibilityMap, udf, cmr);
		} catch (VirtualDatabaseException e) {
			throw new StartException(e);
		}		
		
		this.vdb.removeAttachment(UDFMetaData.class);
		try {
			loadMetadata(this.vdb, cmr, store);
		} catch (TranslatorException e) {
			throw new StartException(e);
		}
				
		this.runtimeVDB = buildRuntimeVDB(this.vdb, context.getController().getServiceContainer());		
	}

	private RuntimeVDB buildRuntimeVDB(final VDBMetaData vdbMetadata, final ServiceContainer serviceContainer) {
		RuntimeVDB.VDBModificationListener modificationListener = new RuntimeVDB.VDBModificationListener() {
			@Override
			public void dataRoleChanged(String policyName) throws AdminProcessingException {
				save();
			}
			@Override
			public void connectionTypeChanged() throws AdminProcessingException {
				save();
			}
			@Override
			public void dataSourceChanged(String modelName, String sourceName,String translatorName, String dsName) throws AdminProcessingException {
				save();
			}
			@Override
			public void onRestart(List<String> modelNames) {
				ServiceController<?> switchSvc = serviceContainer.getService(TeiidServiceNames.vdbSwitchServiceName(vdbMetadata.getName(), vdbMetadata.getVersion()));
		        if (switchSvc != null) {
		        	if (!modelNames.isEmpty()) {
						for (String model:modelNames) {
							deleteModelCache(model);
						}		        	
		        	}
		        	else {
		        		for (String model:vdbMetadata.getModelMetaDatas().keySet()) {
		        			deleteModelCache(model);
		        		}
		        	}
		            switchSvc.setMode(ServiceController.Mode.REMOVE);
		        }		        
			}			
		};
		return new RuntimeVDB(vdbMetadata, modificationListener) {
			protected VDBStatusChecker getVDBStatusChecker() {
				return VDBService.this.vdbStatusCheckInjector.getValue();
			}
		};
	}
	
	Service<Void> createVoidService() {
		return new Service<Void>() {
			@Override
			public Void getValue() throws IllegalStateException, IllegalArgumentException {
				return null;
			}
			@Override
			public void start(StartContext sc)throws StartException {}
			@Override
			public void stop(StopContext sc) {}
		};		
	}

	private ServiceBuilder<Void> addVDBFinishedService(StartContext context) {
		ServiceContainer serviceContainer = context.getController().getServiceContainer();
		final ServiceController<?> controller = serviceContainer.getService(TeiidServiceNames.vdbFinishedServiceName(vdb.getName(), vdb.getVersion()));
        if (controller != null) {
            controller.setMode(ServiceController.Mode.REMOVE);
        }
        return serviceContainer.addService(TeiidServiceNames.vdbFinishedServiceName(vdb.getName(), vdb.getVersion()), createVoidService());
	}

	@Override
	public void stop(StopContext context) {
		ServiceController<?> switchSvc = context.getController().getServiceContainer().getService(TeiidServiceNames.vdbSwitchServiceName(vdb.getName(), vdb.getVersion()));
        if (switchSvc != null) {
            switchSvc.setMode(ServiceController.Mode.REMOVE);
        }
		// stop object replication
		if (this.objectReplicatorInjector.getValue() != null) {
			GlobalTableStore gts = vdb.getAttachment(GlobalTableStore.class);
			this.objectReplicatorInjector.getValue().stop(gts);
		}		
		getVDBRepository().removeListener(this.vdbListener);
		getVDBRepository().removeVDB(this.vdb.getName(), this.vdb.getVersion());
		final ServiceController<?> controller = context.getController().getServiceContainer().getService(TeiidServiceNames.vdbFinishedServiceName(vdb.getName(), vdb.getVersion()));
        if (controller != null) {
            controller.setMode(ServiceController.Mode.REMOVE);
        }	        
		LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50026, this.vdb));
	}

	@Override
	public RuntimeVDB getValue() throws IllegalStateException,IllegalArgumentException {
		return this.runtimeVDB;
	}
	
	private void createConnectorManagers(ConnectorManagerRepository cmr, final TranslatorRepository repo, final VDBMetaData deployment) throws StartException {
		final IdentityHashMap<Translator, ExecutionFactory<Object, Object>> map = new IdentityHashMap<Translator, ExecutionFactory<Object, Object>>();
		
		try {
			cmr.createConnectorManagers(deployment, new ConnectorManagerRepository.ExecutionFactoryProvider() {
				
				@Override
				public ExecutionFactory<Object, Object> getExecutionFactory(String name) throws ConnectorManagerException {
					return VDBService.getExecutionFactory(name, repo, getTranslatorRepository(), deployment, map, new HashSet<String>());
				}
			});
		} catch (ConnectorManagerException e) {
			if (e.getCause() != null) {
				throw new StartException(IntegrationPlugin.Event.TEIID50035.name()+" "+e.getMessage(), e.getCause()); //$NON-NLS-1$
			}
			throw new StartException(e.getMessage());
		}
	}
	
	static ExecutionFactory<Object, Object> getExecutionFactory(String name, TranslatorRepository vdbRepo, TranslatorRepository repo, VDBMetaData deployment, IdentityHashMap<Translator, ExecutionFactory<Object, Object>> map, HashSet<String> building) throws ConnectorManagerException {
		if (!building.add(name)) {
			throw new ConnectorManagerException(IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50076, deployment.getName(), deployment.getVersion(), building));
		}
		VDBTranslatorMetaData translator = vdbRepo.getTranslatorMetaData(name);
		if (translator == null) {
			translator = repo.getTranslatorMetaData(name);
		}
		if (translator == null) {
			throw new ConnectorManagerException(IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50078, deployment.getName(), deployment.getVersion(), name));
		}
		try {
			ExecutionFactory<Object, Object> ef = map.get(translator);
			if ( ef == null) {

				ef = TranslatorUtil.buildExecutionFactory(translator);
				if (ef instanceof DelegatingExecutionFactory) {
					DelegatingExecutionFactory delegator = (DelegatingExecutionFactory)ef;
					String delegateName = delegator.getDelegateName();
					if (delegateName != null) {
						ExecutionFactory<Object, Object> delegate = getExecutionFactory(delegateName, vdbRepo, repo, deployment, map, building);
						((DelegatingExecutionFactory) ef).setDelegate(delegate);
					}
				}
				map.put(translator, ef);
			}
			return ef;
		} catch(TeiidException e) {
			throw new ConnectorManagerException(e);
		}
	}

    protected void loadMetadata(final VDBMetaData vdb, final ModelMetaData model, final ConnectorManagerRepository cmr, final MetadataRepository metadataRepo, final MetadataStore vdbMetadataStore, final AtomicInteger loadCount) {

    	String msg = IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50029,vdb.getName(), vdb.getVersion(), model.getName(), SimpleDateFormat.getInstance().format(new Date())); 
		model.addRuntimeMessage(Severity.INFO, msg); 
		LogManager.logInfo(LogConstants.CTX_RUNTIME, msg);

		final Runnable job = new Runnable() {
			@Override
			public void run() {
				// BUG: DV-27
				// ISSUE: the following scenario had a wrong behavior 
				// 1. set UserConnectorMetadata=true
				// 2. run jboss -> vdb is deployed and metadata loaded by scratch
				// 3. set UserConnectorMetadata=cached -> vdb is redeployed and metadata again reloaded (OK)
				// 4. stop jboss
				// 5. set UserConnectorMetadata=true
				// 6. run jboss -> vdb is deployed, BUT metadata still loaded from cache. Clearing the standalone\data folder and restarting jboss leads to reloading the metadata.
				// SOLUTION: the value of the property UserConnectorMetadata was not checked if metadata files were found and cache was always used.
				// Now the cache is used only if the corresponding property is properly set
				// FIXED by Salvatore Raunich
				// date 20.09.2012
				boolean useCache = !vdb.isDynamic();
				if (vdb.isDynamic()) {
					useCache = "cached".equalsIgnoreCase(vdb.getPropertyValue("UseConnectorMetadata")); //$NON-NLS-1$ //$NON-NLS-2$
				}
				// BUG END

				boolean cached = false;
				Exception ex = null;
				TranslatorException te = null;
				// designer based models define data types based on their built in data types, which are system vdb data types
				Map<String, Datatype> datatypes = getVDBRepository().getRuntimeTypeMap();
				Map<String, Datatype> builtin = getVDBRepository().getSystemStore().getDatatypes();
				final File cachedFile = getSerializer().buildModelFile(vdb, model.getName());
				MetadataFactory factory = getSerializer().loadSafe(cachedFile, MetadataFactory.class);
				// BUG: Views defined as a DDL script in the VDB were not materialized.
				// ISSUE: DVCORE-58
				// SOLUTION: The problem was partially related to a known bug in Teiid, fixed in version 8.1. See
				// https://issues.jboss.org/browse/TEIID-2047 for more details.
				// FIXED by Salvatore Raunich
				// date 29.08.2012
				if (factory != null && factory.getSchema() != null)
					factory.getSchema().setPhysical(model.isSource());
				// BUG END
				// BUG: DV-27
				// ISSUE: the following scenario had a wrong behavior 
				// 1. set UserConnectorMetadata=true
				// 2. run jboss -> vdb is deployed and metadata loaded by scratch
				// 3. set UserConnectorMetadata=cached -> vdb is redeployed and metadata again reloaded (OK)
				// 4. stop jboss
				// 5. set UserConnectorMetadata=true
				// 6. run jboss -> vdb is deployed, BUT metadata still loaded from cache. Clearing the standalone\data folder and restarting jboss leads to reloading the metadata.
				// SOLUTION: the value of the property UserConnectorMetadata was not checked if metadata files were found and cache was always used.
				// Now the cache is used only if the corresponding property is properly set
				// FIXED by Salvatore Raunich
				// date 20.09.2012
//				if (factory != null) {
				if (useCache && factory != null) {
				// BUG END
					factory.correctDatatypes(datatypes, builtin);
					cached = true;
					LogManager.logTrace(LogConstants.CTX_RUNTIME, "Model ", model.getName(), "in VDB ", vdb.getName(), " was loaded from cached metadata"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
					model.addAttchment(MetadataFactory.class, factory);
				} else {
					factory = createMetadataFactory(vdb, model);
					ExecutionFactory ef = null;
					Object cf = null;
					
					try {
						ConnectorManager cm = getConnectorManager(model, cmr);
						if (cm != null) {
							ef = cm.getExecutionFactory();
							cf = cm.getConnectionFactory();
						}
					} catch (TranslatorException e) {
						LogManager.logDetail(LogConstants.CTX_RUNTIME, e, "Failed to get a connection factory for metadata load."); //$NON-NLS-1$
						te = e;
					}
					ClassLoader originalCL = Thread.currentThread().getContextClassLoader();
					try {
						Thread.currentThread().setContextClassLoader(metadataRepo.getClass().getClassLoader());
						metadataRepo.loadMetadata(factory, ef, cf);		
						LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50030,vdb.getName(), vdb.getVersion(), model.getName(), SimpleDateFormat.getInstance().format(new Date())));
					} catch (Exception e) {
						ex = e;
					} finally {
						Thread.currentThread().setContextClassLoader(originalCL);
					}
				}
		    					
				synchronized (vdb) {
					VDBStatusChecker marked = model.removeAttachment(VDBStatusChecker.class);

			    	if (ex == null) {
			    		if (!cached) {
				    		// cache the schema to disk
							cacheMetadataStore(model, factory);
			    		}
						
						metadataLoaded(vdb, model, vdbMetadataStore, loadCount, factory, true);
			    	} else {
 			    		String errorMsg = ex.getMessage()==null?ex.getClass().getName():ex.getMessage();
			    		if (te != null) {
			    			errorMsg += ": " + te.getMessage(); //$NON-NLS-1$ 
			    		}
 			    		model.addRuntimeError(errorMsg); 
						//log the exception of a non-teiid runtime exception as it may indicate a problem 
						LogManager.logWarning(LogConstants.CTX_RUNTIME, (ex instanceof RuntimeException && !(ex instanceof TeiidRuntimeException))?ex:null, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50036,vdb.getName(), vdb.getVersion(), model.getName(), ex.getMessage()));
						if (ex instanceof RuntimeException) {
							metadataLoaded(vdb, model, vdbMetadataStore, loadCount, factory, false);
						} else {
							if (marked != null) {
								getExecutor().execute(this);
							} else {
								//defer the load to the status checker if/when a source is available/redeployed
								model.addAttchment(Runnable.class, this);
								// EXTENSION
								// ISSUE: DVCORE-14
								// FIXED BY: Salvatore Raunich
								// DATE: 20.11.2012
								// force the call to metadataLoaded() method providing "false" as parameter for success
								metadataLoaded(vdb, model, vdbMetadataStore, loadCount, factory, false);
								// END EXTENSION
							}
						}
			    	}
		    	}
			}
		};	    		
		
		Executor executor = getExecutor();
	    //wrap the runnable to trap exceptions that may be caused by an asynch deployment issue
	    executor.execute(new Runnable() {
 	        @Override
 	        public void run() {
			    try {
				    job.run();
			    } catch (IllegalStateException e) {
				    if (vdb.getStatus() != Status.FAILED && vdb.getStatus() != Status.REMOVED) {
					    throw e;
				    }
				    LogManager.logDetail(LogConstants.CTX_RUNTIME, e, "Could not load metadata for a removed or failed deployment."); //$NON-NLS-1$
			    }
 	        }
 	    });
	}	
    
    // if is not dynamic always cache; else check for the flag (this may need to be revisited with index vdb)
	private void cacheMetadataStore(final ModelMetaData model, MetadataFactory schema) {
		boolean cache = !vdb.isDynamic();
		if (vdb.isDynamic()) {
			cache = "cached".equalsIgnoreCase(vdb.getPropertyValue("UseConnectorMetadata")); //$NON-NLS-1$ //$NON-NLS-2$
		}
		
		if (cache) {
			final File cachedFile = getSerializer().buildModelFile(vdb, model.getName());
			try {
				getSerializer().saveAttachment(cachedFile, schema, false);
			} catch (IOException e) {
				LogManager.logWarning(LogConstants.CTX_RUNTIME, e, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50044, vdb.getName(), vdb.getVersion(), model.getName()));
			}
		}
	}    
	
	private void deleteModelCache(String modelName) {
		final File cachedFile = getSerializer().buildModelFile(vdb, modelName);
		getSerializer().removeAttachment(cachedFile);
	}

	protected VDBRepository getVDBRepository() {
		return vdbRepositoryInjector.getValue();
	}
	
	private TranslatorRepository getTranslatorRepository() {
		return this.translatorRepositoryInjector.getValue();
	}
	
	// EXTENSION
	// ISSUE: DVCORE-2233
	// FIXED BY: Roman Pedchenko
	// DATE: 2014.07.31
//	private Executor getExecutor() {
	@Override
	public Executor getExecutor() {
	// END EXTENSION
		return this.executorInjector.getValue();
	}
	
	private ObjectSerializer getSerializer() {
		return serializerInjector.getValue();
	}
	
	private BufferManager getBuffermanager() {
		return bufferManagerInjector.getValue();
	}
	
	private void save() throws AdminProcessingException{
		try {
			ObjectSerializer os = getSerializer();
			VDBMetadataParser.marshell(this.vdb, os.getVdbXmlOutputStream(this.vdb));
		} catch (IOException e) {
			 throw new AdminProcessingException(IntegrationPlugin.Event.TEIID50048, e);
		} catch (XMLStreamException e) {
			 throw new AdminProcessingException(IntegrationPlugin.Event.TEIID50049, e);
		}
	}
	
	/**
	 * Override for module based loading
	 */
	@SuppressWarnings("unchecked")
	@Override
	protected MetadataRepository<?, ?> getMetadataRepository(String repoType) throws VirtualDatabaseException {
		MetadataRepository<?, ?> repo = super.getMetadataRepository(repoType);
		if (repo != null) {
			return repo;
		}
	        try {
			repo = TeiidAdd.buildService(MetadataRepository.class, repoType);
		} catch (OperationFailedException e) {
			throw new VirtualDatabaseException(IntegrationPlugin.Event.TEIID50057, e, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50057, repoType));
	        }
		MetadataRepository old = this.repositories.putIfAbsent(repoType, repo);
		return old!=null?old:repo;
        }
}
