/**
* Copyright 2013-2015 Seagate Technology LLC.
*
* This Source Code Form is subject to the terms of the Mozilla
* Public License, v. 2.0. If a copy of the MPL was not
* distributed with this file, You can obtain one at
* https://mozilla.org/MP:/2.0/.
*
* This program is distributed in the hope that it will be useful,
* but is provided AS-IS, WITHOUT ANY WARRANTY; including without
* the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or
* FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public
* License for more details.
*
* See www.openkinetic.org for more project information
*/
package com.seagate.kinetic.client.io;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import kinetic.client.ClientConfiguration;
import kinetic.client.KineticException;
import com.seagate.kinetic.client.internal.ClientProxy;
import com.seagate.kinetic.client.io.provider.spi.ClientTransportProvider;
import com.seagate.kinetic.common.lib.KineticMessage;
import com.seagate.kinetic.proto.Kinetic;
/**
*
* Kinetic client I/O handler.
* <p>
*
* @author James Hughes
* @author Chiaming Yang
*
*/
public class IoHandler {
// my logger
private final Logger logger = Logger.getLogger(IoHandler.class.getName());
// client configuration
private ClientConfiguration config = null;
// Transpoprt
private ClientTransportProvider transport = null;
private MessageHandler messageHandler = null;
private ClientProxy client = null;
private final boolean useHttp = Boolean.getBoolean("kinetic.io.http");
private final boolean useHttps = Boolean.getBoolean("kinetic.io.https");
// udt transport
private final boolean useUdt = Boolean.getBoolean("kinetic.io.udt");
// define this to load the user defined transport provider
private final boolean isLoadTransportPlugIn = Boolean
.getBoolean("kinetic.client.io.plugin");
// if isLoadTransportPlugIn is defined to true, specified the transport
// provider class name with the following property.
private final String TRANSPORT_PLUGIN_CLASS = "kinetic.client.io.plugin.class";
private static final String UDT_TRANSPORT = "com.seagate.kinetic.client.io.provider.nio.udt.UdtTransportProvider";
private static final String HTTP_TRANSPORT = "com.seagate.kinetic.client.io.provider.nio.http.HttpTransportProvider";
private static final String TCP_TRANSPORT = "com.seagate.kinetic.client.io.provider.tcp.TcpTransportProvider";
private static final String TCP_NIO_TRANSPORT = "com.seagate.kinetic.client.io.provider.nio.tcp.TcpNioTransportProvider";
private static final String SSL_NIO_TRANSPORT = "com.seagate.kinetic.client.io.provider.nio.ssl.SslNioTransportProvider";
/**
* Construct a new instance of IoHandle with the specified configuration.
*
* @param config
* client configuration.
*
* @throws KineticException
* if any I/O or internal exception occurred.
*/
public IoHandler(ClientProxy client)
throws KineticException {
// kinetic client proxy
this.client = client;
// config
this.config = client.getConfiguration();
// initialize
this.init();
}
/**
* Create socket to server and get I/O streams.
*
* @throws KineticException
* if any I/O or internal exception occurred.
*/
private void init() throws KineticException {
try {
// get the transport provider for this kinetic instance.
getTransport();
// message handler to route messages
this.messageHandler = new MessageHandler(this);
// init transport
this.transport.init(messageHandler);
logger.info("connected to device., protocol version: " + Kinetic.Local.getDefaultInstance().getProtocolVersion());
} catch (KineticException ke) {
close();
throw ke;
} catch (Exception e) {
close();
throw new KineticException(e);
}
}
public ClientProxy getClient() {
return this.client;
}
public MessageHandler getMessageHandler() {
return this.messageHandler;
}
/**
* Write message to the binded transport.
*
* @param message
* out bound message.
*
* @throws IOException
* if I/O failed.
*/
public synchronized void write(KineticMessage message) throws IOException {
if (logger.isLoggable(Level.FINEST)) {
logger.finest("writing message: " + message.getMessage());
}
this.transport.write(message);
}
/**
* Close the I/O handler.
*/
public void close() {
try {
this.messageHandler.close();
this.transport.close();
} catch (Exception e) {
logger.log(Level.WARNING, e.getMessage(), e);
}
}
public synchronized ClientTransportProvider getTransport()
throws KineticException {
// instantiate a new instance of transport if none exists yet.
if (transport == null) {
// load transport provider with the defined plug-in class name
if (this.isLoadTransportPlugIn) {
logger.info("using plug-in transport., class name ="
+ TRANSPORT_PLUGIN_CLASS);
String className = this.config
.getProperty(TRANSPORT_PLUGIN_CLASS);
this.transport = this.loadTransportProvider(className);
} else if (config.getUseSsl()) {
logger.info("using ssl transport ...");
this.transport = this.loadTransportProvider(SSL_NIO_TRANSPORT);
} else if (useUdt) {
logger.info("using udt transport ....");
transport = this.loadTransportProvider(UDT_TRANSPORT);
} else if (useHttp) {
logger.info("using http transport ....");
transport = this.loadTransportProvider(HTTP_TRANSPORT);
} else if (useHttps) {
logger.info("using https transport ....");
transport = this.loadTransportProvider(HTTP_TRANSPORT);
} else if (config.getUseNio()) {
logger.info("using Java NIO TCP transport ....");
transport = this.loadTransportProvider(TCP_NIO_TRANSPORT);
} else {
logger.info("using TCP transport ....");
transport = this.loadTransportProvider(TCP_TRANSPORT);
}
}
return transport;
}
/**
* Load transport provider class based on the specified class name.
* <p>
*
* @param className
* the class full name used to load the transport provider
* instance.
*
* @return a new instance of transport provider.
*/
private ClientTransportProvider loadTransportProvider(String className)
throws KineticException {
ClientTransportProvider provider = null;
try {
provider = (ClientTransportProvider) Class.forName(className)
.newInstance();
logger.info("loaded transport provider class., name=" + className);
} catch (Exception e) {
logger.log(Level.WARNING, e.getMessage(), e);
throw new KineticException(e);
}
return provider;
}
public boolean shouldWaitForStatusMessage() {
if (this.useHttp || this.useHttps || this.useUdt) {
return false;
}
return true;
}
}