Spring integration on reconnect TCP send handshake - tcp

I'm trying to use the ClientMode on the TcpSendingMessageHandler to auto-reconnect the connection. This connection needs to be kept open so it's important to implement a reconnect function.
private MessageChannel createNewSubflow(Message<?> message) {
String host = (String) message.getHeaders().get("host");
Integer port = (Integer) message.getHeaders().get("port");
Assert.state(host != null && port != null, "host and/or port header missing");
String hostPort = host + port;
TcpNetClientConnectionFactory cf = new TcpNetClientConnectionFactory(host, port);
TcpReceivingChannelAdapter messageHandler = new TcpReceivingChannelAdapter();
cf.setLeaveOpen(true);
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
HelloWorldInterceptorFactory factory = new HelloWorldInterceptorFactory();
fc.setInterceptors(new TcpConnectionInterceptorFactory[] { factory} );
cf.setInterceptorFactoryChain(fc);
cf.setDeserializer(new CustomSerializerDeserializer());
messageHandler.setErrorChannel(errorChannel);
messageHandler.setConnectionFactory(cf);
messageHandler.setOutputChannel(outputChannel);
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
handler.setConnectionFactory(cf);
handler.setClientMode(true);
handler.setRetryInterval(5000);
IntegrationFlow flow = f -> f.handle(handler);
IntegrationFlowContext.IntegrationFlowRegistration flowRegistration =
this.flowContext
.registration(flow)
.addBean(cf)
.id(hostPort + ".flow")
.register();
MessageChannel inputChannel = flowRegistration.getInputChannel();
this.subFlows.put(hostPort, inputChannel);
return inputChannel;
}
Unfortinily I need to send a handshake after the connection socket has been opened.
I tried to add a Message interceptor described in this post (Interceptor) but when the connection socket is restored it doesn't enter the interceptor.
I get this warning when the socket is restored:
HelloWorldInterceptor : No publisher available to publish TcpConnectionOpenEvent [source=HelloWorldInterceptor

The warning is coming out of the interceptor because the factory was not initialized properly.
You need to add .addBean() for the interceptor factory too.
EDIT
As mentioned in the comments an alternative to the interceptors is just to use an event listener.
I just tested with this and see no problems:
#SpringBootApplication
public class So65899947Application {
public static void main(String[] args) {
SpringApplication.run(So65899947Application.class, args);
}
#Bean
public IntegrationFlow flow() {
return f -> f.handle(Tcp.outboundAdapter(Tcp.netClient("localhost", 1234))
.clientMode(true)
.retryInterval(5000));
}
}
#Component
class InitialSender {
private final IntegrationFlow flow;
InitialSender(IntegrationFlow flow) {
this.flow = flow;
}
#EventListener
public void opened(TcpConnectionOpenEvent event) {
this.flow.getInputChannel().send(new GenericMessage<>("Hello there",
Collections.singletonMap(IpHeaders.CONNECTION_ID, event.getConnectionId())));
}
}
$ nc -l 1234
Hello there
^C
$ nc -l 1234
Hello there
^C
$ nc -l 1234
Hello there
^C
$ nc -l 1234
Hello there
^C
$ nc -l 1234
Hello there
^C
EDIT2
Same results for me when I changed it to use a gateway...
#SpringBootApplication
#IntegrationComponentScan
public class So65899947Application {
public static void main(String[] args) {
SpringApplication.run(So65899947Application.class, args);
}
#Bean
public IntegrationFlow flow() {
return f -> f.handle(Tcp.outboundAdapter(Tcp.netClient("localhost", 1234))
.clientMode(true)
.retryInterval(5000));
}
}
#MessagingGateway(defaultRequestChannel = "flow.input")
interface Gate {
void handShake(#Payload String message, #Header(IpHeaders.CONNECTION_ID) String conn);
}
#Component
class InitialSender {
private final Gate gate;
InitialSender(Gate gate) {
this.gate = gate;
}
#EventListener
public void opened(TcpConnectionOpenEvent event) {
this.gate.handShake("Hello there", event.getConnectionId());
}
}

Related

spring-kafka delivery attempt is not being increased when message was retried

I am using spring-kafka 2.8.6 with retry RetryTopicConfiguration.
#KafkaListener(
topics = "...",
groupId = "...",
containerFactory = "kafkaListenerContainerFactory")
public void listenWithHeaders(final #Valid #Payload Event event,
#Header(KafkaHeaders.DELIVERY_ATTEMPT) final int deliveryAttempt) {
}
I have setup common error handler, and also enable delivery attempt header.
#Bean
public ConcurrentKafkaListenerContainerFactory<String, Event>
kafkaListenerContainerFactory(#Qualifier("ConsumerFactory") final ConsumerFactory<String, Event> consumerFactory) {
final ConcurrentKafkaListenerContainerFactory<String, Event> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory);
factory.setCommonErrorHandler(new DefaultErrorHandler(new ExponentialBackOff(kafkaProperties.getExponentialBackoffInitialInterval(), kafkaProperties.getExponentialBackoffMultiplier())));
LOGGER.info("setup ConcurrentKafkaListenerContainerFactory");
factory.getContainerProperties().setDeliveryAttemptHeader(true);
return factory;
}
But when retry is triggered, delivery attempt in the message header is always 1, never increase.
Do I miss any other part? Thanks!
--- I am using retry topic configuration.
#Bean
public RetryTopicConfiguration retryableTopicKafkaTemplate(#Qualifier("kafkaTemplate") KafkaTemplate<String, Event> kafkaTemplate) {
return RetryTopicConfigurationBuilder
.newInstance()
.exponentialBackoff(
properties.getExponentialBackoffInitialInterval(),
properties.getExponentialBackoffMultiplier(),
properties.getExponentialBackoffMaxInterval())
.autoCreateTopics(properties.isRetryTopicAutoCreateTopics(), properties.getRetryTopicAutoCreateNumPartitions(), properties.getRetryTopicAutoCreateReplicationFactor())
.maxAttempts(properties.getMaxAttempts())
.notRetryOn(...) .retryTopicSuffix(properties.getRetryTopicSuffix())
.dltSuffix(properties.getDltSuffix())
.create(kafkaTemplate);
---- Followed by Gary's suggestion, have it fully working now with my listener.
#KafkaListener(
topics = "...",
groupId = "...",
containerFactory = "kafkaListenerContainerFactory")
public void listenWithHeaders(final #Valid #Payload Event event,
#Header(value = RetryTopicHeaders.DEFAULT_HEADER_ATTEMPTS, required = false) final Integer deliveryAttempt) {
...
It works fine for me with this:
#SpringBootApplication
public class So72871495Application {
public static void main(String[] args) {
SpringApplication.run(So72871495Application.class, args);
}
#KafkaListener(id = "so72871495", topics = "so72871495")
void listen(String in, #Header(KafkaHeaders.DELIVERY_ATTEMPT) int delivery) {
System.out.println(in + " " + delivery);
throw new RuntimeException("test");
}
#Bean
public NewTopic topic() {
return TopicBuilder.name("so72871495").partitions(1).replicas(1).build();
}
#Bean
ApplicationRunner runner(KafkaTemplate<String, String> template,
AbstractKafkaListenerContainerFactory<?, ?, ?> factory) {
factory.getContainerProperties().setDeliveryAttemptHeader(true);
factory.setCommonErrorHandler(new DefaultErrorHandler(new FixedBackOff(5000L, 3)));
return args -> {
template.send("so72871495", "foo");
};
}
}
foo 1
foo 2
foo 3
foo 4
If you can't figure out what's different for you, please provide an MCRE so I can see what's wrong.
EDIT
With #RetryableTopic, that header is always 1 because each delivery is the first attempt from a different topic.
Use this instead
void listen(String in, #Header(name = RetryTopicHeaders.DEFAULT_HEADER_ATTEMPTS, required = false) Integer attempts) {
Integer not int. It will be null on the first attempt and 2, 3, etc on the retries.

RetryingBatchErrorHandler - Offset commit handling

I'm using spring-kafka 2.3.8 and I'm trying to log the recovered records and commit the offsets using RetryingBatchErrorHandler. How would you commit the offset in the recoverer?
public class Customizer implements ContainerCustomizer{
private static ConsumerRecordRecoverer createConsumerRecordRecoverer() {
return (consumerRecord, e) -> {
log.info("Number of attempts exhausted. parition: " consumerRecord.partition() + ", offset: " + consumerRecord.offset());
# need to commit the offset
};
}
#Override
public void configure(AbstractMessageListenerContainer container) {
container.setBatchErrorHandler(new RetryingBatchErrorHandler(new FixedBackOff(5000L, 3L), createConsumerRecordRecoverer()));
}
The container will automatically commit the offsets if the error handler "handles" the exception, unless you set the ackAfterHandle property to false (it is true by default).
EDIT
This works as expected for me:
#SpringBootApplication
public class So69534923Application {
private static final Logger log = LoggerFactory.getLogger(So69534923Application.class);
public static void main(String[] args) {
SpringApplication.run(So69534923Application.class, args);
}
#KafkaListener(id = "so69534923", topics = "so69534923")
void listen(List<String> in) {
System.out.println(in);
throw new RuntimeException("test");
}
#Bean
RetryingBatchErrorHandler eh() {
return new RetryingBatchErrorHandler(new FixedBackOff(1000L, 2), (rec, ex) -> {
this.log.info("Retries exchausted for " + ListenerUtils.recordToString(rec, true));
});
}
#Bean
ApplicationRunner runner(ConcurrentKafkaListenerContainerFactory<?, ?> factory,
KafkaTemplate<String, String> template) {
factory.getContainerProperties().setCommitLogLevel(Level.INFO);
return args -> {
template.send("so69534923", "foo");
template.send("so69534923", "bar");
};
}
}
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.listener.type=batch
so69534923: partitions assigned: [so69534923-0]
[foo, bar]
[foo, bar]
[foo, bar]
Retries exchausted for so69534923-0#2
Retries exchausted for so69534923-0#3
Committing: {so69534923-0=OffsetAndMetadata{offset=4, leaderEpoch=null, metadata=''}}
The log was from the second run.
EDIT2
It does not work with 2.3.x; you should upgrade to a supported version.
https://spring.io/projects/spring-kafka#learn

Netty: TCP Client Server File transfer: Exception TooLongFrameException:

I am new to netty and I am trying to design a solution as below for transfer of file from Server to Client over TCP:
1. Zero copy based file transfer in case of non-ssl based transfer (Using default region of the file)
2. ChunkedFile transfer in case of SSL based transfer.
The Client - Server file transfer works in this way:
1. The client sends the location of the file to be transfered
2. Based on the location (sent by the client) the server transfers the file to the client
The file content could be anything (String /image /pdf etc) and any size.
Now, I get this TooLongFrameException: at the Server side, though the server is just decoding the path received from the client, for running the code mentioned below (Server/Client).
io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 65536: 215542494061 - discarded
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:522)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:500)
Now, My question is:
Am I wrong with the order of Encoders and Decoders and its configuration? If so, what is the correct way to configure it to receive a file from the server?
I went through few related StackOverflow posts SO Q1,SO Q2 , SO Q3, SO Q4. I got to know about the LengthFieldBasedDecoder, but I didn't get to know how to configure its corresponding LengthFieldPrepender at the Server (Encoding side). Is it even required at all?
Please point me into the right direction.
FileClient:
public final class FileClient {
static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL ? "8992" : "8023"));
static final String HOST = System.getProperty("host", "127.0.0.1");
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
} else {
sslCtx = null;
}
// Configure the client
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
}
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(64*1024, 0, 8));
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ObjectEncoder());
pipeline.addLast( new FileClientHandler()); }
});
// Start the server.
ChannelFuture f = b.connect(HOST,PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
group.shutdownGracefully();
}
}
}
FileClientHandler:
public class FileClientHandler extends ChannelInboundHandlerAdapter{
#Override
public void channelActive(ChannelHandlerContext ctx) {
String filePath = "/Users/Home/Documents/Data.pdf";
ctx.writeAndFlush(Unpooled.wrappedBuffer(filePath.getBytes()));
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("File Client Handler Read method...");
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
}
}
FileServer:
/**
* Server that accept the path of a file and echo back its content.
*/
public final class FileServer {
static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL ? "8992" : "8023"));
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
} else {
sslCtx = null;
}
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true).handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
}
pipeline.addLast("frameDecoder",new LengthFieldBasedFrameDecoder(64*1024, 0, 8));
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ObjectEncoder());
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new FileServerHandler());
}
});
// Start the server.
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
FileServerHandler:
public class FileServerHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception {
RandomAccessFile raf = null;
long length = -1;
try {
ByteBuf buff = (ByteBuf)obj;
byte[] bytes = new byte[buff.readableBytes()];
buff.readBytes(bytes);
String msg = new String(bytes);
raf = new RandomAccessFile(msg, "r");
length = raf.length();
} catch (Exception e) {
ctx.writeAndFlush("ERR: " + e.getClass().getSimpleName() + ": " + e.getMessage() + '\n');
return;
} finally {
if (length < 0 && raf != null) {
raf.close();
}
}
if (ctx.pipeline().get(SslHandler.class) == null) {
// SSL not enabled - can use zero-copy file transfer.
ctx.writeAndFlush(new DefaultFileRegion(raf.getChannel(), 0, length));
} else {
// SSL enabled - cannot use zero-copy file transfer.
ctx.writeAndFlush(new ChunkedFile(raf));
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
System.out.println("Exception server.....");
}
}
I referred Netty In Action and code samples from here
There are multiple things wrong with your server/client. First thing the SSL, for the client you don't need to initialize a SslContext for a server instead you would do something like this:
sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
On the server side of things you use a SelfSignedCertificate which in itself isn't wrong but would like to remind you that it should only be used for debugging purposes and not in production. In addition you use the ChannelOption.SO_KEEPALIVE which isn't recommended since the keepalive interval is OS-dependent. Furthermore you added Object En-/Decoder to your pipeline which in your case don't do anything useful so you can remove them.
Also you configured your LengthFieldBasedFrameDecoder wrong due to an incomplete and wrong parameter list. In the netty docs you need the version of the constructor which defines the lengthFieldLength and initialBytesToStrip. Besides the not stripping the length field you also defined the wrong lengthFieldLength which should be the same as your LengthFieldPrepender's lengthFieldLength which is 4 bytes. In conlusion you could use the constructor like this:
new LengthFieldBasedFrameDecoder(64 * 1024, 0, 4, 0, 4)
In both your handler you don't specify a Charset when en-/decoding your String which could lead to problems because if no ´Charset´ is defined the systems default will be used which could vary. You could do something like this:
//to encode the String
string.getBytes(StandardCharsets.UTF_8);
//to decode the String
new String(bytes, StandardCharsets.UTF_8);
Additionally you tried to use the DefaultFileRegion if no SslHandler was added to the pipeline which would have been fine if you didn't added the LengthFieldHandler since they would need a memory copy of the byte[] to send to added the length field. Moreover I would recommend using the ChunkedNioFile instead of the ChunkedFile because it's nonblocking which is always a good thing. You would do this like that:
new ChunkedNioFile(randomAccessFile.getChannel())
One final thing on how to decode a ChunkedFile as it's split in chunks you can simply assamble them tougether with a simple OutputStream. Here's an old file handler of mine:
public class FileTransferHandler extends SimpleChannelInboundHandler<ByteBuf> {
private final Path path;
private final int size;
private final int hash;
private OutputStream outputStream;
private int writtenBytes = 0;
private byte[] buffer = new byte[0];
protected FileTransferHandler(Path path, int size, int hash) {
this.path = path;
this.size = size;
this.hash = hash;
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
if(this.outputStream == null) {
Files.createDirectories(this.path.getParent());
if(Files.exists(this.path))
Files.delete(this.path);
this.outputStream = Files.newOutputStream(this.path, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
}
int size = byteBuf.readableBytes();
if(size > this.buffer.length)
this.buffer = new byte[size];
byteBuf.readBytes(this.buffer, 0, size);
this.outputStream.write(this.buffer, 0, size);
this.writtenBytes += size;
if(this.writtenBytes == this.size && MurMur3.hash(this.path) != this.hash) {
System.err.println("Received file has wrong hash");
return;
}
}
#Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
if(this.outputStream != null)
this.outputStream.close();
}
}

JSch/SSHJ - Connecting to SSH server on button click

I'm trying to connect to SSH Unix server on button click (code written in actionPerformed() method). I'm using JSch for connecting to SSH server. The code is written in SwingWorker class as it is a network operation.
private void testConnectionButtonActionPerformed(java.awt.event.ActionEvent evt) {
SwingWorker<Boolean, Void> sw = new SwingWorker<Boolean, Void>(){
#Override
protected Boolean doInBackground() throws Exception {
JSch jsch = new JSch();
String host = "ServerHost";
String username = "username";
String password = "password";
Session session = jsch.getSession(username, host);
session.setPassword(password);
session.setTimeout(20000);
System.out.println("Connecting to server...");
session.connect();
return true;
}
#Override
public void done(){
try {
System.out.println(get().toString());
} catch (Exception ex) {
System.out.err(ex);
}
}
};
sw.execute();
}
But after running the with correct host, username and password details, I get the below error all the time:
com.jcraft.jsch.JSchException: timeout: socket is not established
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
at java.util.concurrent.FutureTask.get(FutureTask.java:83)
at javax.swing.SwingWorker.get(SwingWorker.java:583)
But whenever I run the same code in standalone program, I mean instead for writing actionPerformed() method, If I write it in normal method and calling from main() method. It will work. when I integrate the same code with Button Click's actionPerformed() method, it will give me above exception.
Can anyone suggest what I'm doing wrong here or any modification should be made to the code.
I tried to connect to SSH Server using "SSHJ" implementation, but I get the below error:
java.net.SocketException: Connection reset
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
at java.util.concurrent.FutureTask.get(FutureTask.java:83)
at javax.swing.SwingWorker.get(SwingWorker.java:583)
Can someone help me - how to move forward?
I took your code, wrapped it in some GUI code (and converted it to non-generics to be able to compile it with the same settings as the rest of the JSch examples). It works for me. Try this, and report what exception you get (it has a bit more exception logging).
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import com.jcraft.jsch.*;
class SwingWorkerExample {
JTextField hostField;
JTextField userNameField;
JTextField passwordField;
JPanel panel;
public SwingWorkerExample() {
JPanel p = panel = new JPanel(new GridLayout(0,2));
hostField = new JTextField(20);
userNameField = new JTextField(20);
passwordField = new JPasswordField(20);
JButton testButton = new JButton("connect!");
testButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
testConnectionButtonActionPerformed(ev);
}
});
p.add(new JLabel("host:"));
p.add(hostField);
p.add(new JLabel("user:"));
p.add(userNameField);
p.add(new JLabel("password:"));
p.add(passwordField);
p.add(testButton);
}
public JPanel getPanel() {
return panel;
}
private void testConnectionButtonActionPerformed(ActionEvent evt) {
SwingWorker sw = new SwingWorker(){
protected Object doInBackground() throws Exception {
try {
JSch jsch = new JSch();
String host = hostField.getText();
String username = userNameField.getText();
String password = passwordField.getText();
Session session = jsch.getSession(username, host);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.setTimeout(20000);
System.out.println("Connecting to server...");
session.connect();
return session;
}
catch(Exception ex) {
ex.printStackTrace();
throw ex;
}
}
public void done(){
try {
System.out.println(get());
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
sw.execute();
}
public static void main(String[] egal) {
EventQueue.invokeLater(new Runnable(){public void run() {
SwingWorkerExample ex = new SwingWorkerExample();
JFrame f = new JFrame("bla");
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
f.setContentPane(ex.getPanel());
f.pack();
f.setVisible(true);
}});
}
}

Not getting value in midlet from servlet

I'm trying to send data from a midlet to a servlet and recieve back a response from the servlet but I don't get any value in response. I've tried to print it on command window and it seems to be null yet I expect only two values "ok" or "error". Please help me check the code and let me know what I should do to get the response right on the midlet. My code is below:
import javax.microedition.midlet.*;//midlet class package import
import javax.microedition.lcdui.*;//package for ui and commands
import javax.microedition.io.*;//
import java.io.*;
/**
* #author k'owino
*/
//Defining the midlet class
public class MvsMidlet extends MIDlet implements CommandListener {
private boolean midletPaused = false;//variable for paused state of midlet
//defining variables
private Display display;// Reference to Display object
private Form welForm;
private Form vCode;//vote code
private StringItem welStr;
private TextField phoneField;
private StringItem phoneError;
private Command quitCmd;
private Command contCmd;
//constructor of the midlet
public MvsMidlet() {
display = Display.getDisplay(this);//creating the display object
welForm = new Form("THE MVS");//instantiating welForm object
welStr = new StringItem("", "Welcome to the MVS, Busitema's mobile voter."
+ "Please enter the your phone number below");//instantiating welStr string item
phoneError = new StringItem("", "");//intantiating phone error string item
phoneField = new TextField("Phone number e.g 0789834141", "", 10, 3);//phone number field object
quitCmd = new Command("Quit", Command.EXIT, 0);//creating quit command object
contCmd = new Command("Continue", Command.OK, 0);//creating continue command object
welForm.append(welStr);//adding welcome string item to form
welForm.append(phoneField);//adding phone field to form
welForm.append(phoneError);//adding phone error string item to form
welForm.addCommand(contCmd);//adding continue command
welForm.addCommand(quitCmd);//adding quit command
welForm.setCommandListener(this);
display.setCurrent(welForm);
}
//start application method definition
public void startApp() {
}
//pause application method definition
public void pauseApp() {
}
//destroy application method definition
public void destroyApp(boolean unconditional) {
}
//Command action method definition
public void commandAction(Command c, Displayable d) {
if (d == welForm) {
if (c == quitCmd) {
exitMidlet();//call to exit midlet
} else {//if the command is contCmd
//place a waiting activity indicator
System.out.println("ken de man");
Thread t = new Thread() {
public void run() {
try {
//method to connect to server
sendPhone();
} catch (Exception e) {
}//end of catch
}//end of ru()
};//end of thread
t.start();//starting the thread
}//end of else
}//end of first if
}//end of command action
//defining method to exit midlet
public void exitMidlet() {
display.setCurrent(null);
destroyApp(true);
notifyDestroyed();
}//end of exitMidlet()
//defining sendPhone method
public void sendPhone() throws IOException {
System.out.println("ken de man");//check
HttpConnection http = null;//HttpConnection variable
OutputStream oStrm = null;//OutputStream variable
InputStream iStrm = null;//InputStream variable
String url = "http://localhost:8084/MvsWeb/CheckPhone";//server url
try {
http = (HttpConnection) Connector.open(url);//opening connection
System.out.println("connection made");//checking code
oStrm = http.openOutputStream();//opening output stream
http.setRequestMethod(HttpConnection.POST);//setting request type
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//setting content type
byte data[] = ("phone=" + phoneField.getString()).getBytes();
oStrm.write(data);
iStrm = http.openInputStream();//openning input stream
if (http.getResponseCode() == HttpConnection.HTTP_OK) {
int length = (int) http.getLength();
String str;
if (length != -1) {
byte servletData[] = new byte[length];
iStrm.read(servletData);
str = new String(servletData);
} else // Length not available...
{
ByteArrayOutputStream bStrm = new ByteArrayOutputStream();
int ch;
while ((ch = iStrm.read()) != -1) {
bStrm.write(ch);
}
str = new String(bStrm.toByteArray());
bStrm.close();
}
System.out.println("de man");
System.out.println(str);
if (str.equals("ok")) {
//change to vcode form
} else {
//add error message to phone_error stingItem
}
}
} catch (Exception e) {
}
}
}//end of class definition
//servlet
import java.io.*;//package for io classes
import javax.servlet.ServletException;//package for servlet exception classes
import javax.servlet.http.*;
import java.sql.*;//package for sql classes
/**
*
* #author k'owino
*/
public class CheckPhone extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
//declaring variables
PrintWriter pw;//PrintWriter object
String pnum;//phone parameter sent from client
Connection con = null;//connection variable
String dbDriver = "com.jdbc.mysql.Driver";//the database driver
String dbUrl = "jdbc:mysql://localhost/mvs_db";//the database url
String dbUser = "root";//database user
String dbPwd = "";//database password
PreparedStatement pstmt = null;//Prepared statement variable
String query = "select * from student where stud_phone = ?;";
ResultSet rs = null;//resultset variable
String dbPhone=null;//phone from database
//getting the "phone" parameter sent from client
pnum = req.getParameter("phone");//getting the "phone" parameter sent from client
System.out.println(pnum);
//setting the content type of the response
res.setContentType("text/html");
//creating a PrintWriter object
pw = res.getWriter();
pw.println("ken");
try{//trying to load the database driver and establish a connection to the database
Class.forName(dbDriver).newInstance();//loading the database driver
con = DriverManager.getConnection(dbUrl,dbUser,dbPwd);//establishing a connection to the database
System.out.println("connection established");
}
catch(Exception e){
}
//trying to query the database
try{
pstmt = con.prepareStatement(query);//preparing a statement
pstmt.setString(1, pnum);//setting the input parameter
rs = pstmt.executeQuery();//executing the query assigning to the resultset object
//extracring data from the resultset
while(rs.next()){
dbPhone = rs.getString("stud_phone");//getting the phone number from database
}//end of while
if(pnum.equals(dbPhone)){
pw.print("ok");
pw.close();
}
else{
pw.print("error");
pw.close();
}
}
catch(Exception e){
}
}
#Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}

Resources