/*
* 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.jboss;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.util.Properties;
import org.jboss.as.network.SocketBinding;
import org.jboss.modules.Module;
import org.jboss.msc.service.Service;
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.impl.SessionMetadata;
import org.teiid.client.DQP;
import org.teiid.client.security.ILogon;
import org.teiid.client.security.InvalidSessionException;
import org.teiid.client.util.ExceptionUtil;
import org.teiid.client.util.ResultsFuture;
import org.teiid.common.buffer.BufferManager;
import org.teiid.deployers.VDBRepository;
import org.teiid.dqp.internal.process.DQPCore;
import org.teiid.dqp.internal.process.DQPWorkContext;
import org.teiid.dqp.service.SessionService;
import org.teiid.jdbc.ConnectionImpl;
import org.teiid.jdbc.ConnectionProfile;
import org.teiid.jdbc.TeiidDriver;
import org.teiid.jdbc.TeiidSQLException;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.logging.MessageLevel;
import org.teiid.net.CommunicationException;
import org.teiid.net.ConnectionException;
import org.teiid.net.socket.AuthenticationType;
import org.teiid.runtime.RuntimePlugin;
import org.teiid.transport.ClientServiceRegistry;
import org.teiid.transport.ClientServiceRegistryImpl;
import org.teiid.transport.LocalServerConnection;
import org.teiid.transport.LogonImpl;
import org.teiid.transport.ODBCSocketListener;
import org.teiid.transport.SocketConfiguration;
import org.teiid.transport.SocketListener;
import org.teiid.transport.WireProtocol;
import org.teiid.vdb.runtime.VDBKey;
public class TransportService extends ClientServiceRegistryImpl implements Service<ClientServiceRegistry> {
private transient LogonImpl logon;
private SocketConfiguration socketConfig;
private SocketListener socketListener;
private AuthenticationType authenticationType;
private int maxODBCLobSizeAllowed = 5*1024*1024; // 5 MB
private boolean local;
private InetSocketAddress address = null;
private String transportName;
private final InjectedValue<SocketBinding> socketBindingInjector = new InjectedValue<SocketBinding>();
private final InjectedValue<VDBRepository> vdbRepositoryInjector = new InjectedValue<VDBRepository>();
private final InjectedValue<DQPCore> dqpInjector = new InjectedValue<DQPCore>();
private final InjectedValue<BufferManager> bufferManagerInjector = new InjectedValue<BufferManager>();
private final InjectedValue<SessionService> sessionServiceInjector = new InjectedValue<SessionService>();
public TransportService(String transportName) {
this.transportName = transportName;
}
@Override
public ClientServiceRegistry getValue() throws IllegalStateException, IllegalArgumentException {
return this;
}
@Override
public void waitForFinished(VDBKey vdbKey,
int timeOutMillis) throws ConnectionException {
VDBRepository repo = this.vdbRepositoryInjector.getValue();
repo.waitForFinished(vdbKey, timeOutMillis);
}
@Override
public ClassLoader getCallerClassloader() {
return Module.getCallerModule().getClassLoader();
}
@Override
public void start(StartContext context) throws StartException {
this.setVDBRepository(this.getVdbRepository());
SessionService ss = sessionServiceInjector.getValue();
this.setSecurityHelper(ss.getSecurityHelper());
// create the necessary services
this.logon = new LogonImpl(ss, "teiid-cluster"); //$NON-NLS-1$
DQP dqpProxy = proxyService(DQP.class, getDQP(), LogConstants.CTX_DQP);
this.registerClientService(ILogon.class, logon, LogConstants.CTX_SECURITY);
this.registerClientService(DQP.class, dqpProxy, LogConstants.CTX_DQP);
this.setAuthenticationType(ss.getDefaultAuthenticationType());
if (this.socketConfig != null) {
/*
try {
// this is to show the bound socket port in the JMX console
SocketBinding socketBinding = getSocketBindingInjector().getValue();
ManagedServerSocketBinding ss = (ManagedServerSocketBinding)socketBinding.getSocketBindings().getServerSocketFactory().createServerSocket(socketBinding.getName());
socketBinding.getSocketBindings().getNamedRegistry().registerBinding(ss);
} catch (IOException e) {
throw new StartException(IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50013));
}
*/
this.address = getSocketBindingInjector().getValue().getSocketAddress();
this.socketConfig.setBindAddress(this.address.getHostName());
this.socketConfig.setPortNumber(this.address.getPort());
boolean sslEnabled = false;
if (this.socketConfig.getSSLConfiguration() != null) {
sslEnabled = this.socketConfig.getSSLConfiguration().isSslEnabled();
}
if (socketConfig.getProtocol() == WireProtocol.teiid) {
this.socketListener = new SocketListener(address, this.socketConfig, this, getBufferManagerInjector().getValue());
LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50012, this.transportName, address.getHostName(), String.valueOf(address.getPort()), (sslEnabled?"ON":"OFF"))); //$NON-NLS-1$ //$NON-NLS-2$
}
else if (socketConfig.getProtocol() == WireProtocol.pg) {
TeiidDriver driver = new TeiidDriver();
driver.setLocalProfile(new ConnectionProfile() {
@Override
public ConnectionImpl connect(String url, Properties info) throws TeiidSQLException {
try {
LocalServerConnection sc = new LocalServerConnection(info, true){
@Override
protected ClientServiceRegistry getClientServiceRegistry(String name) {
return TransportService.this;
}
};
return new ConnectionImpl(sc, info, url);
} catch (CommunicationException e) {
throw TeiidSQLException.create(e);
} catch (ConnectionException e) {
throw TeiidSQLException.create(e);
}
}
});
ODBCSocketListener odbc = new ODBCSocketListener(address, this.socketConfig, this, getBufferManagerInjector().getValue(), getMaxODBCLobSizeAllowed(), this.logon, driver);
this.socketListener = odbc;
LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50037, this.transportName, address.getHostName(), String.valueOf(address.getPort()), (sslEnabled?"ON":"OFF"))); //$NON-NLS-1$ //$NON-NLS-2$
}
else {
throw new StartException(IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50013));
}
}
else {
LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50038, LocalServerConnection.jndiNameForRuntime(transportName)));
}
}
@Override
public void stop(StopContext context) {
// Stop socket transport(s)
if (this.socketListener != null) {
this.socketListener.stop();
this.socketListener = null;
}
if (this.socketConfig != null) {
if (socketConfig.getProtocol() == WireProtocol.teiid) {
LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50039, this.transportName, this.address.getHostName(), String.valueOf(this.address.getPort())));
}
else if (socketConfig.getProtocol() == WireProtocol.pg) {
LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50040, this.transportName, this.address.getHostName(), String.valueOf(this.address.getPort())));
}
}
else {
LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50041, LocalServerConnection.jndiNameForRuntime(transportName)));
}
}
/**
* Creates an proxy to validate the incoming session
*/
private <T> T proxyService(final Class<T> iface, final T instance, String context) {
return iface.cast(Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {iface}, new LogManager.LoggingProxy(instance, context, MessageLevel.TRACE) {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Throwable exception = null;
try {
DQPWorkContext workContext = DQPWorkContext.getWorkContext();
if (workContext.getSession().isClosed() || workContext.getSessionId() == null) {
if (method.getName().equals("closeRequest")) { //$NON-NLS-1$
//the client can issue close request effectively concurrently with close session
//there's no need for this to raise an exception
return ResultsFuture.NULL_FUTURE;
}
String sessionID = workContext.getSession().getSessionId();
if (sessionID == null) {
throw new InvalidSessionException(RuntimePlugin.Event.TEIID40041, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40041));
}
workContext.setSession(new SessionMetadata());
throw new InvalidSessionException(RuntimePlugin.Event.TEIID40042, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40042, sessionID));
}
return super.invoke(proxy, method, args);
} catch (InvocationTargetException e) {
exception = e.getTargetException();
} catch(Throwable t){
exception = t;
}
throw ExceptionUtil.convertException(method, exception);
}
}));
}
public InjectedValue<SocketBinding> getSocketBindingInjector() {
return this.socketBindingInjector;
}
public SocketConfiguration getSocketConfig() {
return socketConfig;
}
public void setSocketConfig(SocketConfiguration socketConfig) {
this.socketConfig = socketConfig;
}
public InjectedValue<VDBRepository> getVdbRepositoryInjector() {
return vdbRepositoryInjector;
}
private VDBRepository getVdbRepository() {
return vdbRepositoryInjector.getValue();
}
private DQPCore getDQP() {
return getDqpInjector().getValue();
}
public InjectedValue<DQPCore> getDqpInjector() {
return dqpInjector;
}
public InjectedValue<BufferManager> getBufferManagerInjector() {
return bufferManagerInjector;
}
@Override
public AuthenticationType getAuthenticationType() {
return authenticationType;
}
@Override
public void setAuthenticationType(AuthenticationType authenticationType) {
this.authenticationType = authenticationType;
}
public InjectedValue<SessionService> getSessionServiceInjector() {
return sessionServiceInjector;
}
private int getMaxODBCLobSizeAllowed() {
return this.maxODBCLobSizeAllowed;
}
public void setMaxODBCLobSizeAllowed(int lobSize) {
this.maxODBCLobSizeAllowed = lobSize;
}
public void setLocal(boolean v) {
this.local = v;
}
public boolean isLocal() {
return this.local;
}
}