package com.tesora.dve.externalservice;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import java.sql.ResultSet;
import java.sql.SQLException;
import com.tesora.dve.db.DBNative;
import com.tesora.dve.server.global.HostService;
import com.tesora.dve.singleton.Singletons;
import org.apache.log4j.Logger;
import com.tesora.dve.common.PEConstants;
import com.tesora.dve.common.catalog.CatalogDAO;
import com.tesora.dve.common.catalog.CatalogEntity;
import com.tesora.dve.common.catalog.ExternalService;
import com.tesora.dve.common.catalog.User;
import com.tesora.dve.common.catalog.CatalogDAO.CatalogDAOFactory;
import com.tesora.dve.dbc.ServerDBConnection;
import com.tesora.dve.dbc.ServerDBConnectionParameters;
import com.tesora.dve.exceptions.PEException;
import com.tesora.dve.sql.template.TemplateBuilder;
public class ExternalServiceContextImpl implements ExternalServiceContext {
Logger logger = Logger.getLogger(ExternalServiceContextImpl.class);
// TODO should be configurable? It seems that if we set it short enough to be below
// any DB idle timeout, we should be ok
private static final long IDLE_CONNECT_TIMEOUT = 300;
String externalServiceName;
private ServerDBConnection svrDBconn = null;
private ExternalService externalService = null;
private long connectIdleTimerStart = 0;
private ServerDBConnectionParameters svrDBParams = null;
public ExternalServiceContextImpl(String externalServiceName) throws PEException {
this.externalServiceName = externalServiceName;
// If this External Service needs a DataStore, check if the Database
// needs to be created on the System SG
if (getExternalService().usesDataStore()) {
CatalogDAO c = null;
externalService = null;
try {
c = CatalogDAOFactory.newInstance();
DBNative dbNat = Singletons.require(DBNative.class);
if (c.findDatabase(getExternalService().getDataStoreName(), false) == null) {
// see if we already have an allRandom template, and if so, don't bother creating it
if (!hasAllRandom(getServerDBConnection()))
getServerDBConnection().execute(new TemplateBuilder("allRandom").withTable(".*", "Random").toCreateStatement());
getServerDBConnection().execute(
String.format("create database %s default persistent group %s using template allRandom default character set = %s default collate = %s",
getExternalService().getDataStoreName(),
PEConstants.SYSTEM_GROUP_NAME,
dbNat.getDefaultServerCharacterSet(),
dbNat.getDefaultServerCollation()));
}
} catch (Throwable e) {
throw new PEException("Unable to create service datastore for "
+ externalServiceName, e);
} finally {
if (c != null)
c.close();
}
}
}
private static boolean hasAllRandom(ServerDBConnection conn) {
ResultSet rs = null;
boolean any = false;
try {
rs = conn.executeQuery("select name from information_schema.templates where name = 'allRandom'");
while(rs.next())
any = true;
} catch (SQLException sqle) {
return false;
} finally {
if (rs != null) try {
rs.close();
} catch (SQLException sqle) {
// really?
}
}
return any;
}
@Override
public void setServiceAutoStart(final boolean autoStart) throws PEException {
CatalogDAO c = null;
externalService = null;
try {
c = CatalogDAOFactory.newInstance();
final CatalogDAO cdf = c;
c.new EntityUpdater() {
@Override
public CatalogEntity update() throws Throwable {
ExternalService es = cdf.findExternalService(externalServiceName);
es.setAutoStart(autoStart);
return es;
}
}.execute();
} catch (Throwable e) {
throw new PEException("Unable to update external service " + externalServiceName, e);
} finally {
if ( c != null )
c.close();
}
}
@Override
public boolean getServiceAutoStart() throws PEException {
return getExternalService().isAutoStart();
}
@Override
public void setServiceConfig(final ExternalServiceConfig esConfig) throws PEException {
final String config = esConfig.marshall();
externalService = null;
CatalogDAO c = null;
try {
c = CatalogDAOFactory.newInstance();
final CatalogDAO cdf = c;
c.new EntityUpdater() {
@Override
public CatalogEntity update() throws Throwable {
ExternalService es = cdf.findExternalService(externalServiceName);
es.setConfig(config);
return es;
}
}.execute();
} catch (Throwable e) {
throw new PEException("Unable to update external service " + externalServiceName, e);
} finally {
if ( c != null )
c.close();
}
}
@Override
public void getServiceConfig(ExternalServiceConfig esConfig) throws PEException {
esConfig.unmarshall(getExternalService().getConfig());
}
@Override
public String getServiceName() throws PEException {
return getExternalService().getName();
}
@Override
public String getPlugin() throws PEException {
return getExternalService().getPlugin();
}
boolean isServerDBConnectionTimedOut() {
return ( ( System.currentTimeMillis() - connectIdleTimerStart ) / 1000 ) <= IDLE_CONNECT_TIMEOUT;
}
public ServerDBConnection getServerDBConnection() throws SQLException, PEException {
if ((svrDBconn == null) || (!isServerDBConnectionTimedOut() && !svrDBconn.isInTransaction())) {
closeServerDBConnection();
User connectUser = getConnectUser();
if ( logger.isDebugEnabled() )
logger.debug("Creating ServerDBConnection for " + connectUser.getName());
if (svrDBParams != null)
svrDBParams.setCacheName(externalServiceName);
svrDBconn = new ESServerDBConnection(connectUser.getName(), connectUser.getPlaintextPassword(), svrDBParams);
}
connectIdleTimerStart = System.currentTimeMillis();
return svrDBconn;
}
@Override
public void closeServerDBConnection() throws PEException {
if (svrDBconn != null) {
svrDBconn.closeComms();
svrDBconn = null;
}
}
@Override
public ServerDBConnection useServiceDataStore() throws SQLException, PEException {
if ( !getExternalService().usesDataStore() )
throw new PEException("Service " + getServiceName() + " isn't configured to use a DataStore");
getServerDBConnection().setCatalog(getExternalService().getDataStoreName());
return getServerDBConnection();
}
private ExternalService getExternalService() throws PEException {
if (externalService == null) {
CatalogDAO c = null;
try {
c = CatalogDAOFactory.newInstance();
return c.findExternalService(externalServiceName);
} finally {
if (c != null)
c.close();
}
} else
return externalService;
}
private User getConnectUser() throws PEException {
String userid = getExternalService().getConnectUser();
CatalogDAO c = null;
try {
c = CatalogDAOFactory.newInstance();
return c.findUser(userid);
} finally {
if (c != null)
c.close();
}
}
@Override
public ServerDBConnectionParameters getSvrDBParams() {
return svrDBParams;
}
@Override
public void setSvrDBParams(ServerDBConnectionParameters svrDBParams) {
this.svrDBParams = svrDBParams;
}
@Override
public void close() throws PEException {
closeServerDBConnection();
}
public class ESServerDBConnection extends ServerDBConnection {
public ESServerDBConnection(String connectUser, String connectPwd)
throws PEException {
super(connectUser, connectPwd);
getSSConn().getReplicationOptions().setConnectionFromReplicationSlave(true);
}
public ESServerDBConnection(String connectUser, String connectPwd, ServerDBConnectionParameters svrDBParams) throws PEException {
super(connectUser, connectPwd, svrDBParams);
getSSConn().getReplicationOptions().setConnectionFromReplicationSlave(true);
}
}
}