/** @author "Frederic Bregier" */ public class WaarpSslHandler extends SslHandler { /** Internal Logger */ private static final WaarpLogger logger = WaarpLoggerFactory.getLogger(WaarpSslHandler.class); public WaarpSslHandler(SSLEngine engine) { super(engine); } public WaarpSslHandler(SSLEngine engine, boolean startTls) { super(engine, startTls); } @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { ctx.channel().config().setAutoRead(true); super.handlerAdded(ctx); logger.debug("Ssl Handler added: " + ctx.channel().toString()); } }
/** @author Frederic Bregier */ public class HttpSslHandler extends SimpleChannelInboundHandler<FullHttpRequest> { /** Internal Logger */ private static final WaarpLogger logger = WaarpLoggerFactory.getLogger(HttpSslHandler.class); /** Session Management */ private static final ConcurrentHashMap<String, R66Session> sessions = new ConcurrentHashMap<String, R66Session>(); private static final Random random = new Random(); private R66Session authentHttp = new R66Session(); private FullHttpRequest request; private boolean newSession = false; private volatile Cookie admin = null; private final StringBuilder responseContent = new StringBuilder(); private String uriRequest; private Map<String, List<String>> params; private String lang = Messages.getSlocale(); private volatile boolean forceClose = false; private volatile boolean shutdown = false; private static final String R66SESSION = "R66SESSION"; private static final String I18NEXT = "i18next"; private static enum REQUEST { Logon("Logon.html"), index("index.html"), error("error.html"), System("System.html"); private String header; /** * Constructor for a unique file * * @param uniquefile */ private REQUEST(String uniquefile) { this.header = uniquefile; } /** * Reader for a unique file * * @return the content of the unique file */ public String readFileUnique(HttpSslHandler handler) { return handler.readFileHeader(Configuration.configuration.getHttpBasePath() + this.header); } } private static enum REPLACEMENT { XXXHOSTIDXXX, XXXADMINXXX, XXXVERSIONXXX, XXXBANDWIDTHXXX, XXXXSESSIONLIMITRXXX, XXXXSESSIONLIMITWXXX, XXXXCHANNELLIMITRXXX, XXXXCHANNELLIMITWXXX, XXXXDELAYCOMMDXXX, XXXXDELAYRETRYXXX, XXXLOCALXXX, XXXNETWORKXXX, XXXERRORMESGXXX, XXXLANGXXX, XXXCURLANGENXXX, XXXCURLANGFRXXX, XXXCURSYSLANGENXXX, XXXCURSYSLANGFRXXX; } static final int LIMITROW = 48; // better if it can // be divided by 4 private String readFileHeader(String filename) { String value; try { value = WaarpStringUtils.readFileException(filename); } catch (InvalidArgumentException e) { logger.error("Error while trying to open: " + filename, e); return ""; } catch (FileTransferException e) { logger.error("Error while trying to read: " + filename, e); return ""; } StringBuilder builder = new StringBuilder(value); WaarpStringUtils.replace( builder, REPLACEMENT.XXXLOCALXXX.toString(), Integer.toString(Configuration.configuration.getLocalTransaction().getNumberLocalChannel()) + " " + Thread.activeCount()); WaarpStringUtils.replace( builder, REPLACEMENT.XXXNETWORKXXX.toString(), Integer.toString( Configuration.configuration.getLocalTransaction().getNumberLocalChannel())); WaarpStringUtils.replace( builder, REPLACEMENT.XXXHOSTIDXXX.toString(), Configuration.configuration.getHOST_ID()); if (authentHttp.isAuthenticated()) { WaarpStringUtils.replace( builder, REPLACEMENT.XXXADMINXXX.toString(), Messages.getString("HttpSslHandler.1")); // $NON-NLS-1$ } else { WaarpStringUtils.replace( builder, REPLACEMENT.XXXADMINXXX.toString(), Messages.getString("HttpSslHandler.0")); // $NON-NLS-1$ } TrafficCounter trafficCounter = Configuration.configuration.getGlobalTrafficShapingHandler().trafficCounter(); WaarpStringUtils.replace( builder, REPLACEMENT.XXXBANDWIDTHXXX.toString(), Messages.getString("HttpSslHandler.IN") + (trafficCounter.lastReadThroughput() >> 20) + //$NON-NLS-1$ Messages.getString("HttpSslHandler.MOPS") + //$NON-NLS-1$ Messages.getString("HttpSslHandler.OUT") + //$NON-NLS-1$ (trafficCounter.lastWriteThroughput() >> 20) + Messages.getString("HttpSslHandler.MOPS")); // $NON-NLS-1$ WaarpStringUtils.replace(builder, REPLACEMENT.XXXLANGXXX.toString(), lang); return builder.toString(); } private String getTrimValue(String varname) { String value = params.get(varname).get(0).trim(); if (value.isEmpty()) { value = null; } return value; } private String index() { String index = REQUEST.index.readFileUnique(this); StringBuilder builder = new StringBuilder(index); WaarpStringUtils.replaceAll( builder, REPLACEMENT.XXXHOSTIDXXX.toString(), Configuration.configuration.getHOST_ID()); WaarpStringUtils.replaceAll( builder, REPLACEMENT.XXXADMINXXX.toString(), "Administrator Connected"); WaarpStringUtils.replace(builder, REPLACEMENT.XXXVERSIONXXX.toString(), Version.ID); return builder.toString(); } private String error(String mesg) { String index = REQUEST.error.readFileUnique(this); return index.replaceAll(REPLACEMENT.XXXERRORMESGXXX.toString(), mesg); } private String Logon() { return REQUEST.Logon.readFileUnique(this); } /** * Applied current lang to system page * * @param builder */ private void langHandle(StringBuilder builder) { // i18n: add here any new languages WaarpStringUtils.replace( builder, REPLACEMENT.XXXCURLANGENXXX.name(), lang.equalsIgnoreCase("en") ? "checked" : ""); WaarpStringUtils.replace( builder, REPLACEMENT.XXXCURLANGFRXXX.name(), lang.equalsIgnoreCase("fr") ? "checked" : ""); WaarpStringUtils.replace( builder, REPLACEMENT.XXXCURSYSLANGENXXX.name(), Messages.getSlocale().equalsIgnoreCase("en") ? "checked" : ""); WaarpStringUtils.replace( builder, REPLACEMENT.XXXCURSYSLANGFRXXX.name(), Messages.getSlocale().equalsIgnoreCase("fr") ? "checked" : ""); } /** @param builder */ private void replaceStringSystem(StringBuilder builder) { WaarpStringUtils.replace( builder, REPLACEMENT.XXXXSESSIONLIMITWXXX.toString(), Long.toString(Configuration.configuration.getServerChannelWriteLimit())); WaarpStringUtils.replace( builder, REPLACEMENT.XXXXSESSIONLIMITRXXX.toString(), Long.toString(Configuration.configuration.getServerChannelReadLimit())); WaarpStringUtils.replace( builder, REPLACEMENT.XXXXDELAYCOMMDXXX.toString(), Long.toString(Configuration.configuration.getDelayCommander())); WaarpStringUtils.replace( builder, REPLACEMENT.XXXXDELAYRETRYXXX.toString(), Long.toString(Configuration.configuration.getDelayRetry())); WaarpStringUtils.replace( builder, REPLACEMENT.XXXXCHANNELLIMITWXXX.toString(), Long.toString(Configuration.configuration.getServerGlobalWriteLimit())); WaarpStringUtils.replace( builder, REPLACEMENT.XXXXCHANNELLIMITRXXX.toString(), Long.toString(Configuration.configuration.getServerGlobalReadLimit())); WaarpStringUtils.replace( builder, "XXXBLOCKXXX", Configuration.configuration.isShutdown() ? "checked" : ""); switch (WaarpLoggerFactory.getLogLevel()) { case DEBUG: WaarpStringUtils.replace(builder, "XXXLEVEL1XXX", "checked"); WaarpStringUtils.replace(builder, "XXXLEVEL2XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL3XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL4XXX", ""); break; case INFO: WaarpStringUtils.replace(builder, "XXXLEVEL1XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL2XXX", "checked"); WaarpStringUtils.replace(builder, "XXXLEVEL3XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL4XXX", ""); break; case WARN: WaarpStringUtils.replace(builder, "XXXLEVEL1XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL2XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL3XXX", "checked"); WaarpStringUtils.replace(builder, "XXXLEVEL4XXX", ""); break; case ERROR: WaarpStringUtils.replace(builder, "XXXLEVEL1XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL2XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL3XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL4XXX", "checked"); break; default: WaarpStringUtils.replace(builder, "XXXLEVEL1XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL2XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL3XXX", ""); WaarpStringUtils.replace(builder, "XXXLEVEL4XXX", ""); break; } } private String System() { getParams(); if (params == null) { String system = REQUEST.System.readFileUnique(this); StringBuilder builder = new StringBuilder(system); replaceStringSystem(builder); langHandle(builder); return builder.toString(); } String extraInformation = null; if (params.containsKey("ACTION")) { List<String> action = params.get("ACTION"); for (String act : action) { if (act.equalsIgnoreCase("Language")) { lang = getTrimValue("change"); String sys = getTrimValue("changesys"); Messages.init(new Locale(sys)); extraInformation = Messages.getString("HttpSslHandler.LangIs") + "Web: " + lang + " OpenR66: " + Messages.getSlocale(); // $NON-NLS-1$ } else if (act.equalsIgnoreCase("Level")) { String loglevel = getTrimValue("loglevel"); WaarpLogLevel level = WaarpLogLevel.WARN; if (loglevel.equalsIgnoreCase("debug")) { level = WaarpLogLevel.DEBUG; } else if (loglevel.equalsIgnoreCase("info")) { level = WaarpLogLevel.INFO; } else if (loglevel.equalsIgnoreCase("warn")) { level = WaarpLogLevel.WARN; } else if (loglevel.equalsIgnoreCase("error")) { level = WaarpLogLevel.ERROR; } WaarpLoggerFactory.setLogLevel(level); extraInformation = Messages.getString("HttpSslHandler.LangIs") + level.name(); // $NON-NLS-1$ } else if (act.equalsIgnoreCase("Disconnect")) { String logon = Logon(); logon = logon.replaceAll( REPLACEMENT.XXXERRORMESGXXX.toString(), Messages.getString("HttpSslHandler.DisActive")); newSession = true; clearSession(); forceClose = true; return logon; } else if (act.equalsIgnoreCase("Shutdown")) { String error; if (Configuration.configuration.getShutdownConfiguration().serviceFuture != null) { error = error(Messages.getString("HttpSslHandler.38")); // $NON-NLS-1$ } else { error = error(Messages.getString("HttpSslHandler.37")); // $NON-NLS-1$ } R66ShutdownHook.setRestart(false); newSession = true; clearSession(); forceClose = true; shutdown = true; return error; } else if (act.equalsIgnoreCase("Restart")) { String error; if (Configuration.configuration.getShutdownConfiguration().serviceFuture != null) { error = error(Messages.getString("HttpSslHandler.38")); // $NON-NLS-1$ } else { error = error( Messages.getString("HttpSslHandler.39") + (Configuration.configuration.getTIMEOUTCON() * 2 / 1000) + Messages.getString("HttpSslHandler.40")); // $NON-NLS-1$ //$NON-NLS-2$ } error = error.replace( "XXXRELOADHTTPXXX", "HTTP-EQUIV=\"refresh\" CONTENT=\"" + (Configuration.configuration.getTIMEOUTCON() * 2 / 1000) + "\""); R66ShutdownHook.setRestart(true); newSession = true; clearSession(); forceClose = true; shutdown = true; return error; } else if (act.equalsIgnoreCase("Validate")) { String bsessionr = getTrimValue("BSESSR"); long lsessionr = Configuration.configuration.getServerChannelReadLimit(); long lglobalr; long lsessionw; long lglobalw; try { if (bsessionr != null) { lsessionr = (Long.parseLong(bsessionr) / 10) * 10; } String bglobalr = getTrimValue("BGLOBR"); lglobalr = Configuration.configuration.getServerGlobalReadLimit(); if (bglobalr != null) { lglobalr = (Long.parseLong(bglobalr) / 10) * 10; } String bsessionw = getTrimValue("BSESSW"); lsessionw = Configuration.configuration.getServerChannelWriteLimit(); if (bsessionw != null) { lsessionw = (Long.parseLong(bsessionw) / 10) * 10; } String bglobalw = getTrimValue("BGLOBW"); lglobalw = Configuration.configuration.getServerGlobalWriteLimit(); if (bglobalw != null) { lglobalw = (Long.parseLong(bglobalw) / 10) * 10; } Configuration.configuration.changeNetworkLimit( lglobalw, lglobalr, lsessionw, lsessionr, Configuration.configuration.getDelayLimit()); String dcomm = getTrimValue("DCOM"); if (dcomm != null) { Configuration.configuration.setDelayCommander(Long.parseLong(dcomm)); if (Configuration.configuration.getDelayCommander() <= 100) { Configuration.configuration.setDelayCommander(100); } Configuration.configuration.reloadCommanderDelay(); } String dret = getTrimValue("DRET"); if (dret != null) { Configuration.configuration.setDelayRetry(Long.parseLong(dret)); if (Configuration.configuration.getDelayRetry() <= 1000) { Configuration.configuration.setDelayRetry(1000); } } extraInformation = Messages.getString("HttpSslHandler.41"); // $NON-NLS-1$ } catch (NumberFormatException e) { extraInformation = Messages.getString("HttpSslHandler.42"); // $NON-NLS-1$ } } } } String system = REQUEST.System.readFileUnique(this); StringBuilder builder = new StringBuilder(system); replaceStringSystem(builder); langHandle(builder); if (extraInformation != null) { builder.append(extraInformation); } return builder.toString(); } private void getParams() { if (request.method() == HttpMethod.GET) { params = null; } else if (request.method() == HttpMethod.POST) { ByteBuf content = request.content(); if (content.isReadable()) { String param = content.toString(WaarpStringUtils.UTF8); QueryStringDecoder queryStringDecoder2 = new QueryStringDecoder("/?" + param); params = queryStringDecoder2.parameters(); } else { params = null; } } } private void clearSession() { if (admin != null) { R66Session lsession = sessions.remove(admin.value()); admin = null; if (lsession != null) { lsession.setStatus(75); lsession.clear(); } } } private void checkAuthent(ChannelHandlerContext ctx) { newSession = true; if (request.method() == HttpMethod.GET) { String logon = Logon(); logon = logon.replaceAll(REPLACEMENT.XXXERRORMESGXXX.toString(), ""); responseContent.append(logon); clearSession(); writeResponse(ctx); return; } else if (request.method() == HttpMethod.POST) { getParams(); if (params == null) { String logon = Logon(); logon = logon.replaceAll( REPLACEMENT.XXXERRORMESGXXX.toString(), Messages.getString("HttpSslHandler.EmptyLogin")); responseContent.append(logon); clearSession(); writeResponse(ctx); return; } } boolean getMenu = false; if (params.containsKey("Logon")) { String name = null, password = null; List<String> values = null; if (!params.isEmpty()) { // get values if (params.containsKey("name")) { values = params.get("name"); if (values != null) { name = values.get(0); if (name == null || name.isEmpty()) { getMenu = true; } } } else { getMenu = true; } // search the nb param if ((!getMenu) && params.containsKey("passwd")) { values = params.get("passwd"); if (values != null) { password = values.get(0); if (password == null || password.isEmpty()) { getMenu = true; } else { getMenu = false; } } else { getMenu = true; } } else { getMenu = true; } } else { getMenu = true; } if (!getMenu) { logger.debug( "Name=" + name + " vs " + name.equals(Configuration.configuration.getADMINNAME()) + " Passwd vs " + Arrays.equals( password.getBytes(WaarpStringUtils.UTF8), Configuration.configuration.getSERVERADMINKEY())); if (name.equals(Configuration.configuration.getADMINNAME()) && Arrays.equals( password.getBytes(WaarpStringUtils.UTF8), Configuration.configuration.getSERVERADMINKEY())) { authentHttp .getAuth() .specialNoSessionAuth(true, Configuration.configuration.getHOST_ID()); authentHttp.setStatus(70); } else { getMenu = true; } if (!authentHttp.isAuthenticated()) { authentHttp.setStatus(71); logger.debug("Still not authenticated: {}", authentHttp); getMenu = true; } } } else { getMenu = true; } if (getMenu) { String logon = Logon(); logon = logon.replaceAll( REPLACEMENT.XXXERRORMESGXXX.toString(), Messages.getString("HttpSslHandler.BadLogin")); responseContent.append(logon); clearSession(); writeResponse(ctx); } else { String index = index(); responseContent.append(index); clearSession(); admin = new DefaultCookie( R66SESSION + Configuration.configuration.getHOST_ID(), Configuration.configuration.getHOST_ID() + Long.toHexString(random.nextLong())); sessions.put(admin.value(), this.authentHttp); authentHttp.setStatus(72); logger.debug("CreateSession: " + uriRequest + ":{}", admin); writeResponse(ctx); } } @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception { FullHttpRequest request = this.request = msg; QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri()); uriRequest = queryStringDecoder.path(); logger.debug("Msg: " + uriRequest); if (uriRequest.contains("gre/") || uriRequest.contains("img/") || uriRequest.contains("res/") || uriRequest.contains("favicon.ico")) { HttpWriteCacheEnable.writeFile( request, ctx, Configuration.configuration.getHttpBasePath() + uriRequest, R66SESSION + Configuration.configuration.getHOST_ID()); ctx.flush(); return; } checkSession(ctx.channel()); if (!authentHttp.isAuthenticated()) { logger.debug("Not Authent: " + uriRequest + ":{}", authentHttp); checkAuthent(ctx); return; } String find = uriRequest; if (uriRequest.charAt(0) == '/') { find = uriRequest.substring(1); } find = find.substring(0, find.indexOf(".")); REQUEST req = REQUEST.index; try { req = REQUEST.valueOf(find); } catch (IllegalArgumentException e1) { req = REQUEST.index; logger.debug("NotFound: " + find + ":" + uriRequest); } switch (req) { case index: responseContent.append(index()); break; case Logon: responseContent.append(index()); break; case System: responseContent.append(System()); break; default: responseContent.append(index()); break; } writeResponse(ctx); } private void checkSession(Channel channel) { String cookieString = request.headers().get(HttpHeaderNames.COOKIE); if (cookieString != null) { Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString); if (!cookies.isEmpty()) { for (Cookie elt : cookies) { if (elt.name().equalsIgnoreCase(R66SESSION + Configuration.configuration.getHOST_ID())) { logger.debug("Found session: " + elt); admin = elt; R66Session session = sessions.get(admin.value()); if (session != null) { authentHttp = session; authentHttp.setStatus(73); } else { admin = null; continue; } } else if (elt.name().equalsIgnoreCase(I18NEXT)) { logger.debug("Found i18next: " + elt); lang = elt.value(); } } } } if (admin == null) { logger.debug("NoSession: " + uriRequest + ":{}", admin); } } private void handleCookies(HttpResponse response) { String cookieString = request.headers().get(HttpHeaderNames.COOKIE); boolean i18nextFound = false; if (cookieString != null) { Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString); if (!cookies.isEmpty()) { // Reset the sessions if necessary. boolean findSession = false; for (Cookie cookie : cookies) { if (cookie .name() .equalsIgnoreCase(R66SESSION + Configuration.configuration.getHOST_ID())) { if (newSession) { findSession = false; } else { findSession = true; response .headers() .add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)); } } else if (cookie.name().equalsIgnoreCase(I18NEXT)) { i18nextFound = true; cookie.setValue(lang); response .headers() .add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)); } else { response .headers() .add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)); } } if (!i18nextFound) { Cookie cookie = new DefaultCookie(I18NEXT, lang); response .headers() .add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)); } newSession = false; if (!findSession) { if (admin != null) { response .headers() .add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(admin)); logger.debug("AddSession: " + uriRequest + ":{}", admin); } } } } else { Cookie cookie = new DefaultCookie(I18NEXT, lang); response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(cookie)); if (admin != null) { logger.debug("AddSession: " + uriRequest + ":{}", admin); response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.LAX.encode(admin)); } } } /** Write the response */ private void writeResponse(ChannelHandlerContext ctx) { // Convert the response content to a ByteBuf. ByteBuf buf = Unpooled.copiedBuffer(responseContent.toString(), WaarpStringUtils.UTF8); responseContent.setLength(0); // Decide whether to close the connection or not. boolean keepAlive = HttpUtil.isKeepAlive(request); boolean close = HttpHeaderValues.CLOSE.contentEqualsIgnoreCase( request.headers().get(HttpHeaderNames.CONNECTION)) || (!keepAlive) || forceClose; // Build the response object. FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf); response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html"); if (keepAlive) { response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } if (!close) { // There's no need to add 'Content-Length' header // if this is the last response. response.headers().set(HttpHeaderNames.CONTENT_LENGTH, String.valueOf(buf.readableBytes())); } handleCookies(response); // Write the response. ChannelFuture future = ctx.writeAndFlush(response); // Close the connection after the write operation is done if necessary. if (close) { future.addListener(WaarpSslUtility.SSLCLOSE); } if (shutdown) { ChannelUtils.startShutdown(); } } /** * Send an error and close * * @param ctx * @param status */ private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { responseContent.setLength(0); responseContent.append(error(status.toString())); FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(responseContent.toString(), WaarpStringUtils.UTF8)); response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html"); responseContent.setLength(0); clearSession(); // Close the connection as soon as the error message is sent. ctx.writeAndFlush(response).addListener(WaarpSslUtility.SSLCLOSE); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { OpenR66Exception exception = OpenR66ExceptionTrappedFactory.getExceptionFromTrappedException(ctx.channel(), cause); if (exception != null) { if (!(exception instanceof OpenR66ProtocolBusinessNoWriteBackException)) { if (cause instanceof IOException) { // Nothing to do return; } logger.warn("Exception in HttpSslHandler {}", exception.getMessage()); } if (ctx.channel().isActive()) { sendError(ctx, HttpResponseStatus.BAD_REQUEST); } } else { // Nothing to do return; } } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); Configuration.configuration.getHttpChannelGroup().add(channel); super.channelActive(ctx); } }
/** * This class launch and control the Commander and enable TaskRunner job submissions * * @author Frederic Bregier */ public class InternalRunner { /** Internal Logger */ private static final WaarpLogger logger = WaarpLoggerFactory.getLogger(InternalRunner.class); private final ScheduledExecutorService scheduledExecutorService; private ScheduledFuture<?> scheduledFuture; private CommanderInterface commander = null; private volatile boolean isRunning = true; private final ThreadPoolExecutor threadPoolExecutor; private final NetworkTransaction networkTransaction; /** * Create the structure to enable submission by database * * @throws WaarpDatabaseNoConnectionException * @throws WaarpDatabaseSqlException */ public InternalRunner() throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException { if (DbConstant.admin.isActive()) { commander = new Commander(this, true); } else { commander = new CommanderNoDb(this, true); } scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new WaarpThreadFactory("InternalRunner")); isRunning = true; BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(10); threadPoolExecutor = new ThreadPoolExecutor( 10, Configuration.configuration.getRUNNER_THREAD(), 1000, TimeUnit.MILLISECONDS, workQueue); scheduledFuture = scheduledExecutorService.scheduleWithFixedDelay( commander, Configuration.configuration.getDelayCommander(), Configuration.configuration.getDelayCommander(), TimeUnit.MILLISECONDS); networkTransaction = new NetworkTransaction(); } public NetworkTransaction getNetworkTransaction() { return networkTransaction; } /** * Submit a task * * @param taskRunner */ public void submitTaskRunner(DbTaskRunner taskRunner) { if (isRunning || !Configuration.configuration.isShutdown()) { if (threadPoolExecutor.getActiveCount() > Configuration.configuration.getRUNNER_THREAD()) { // too many current active threads taskRunner.changeUpdatedInfo(UpdatedInfo.TOSUBMIT); taskRunner.forceSaveStatus(); return; } logger.debug("Will run {}", taskRunner); ClientRunner runner = new ClientRunner(networkTransaction, taskRunner, null); if (taskRunner.isSendThrough() && (taskRunner.isRescheduledTransfer() || taskRunner.isPreTaskStarting())) { runner.setSendThroughMode(); taskRunner.checkThroughMode(); } runner.setDaemon(true); // create the client, connect and run threadPoolExecutor.execute(runner); runner = null; } } /** First step while shutting down the service */ public void prepareStopInternalRunner() { isRunning = false; scheduledFuture.cancel(false); scheduledExecutorService.shutdown(); threadPoolExecutor.shutdown(); } /** * This should be called when the server is shutting down, after stopping active requests if * possible. */ public void stopInternalRunner() { isRunning = false; logger.info("Stopping Commander and Runner Tasks"); scheduledFuture.cancel(false); scheduledExecutorService.shutdownNow(); threadPoolExecutor.shutdownNow(); networkTransaction.closeAll(false); } public int nbInternalRunner() { return threadPoolExecutor.getActiveCount(); } public void reloadInternalRunner() throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException { scheduledFuture.cancel(false); if (commander != null) { commander.finalize(); } if (DbConstant.admin.isActive()) { commander = new Commander(this); } else { commander = new CommanderNoDb(this); } scheduledFuture = scheduledExecutorService.scheduleWithFixedDelay( commander, Configuration.configuration.getDelayCommander(), Configuration.configuration.getDelayCommander(), TimeUnit.MILLISECONDS); } }