Skip to content

Commit

Permalink
Added QRest module
Browse files Browse the repository at this point in the history
  • Loading branch information
ar committed May 2, 2018
1 parent eaf0618 commit 04ee96f
Show file tree
Hide file tree
Showing 19 changed files with 926 additions and 1 deletion.
19 changes: 19 additions & 0 deletions modules/qrest/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
description = 'jPOS-EE :: QRest'

dependencies {
compile libraries.jpos
compile libraries.jacksonDatabind
compile libraries.nettyHandler
compile libraries.nettyCodecHttp
testCompile libraries.junit
testCompile libraries.restAssured

}

apply from: "${rootProject.projectDir}/jpos-app.gradle"

test {
dependsOn('installApp')
workingDir = "build/install/qrest"
}

5 changes: 5 additions & 0 deletions modules/qrest/src/dist/bin/bsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
cd `dirname $0`/.. || exit 1
CLASSPATH=classes:$CLASSPATH
CLASSPATH=`echo @jarname@ lib/*.jar | tr ' ' ':'`:$CLASSPATH
exec java -cp $CLASSPATH bsh.Interpreter $*
22 changes: 22 additions & 0 deletions modules/qrest/src/dist/bin/q2
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh

cd `dirname $0`/.. || exit 1
rm -f deploy/shutdown.xml
exec java -server \
-Xmx1G \
-Xloggc:log/gc.log \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-XX:+UseGCLogFileRotation \
-XX:NumberOfGCLogFiles=5 \
-XX:GCLogFileSize=2M \
-XX:NumberOfGCLogFiles=5 \
-Djava.net.preferIPv4Stack=true \
-Dcom.sun.management.jmxremote \
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses \
-XX:+UseConcMarkSweepGC \
-XX:+AggressiveOpts \
-XX:+ParallelRefProcEnabled \
-XX:+TieredCompilation \
-jar jposee-@jarname@ --pid-file='jpos.pid' "$@"

5 changes: 5 additions & 0 deletions modules/qrest/src/dist/bin/start
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

cd `dirname $0`
echo Starting Q2
nohup ./q2 > /dev/null 2>&1 &
4 changes: 4 additions & 0 deletions modules/qrest/src/dist/bin/stop
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh

echo Stopping Q2
echo '<shutdown/>' > `dirname $0`/../deploy/shutdown.xml
16 changes: 16 additions & 0 deletions modules/qrest/src/dist/deploy/00_logger.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>

<logger name="Q2" class="org.jpos.q2.qbean.LoggerAdaptor">
<property name="redirect" value="stdout, stderr" />
<log-listener class="org.jpos.util.SimpleLogListener" />

<!--
<log-listener class="org.jpos.util.RotateLogListener">
<property name="file" value="log/q2.log" />
<property name="window" value="86400" />
<property name="copies" value="1000" />
<property name="maxsize" value="100000000" />
</log-listener>
-->
</logger>

16 changes: 16 additions & 0 deletions modules/qrest/src/dist/deploy/30_qrest_txnmgr.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<txnmgr class="org.jpos.transaction.TransactionManager" logger="Q2" realm='qrest-txnmgr'>
<property name="queue" value="TXNMGR"/>
<property name="sessions" value="2"/>
<property name="max-sessions" value="128"/>
<property name="debug" value="true"/>

<participant class="org.jpos.qrest.participant.Router">
<route path="/q2**" method="GET" name="q2"/>
</participant>

<group name="q2">
<participant class="org.jpos.qrest.participant.Q2Info" />
</group>
<participant class="org.jpos.qrest.SendResponse" logger="Q2"/>
</txnmgr>

5 changes: 5 additions & 0 deletions modules/qrest/src/dist/deploy/50_qrest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<qrest class='org.jpos.qrest.RestServer' logger='Q2'>
<property name='port' value='8081' />
<property name='queue' value='TXNMGR' />
</qrest>

7 changes: 7 additions & 0 deletions modules/qrest/src/dist/deploy/99_sysmon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<sysmon logger="Q2">
<!-- Environment: '@target@' -->
<attr name="sleepTime" type="java.lang.Long">3600000</attr>
<attr name="detailRequired" type="java.lang.Boolean">true</attr>
<property name="metrics-dir" value="log" />
</sysmon>

27 changes: 27 additions & 0 deletions modules/qrest/src/main/java/org/jpos/qrest/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2018 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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/>.
*/

package org.jpos.qrest;

public enum Constants {
SESSION,
REQUEST,
QUERYPARAMS,
PATHPARAMS,
RESPONSE,
}
39 changes: 39 additions & 0 deletions modules/qrest/src/main/java/org/jpos/qrest/Response.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2018 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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/>.
*/

package org.jpos.qrest;

import io.netty.handler.codec.http.HttpResponseStatus;

public class Response {
private HttpResponseStatus status;
private Object body;
public Response(HttpResponseStatus status, Object body) {
this.status = status;
this.body = body;
}

public HttpResponseStatus status() {
return status;
}

public Object body() {
return body;
}
}

116 changes: 116 additions & 0 deletions modules/qrest/src/main/java/org/jpos/qrest/RestServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2018 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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/>.
*/

package org.jpos.qrest;

import java.net.BindException;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.timeout.IdleStateHandler;
import org.jpos.iso.ISOUtil;
import org.jpos.q2.QBeanSupport;
import org.jpos.space.Space;
import org.jpos.space.SpaceFactory;
import org.jpos.transaction.Context;
import org.jpos.util.NameRegistrar;

public class RestServer extends QBeanSupport implements Runnable {
private ServerBootstrap serverBootstrap;
private ChannelFuture cf;
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
private Space sp;
private Thread initializerThread;

@Override
protected void initService() {
sp = SpaceFactory.getSpace();
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
serverBootstrap = new ServerBootstrap();
serverBootstrap
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
int timeout = cfg.getInt("timeout", 300);
ch.pipeline().addLast(new IdleStateHandler(timeout,timeout,timeout));
ch.pipeline().addLast(new HttpServerCodec()) ;
ch.pipeline().addLast(new HttpObjectAggregator(512*1024));
ch.pipeline().addLast(new RestSession(RestServer.this));
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.SO_KEEPALIVE, true);
}

@Override
protected void startService () throws Exception {
initializerThread = new Thread(this, getName());
initializerThread.start();
}

@Override
protected void stopService() {
if (initializerThread != null) {
initializerThread.interrupt();
NameRegistrar.unregister(getName());
cf.channel().close();
}
}

@Override
protected void destroyService() {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}

@Override
public void run() {
int port = cfg.getInt("port", 8080);
while (running()) {
try {
cf = serverBootstrap.bind(port).sync();
if (cf.isSuccess()) {
getLog().info (getName() + " ready - port " + port);
NameRegistrar.register(getName(), this);
break;
}
} catch (Throwable t) {
if (t instanceof BindException) {
getLog().warn (t.getMessage() + " port (" + port + ") --- retrying");
} else {
getLog().warn(t);
break;
}
ISOUtil.sleep(5000L);
}
}
}

public void queue (Context ctx) {
sp.out(cfg.get("queue"), ctx, 60000L);
}
}
89 changes: 89 additions & 0 deletions modules/qrest/src/main/java/org/jpos/qrest/RestSession.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2018 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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/>.
*/

package org.jpos.qrest;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.jpos.transaction.Context;

import static io.netty.buffer.Unpooled.copiedBuffer;

public class RestSession extends ChannelInboundHandlerAdapter {
private RestServer server;

RestSession(RestServer server) {
this.server = server;
}

@Override
public void channelRead(ChannelHandlerContext ch, Object msg) throws Exception {
Context ctx = new Context();
if (msg instanceof FullHttpRequest) {
final FullHttpRequest request = (FullHttpRequest) msg;
ctx.put(Constants.SESSION, ch);
ctx.put(Constants.REQUEST, request);
server.queue(ctx);
} else {
super.channelRead(ch, msg);
}
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
server.getLog().warn(cause);
ctx.writeAndFlush(new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.INTERNAL_SERVER_ERROR,
copiedBuffer(cause.getMessage().getBytes())
));
ctx.close();
}

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
server.getLog().info("accepted: " + ctx.channel());
}

@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
server.getLog().info("closed: " + ctx.channel());
}

@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleState e = ((IdleStateEvent) evt).state();
if (e == IdleState.READER_IDLE) {
server.getLog().info("timeout " + ctx.channel());
ctx.fireChannelInactive();
ctx.close();
}
}
}
}
Loading

0 comments on commit 04ee96f

Please sign in to comment.