Working on the async lotro server.
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import com.gempukku.lotro.SubscriptionConflictException;
|
||||
import com.gempukku.lotro.SubscriptionExpiredException;
|
||||
import com.gempukku.lotro.collection.CollectionsManager;
|
||||
import com.gempukku.lotro.db.vo.League;
|
||||
import com.gempukku.lotro.game.LotroFormat;
|
||||
import com.gempukku.lotro.game.Player;
|
||||
import com.gempukku.lotro.game.formats.LotroFormatLibrary;
|
||||
import com.gempukku.lotro.hall.HallChannelVisitor;
|
||||
import com.gempukku.lotro.hall.HallServer;
|
||||
import com.gempukku.lotro.league.LeagueSerieData;
|
||||
import com.gempukku.lotro.league.LeagueService;
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.handler.codec.http.HttpMethod;
|
||||
import org.jboss.netty.handler.codec.http.HttpRequest;
|
||||
import org.jboss.netty.handler.codec.http.QueryStringDecoder;
|
||||
import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public class HallRequestHandler extends LotroServerRequestHandler implements UriRequestHandler {
|
||||
private CollectionsManager _collectionManager;
|
||||
private LotroFormatLibrary _formatLibrary;
|
||||
private HallServer _hallServer;
|
||||
private LeagueService _leagueService;
|
||||
private long _longPollingLength = 5000;
|
||||
private long _longPollingInterval = 200;
|
||||
|
||||
public HallRequestHandler(Map<Type, Object> context) {
|
||||
super(context);
|
||||
_collectionManager = extractObject(context, CollectionsManager.class);
|
||||
_formatLibrary = extractObject(context, LotroFormatLibrary.class);
|
||||
_hallServer = extractObject(context, HallServer.class);
|
||||
_leagueService = extractObject(context, LeagueService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(String uri, HttpRequest request, Map<Type, Object> context, ResponseWriter responseWriter, MessageEvent e) {
|
||||
if (uri.equals("") && request.getMethod() == HttpMethod.GET) {
|
||||
getHall(request, responseWriter);
|
||||
} else if (uri.equals("/update") && request.getMethod() == HttpMethod.POST) {
|
||||
updateHall(request, responseWriter);
|
||||
} else {
|
||||
responseWriter.writeError(404);
|
||||
}
|
||||
}
|
||||
|
||||
private void getHall(HttpRequest request, ResponseWriter responseWriter) {
|
||||
QueryStringDecoder queryDecoder = new QueryStringDecoder(request.getUri());
|
||||
|
||||
String participantId = getQueryParameterSafely(queryDecoder, "participantId");
|
||||
|
||||
try {
|
||||
Player resourceOwner = getResourceOwnerSafely(request, participantId);
|
||||
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
|
||||
Document doc = documentBuilder.newDocument();
|
||||
|
||||
Element hall = doc.createElement("hall");
|
||||
hall.setAttribute("currency", String.valueOf(_collectionManager.getPlayerCollection(resourceOwner, "permanent").getCurrency()));
|
||||
|
||||
_hallServer.signupUserForHall(resourceOwner, new SerializeHallInfoVisitor(doc, hall));
|
||||
for (Map.Entry<String, LotroFormat> format : _formatLibrary.getHallFormats().entrySet()) {
|
||||
Element formatElem = doc.createElement("format");
|
||||
formatElem.setAttribute("type", format.getKey());
|
||||
formatElem.appendChild(doc.createTextNode(format.getValue().getName()));
|
||||
hall.appendChild(formatElem);
|
||||
}
|
||||
for (League league : _leagueService.getActiveLeagues()) {
|
||||
final LeagueSerieData currentLeagueSerie = _leagueService.getCurrentLeagueSerie(league);
|
||||
if (currentLeagueSerie != null && _leagueService.isPlayerInLeague(league, resourceOwner)) {
|
||||
Element formatElem = doc.createElement("format");
|
||||
formatElem.setAttribute("type", league.getType());
|
||||
formatElem.appendChild(doc.createTextNode(league.getName()));
|
||||
hall.appendChild(formatElem);
|
||||
}
|
||||
}
|
||||
|
||||
doc.appendChild(hall);
|
||||
|
||||
responseWriter.writeResponse(doc);
|
||||
} catch (HttpProcessingException exp) {
|
||||
responseWriter.writeError(exp.getStatus());
|
||||
} catch (Exception exp) {
|
||||
responseWriter.writeError(500);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHall(HttpRequest request, ResponseWriter responseWriter) {
|
||||
try {
|
||||
HttpPostRequestDecoder postDecoder = new HttpPostRequestDecoder(request);
|
||||
String participantId = getFormParameterSafely(postDecoder, "participantId");
|
||||
int channelNumber = Integer.parseInt(getFormParameterSafely(postDecoder, "channelNumber"));
|
||||
|
||||
Player resourceOwner = getResourceOwnerSafely(request, participantId);
|
||||
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
|
||||
Document doc = documentBuilder.newDocument();
|
||||
|
||||
Element hall = doc.createElement("hall");
|
||||
|
||||
try {
|
||||
// Use long polling
|
||||
long start = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() < start + _longPollingLength && !_hallServer.hasChanges(resourceOwner, channelNumber)) {
|
||||
try {
|
||||
Thread.sleep(_longPollingInterval);
|
||||
} catch (InterruptedException exp) {
|
||||
|
||||
}
|
||||
}
|
||||
_hallServer.processHall(resourceOwner, channelNumber, new SerializeHallInfoVisitor(doc, hall));
|
||||
} catch (SubscriptionExpiredException exp) {
|
||||
throw new WebApplicationException(Response.Status.GONE);
|
||||
} catch (SubscriptionConflictException exp) {
|
||||
throw new WebApplicationException(Response.Status.CONFLICT);
|
||||
}
|
||||
hall.setAttribute("currency", String.valueOf(_collectionManager.getPlayerCollection(resourceOwner, "permanent").getCurrency()));
|
||||
|
||||
doc.appendChild(hall);
|
||||
responseWriter.writeResponse(doc);
|
||||
} catch (HttpProcessingException exp) {
|
||||
responseWriter.writeError(exp.getStatus());
|
||||
} catch (Exception exp) {
|
||||
responseWriter.writeError(500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class SerializeHallInfoVisitor implements HallChannelVisitor {
|
||||
private Document _doc;
|
||||
private Element _hall;
|
||||
|
||||
public SerializeHallInfoVisitor(Document doc, Element hall) {
|
||||
_doc = doc;
|
||||
_hall = hall;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelNumber(int channelNumber) {
|
||||
_hall.setAttribute("channelNumber", String.valueOf(channelNumber));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverTime(String serverTime) {
|
||||
_hall.setAttribute("serverTime", serverTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void motdChanged(String motd) {
|
||||
_hall.setAttribute("motd", motd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTournamentQueue(String queueId, Map<String, String> props) {
|
||||
Element queue = _doc.createElement("queue");
|
||||
queue.setAttribute("action", "add");
|
||||
queue.setAttribute("id", queueId);
|
||||
for (Map.Entry<String, String> attribute : props.entrySet())
|
||||
queue.setAttribute(attribute.getKey(), attribute.getValue());
|
||||
_hall.appendChild(queue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTournamentQueue(String queueId, Map<String, String> props) {
|
||||
Element queue = _doc.createElement("queue");
|
||||
queue.setAttribute("action", "update");
|
||||
queue.setAttribute("id", queueId);
|
||||
for (Map.Entry<String, String> attribute : props.entrySet())
|
||||
queue.setAttribute(attribute.getKey(), attribute.getValue());
|
||||
_hall.appendChild(queue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTournamentQueue(String queueId) {
|
||||
Element queue = _doc.createElement("queue");
|
||||
queue.setAttribute("action", "remove");
|
||||
queue.setAttribute("id", queueId);
|
||||
_hall.appendChild(queue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTournament(String tournamentId, Map<String, String> props) {
|
||||
Element tournament = _doc.createElement("tournament");
|
||||
tournament.setAttribute("action", "add");
|
||||
tournament.setAttribute("id", tournamentId);
|
||||
for (Map.Entry<String, String> attribute : props.entrySet())
|
||||
tournament.setAttribute(attribute.getKey(), attribute.getValue());
|
||||
_hall.appendChild(tournament);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTournament(String tournamentId, Map<String, String> props) {
|
||||
Element tournament = _doc.createElement("tournament");
|
||||
tournament.setAttribute("action", "update");
|
||||
tournament.setAttribute("id", tournamentId);
|
||||
for (Map.Entry<String, String> attribute : props.entrySet())
|
||||
tournament.setAttribute(attribute.getKey(), attribute.getValue());
|
||||
_hall.appendChild(tournament);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTournament(String tournamentId) {
|
||||
Element tournament = _doc.createElement("tournament");
|
||||
tournament.setAttribute("action", "remove");
|
||||
tournament.setAttribute("id", tournamentId);
|
||||
_hall.appendChild(tournament);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTable(String tableId, Map<String, String> props) {
|
||||
Element table = _doc.createElement("table");
|
||||
table.setAttribute("action", "add");
|
||||
table.setAttribute("id", tableId);
|
||||
for (Map.Entry<String, String> attribute : props.entrySet())
|
||||
table.setAttribute(attribute.getKey(), attribute.getValue());
|
||||
_hall.appendChild(table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTable(String tableId, Map<String, String> props) {
|
||||
Element table = _doc.createElement("table");
|
||||
table.setAttribute("action", "update");
|
||||
table.setAttribute("id", tableId);
|
||||
for (Map.Entry<String, String> attribute : props.entrySet())
|
||||
table.setAttribute(attribute.getKey(), attribute.getValue());
|
||||
_hall.appendChild(table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTable(String tableId) {
|
||||
Element table = _doc.createElement("table");
|
||||
table.setAttribute("action", "remove");
|
||||
table.setAttribute("id", tableId);
|
||||
_hall.appendChild(table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runningPlayerGame(String gameId) {
|
||||
Element runningGame = _doc.createElement("game");
|
||||
runningGame.setAttribute("id", gameId);
|
||||
_hall.appendChild(runningGame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerBusy(boolean busy) {
|
||||
_hall.setAttribute("busy", String.valueOf(busy));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
public class HttpProcessingException extends Exception {
|
||||
private int _status;
|
||||
|
||||
public HttpProcessingException(int status) {
|
||||
_status = status;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return _status;
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.channel.*;
|
||||
import org.jboss.netty.handler.codec.http.*;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.is100ContinueExpected;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.isKeepAlive;
|
||||
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
|
||||
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
import org.jboss.netty.util.CharsetUtil;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpRequestHandler extends SimpleChannelUpstreamHandler {
|
||||
|
||||
private HttpRequest _request;
|
||||
private boolean _readingChunks;
|
||||
private String _uri;
|
||||
private Map<Type, Object> _objects;
|
||||
|
||||
public HttpRequestHandler(Map<Type, Object> objects) {
|
||||
_objects = objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
||||
_request = (HttpRequest) e.getMessage();
|
||||
|
||||
if (is100ContinueExpected(_request)) {
|
||||
send100Continue(e);
|
||||
}
|
||||
|
||||
String uri = _request.getUri();
|
||||
|
||||
if (uri.indexOf("?")>-1)
|
||||
_uri = uri.substring(0, uri.indexOf("?"));
|
||||
else
|
||||
_uri = uri;
|
||||
|
||||
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(_request.getUri());
|
||||
Map<String, List<String>> queryStringParams = queryStringDecoder.getParameters();
|
||||
|
||||
HttpMethod httpMethod = _request.getMethod();
|
||||
|
||||
if (_request.isChunked()) {
|
||||
send400Error(e);
|
||||
} else {
|
||||
ChannelBuffer content = _request.getContent();
|
||||
if (content.readable()) {
|
||||
}
|
||||
writeResponse(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeResponse(MessageEvent e) {
|
||||
// Decide whether to close the connection or not.
|
||||
boolean keepAlive = isKeepAlive(_request);
|
||||
|
||||
// Build the response object.
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
response.setContent(ChannelBuffers.copiedBuffer("Response: " + _uri, CharsetUtil.UTF_8));
|
||||
response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
|
||||
if (keepAlive) {
|
||||
// Add 'Content-Length' header only for a keep-alive connection.
|
||||
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
|
||||
}
|
||||
|
||||
// Write the response.
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
|
||||
// Close the non-keep-alive connection after the write operation is done.
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
private void send400Error(MessageEvent e) {
|
||||
boolean keepAlive = isKeepAlive(_request);
|
||||
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, BAD_REQUEST);
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
private void send100Continue(MessageEvent e) {
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, CONTINUE);
|
||||
e.getChannel().write(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
|
||||
throws Exception {
|
||||
e.getCause().printStackTrace();
|
||||
e.getChannel().close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import org.jboss.netty.handler.codec.http.Cookie;
|
||||
import org.jboss.netty.handler.codec.http.CookieDecoder;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.COOKIE;
|
||||
import org.jboss.netty.handler.codec.http.HttpRequest;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class LoggedUserHolder {
|
||||
private Map<String, String> _users = Collections.synchronizedMap(new HashMap<String, String>());
|
||||
|
||||
public String getLoggedUser(HttpRequest request) {
|
||||
CookieDecoder cookieDecoder = new CookieDecoder();
|
||||
Set<Cookie> cookies = cookieDecoder.decode(request.getHeader(COOKIE));
|
||||
for (Cookie cookie : cookies) {
|
||||
if (cookie.getName().equals("loggedUser")) {
|
||||
String value = cookie.getValue();
|
||||
if (value != null) {
|
||||
String loggedUser = _users.get(value);
|
||||
if (loggedUser != null)
|
||||
return loggedUser;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<String, String> logUser(String userName) {
|
||||
Map<String, String> cookies = new HashMap<String, String>();
|
||||
cookies.put("loggedUser", insertValueForUser(userName));
|
||||
return cookies;
|
||||
}
|
||||
|
||||
private char[] _chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
|
||||
|
||||
private synchronized String insertValueForUser(String userName) {
|
||||
Random rnd = new Random();
|
||||
String randomStr;
|
||||
do {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < 20; i++)
|
||||
result.append(_chars[rnd.nextInt(_chars.length)]);
|
||||
randomStr = result.toString();
|
||||
} while (_users.containsKey(randomStr));
|
||||
_users.put(randomStr, userName);
|
||||
return randomStr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import com.gempukku.lotro.game.Player;
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.handler.codec.http.HttpMethod;
|
||||
import org.jboss.netty.handler.codec.http.HttpRequest;
|
||||
import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
public class LoginRequestHandler extends LotroServerRequestHandler implements UriRequestHandler {
|
||||
public LoginRequestHandler(Map<Type, Object> context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(String uri, HttpRequest request, Map<Type, Object> context, ResponseWriter responseWriter, MessageEvent e) {
|
||||
try {
|
||||
if (uri.equals("") && request.getMethod() == HttpMethod.POST) {
|
||||
HttpPostRequestDecoder postDecoder = new HttpPostRequestDecoder(request);
|
||||
String login = getFormParameterSafely(postDecoder, "login");
|
||||
String password = getFormParameterSafely(postDecoder, "password");
|
||||
|
||||
Player player = _playerDao.loginUser(login, password);
|
||||
if (player != null) {
|
||||
if (player.getType().contains("u")) {
|
||||
responseWriter.writeResponse(null, logUserReturningCookies(e, login));
|
||||
} else {
|
||||
responseWriter.writeError(403);
|
||||
}
|
||||
} else {
|
||||
responseWriter.writeError(401);
|
||||
}
|
||||
|
||||
} else {
|
||||
responseWriter.writeError(404);
|
||||
}
|
||||
} catch (Exception exp) {
|
||||
responseWriter.writeError(500);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> logUserReturningCookies(MessageEvent e, String login) throws SQLException {
|
||||
_playerDao.updateLastLoginIp(login, e.getChannel().getRemoteAddress().toString());
|
||||
return _loggedUserHolder.logUser(login);
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,10 @@ public class LotroAsyncServer {
|
||||
|
||||
ServerBootstrap bootstrap = new ServerBootstrap(factory);
|
||||
|
||||
bootstrap.setPipelineFactory(new HttpServerPipelineFactory());
|
||||
bootstrap.setPipelineFactory(new LotroServerPipelineFactory());
|
||||
|
||||
bootstrap.setOption("child.tcpNoDelay", true);
|
||||
bootstrap.setOption("child.keepAlive", true);
|
||||
bootstrap.bind(new InetSocketAddress(8080));
|
||||
bootstrap.bind(new InetSocketAddress(80));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.channel.*;
|
||||
import org.jboss.netty.handler.codec.http.*;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.is100ContinueExpected;
|
||||
import static org.jboss.netty.handler.codec.http.HttpHeaders.isKeepAlive;
|
||||
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
|
||||
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
import org.jboss.netty.util.CharsetUtil;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public class LotroHttpRequestHandler extends SimpleChannelUpstreamHandler {
|
||||
private Logger _log = Logger.getLogger(LotroHttpRequestHandler.class);
|
||||
|
||||
private Map<Type, Object> _objects;
|
||||
private UriRequestHandler _uriRequestHandler;
|
||||
|
||||
public LotroHttpRequestHandler(Map<Type, Object> objects, UriRequestHandler uriRequestHandler) {
|
||||
_objects = objects;
|
||||
_uriRequestHandler = uriRequestHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception {
|
||||
final HttpRequest request = (HttpRequest) e.getMessage();
|
||||
|
||||
if (is100ContinueExpected(request)) {
|
||||
send100Continue(e);
|
||||
}
|
||||
|
||||
String uri = request.getUri();
|
||||
|
||||
if (uri.indexOf("?") > -1)
|
||||
uri = uri.substring(0, uri.indexOf("?"));
|
||||
|
||||
if (request.isChunked()) {
|
||||
send400Error(request, e);
|
||||
} else {
|
||||
ResponseWriter responseWriter = new ResponseWriter() {
|
||||
@Override
|
||||
public void writeError(int status) {
|
||||
writeHttpErrorResponse(request, status, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeResponse(Document document) {
|
||||
writeHttpResponse(request, document, null, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeResponse(Document document, Map<String, String> addCookies) {
|
||||
writeHttpResponse(request, document, addCookies, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHtmlResponse(String html) {
|
||||
writeHttpHtmlResponse(request, html, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFile(File file) {
|
||||
writeFileResponse(request, file, e);
|
||||
}
|
||||
};
|
||||
|
||||
_uriRequestHandler.handleRequest(uri, request, _objects, responseWriter, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeFileResponse(HttpRequest request, File file, MessageEvent e) {
|
||||
try {
|
||||
RandomAccessFile raf;
|
||||
try {
|
||||
raf = new RandomAccessFile(file, "r");
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
writeHttpErrorResponse(request, 404, e);
|
||||
return;
|
||||
}
|
||||
long fileLength = raf.length();
|
||||
|
||||
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
response.setHeader(CONTENT_LENGTH, fileLength);
|
||||
|
||||
String fileName = file.getName();
|
||||
if (fileName.endsWith(".html")) {
|
||||
response.setHeader(CACHE_CONTROL, "no-cache");
|
||||
response.setHeader(PRAGMA, "no-cache");
|
||||
response.setHeader(EXPIRES, -1);
|
||||
response.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
}
|
||||
|
||||
Channel ch = e.getChannel();
|
||||
|
||||
// Write the initial line and the header.
|
||||
ch.write(response);
|
||||
|
||||
// Write the content.
|
||||
ChannelFuture writeFuture;
|
||||
// No encryption - use zero-copy.
|
||||
final FileRegion region =
|
||||
new DefaultFileRegion(raf.getChannel(), 0, fileLength);
|
||||
writeFuture = ch.write(region);
|
||||
writeFuture.addListener(new ChannelFutureProgressListener() {
|
||||
public void operationComplete(ChannelFuture future) {
|
||||
region.releaseExternalResources();
|
||||
}
|
||||
|
||||
public void operationProgressed(
|
||||
ChannelFuture future, long amount, long current, long total) {
|
||||
}
|
||||
});
|
||||
|
||||
// Decide whether to close the connection or not.
|
||||
if (!isKeepAlive(request)) {
|
||||
// Close the connection when the whole content is written out.
|
||||
writeFuture.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
} catch (IOException exp) {
|
||||
writeHttpErrorResponse(request, 500, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHttpErrorResponse(HttpRequest request, int status, MessageEvent e) {
|
||||
boolean keepAlive = isKeepAlive(request);
|
||||
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(status));
|
||||
|
||||
if (keepAlive) {
|
||||
// Add 'Content-Length' header only for a keep-alive connection.
|
||||
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
|
||||
}
|
||||
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHttpResponse(HttpRequest request, Document document, Map<String, String> addCookies, MessageEvent e) {
|
||||
// Decide whether to close the connection or not.
|
||||
boolean keepAlive = isKeepAlive(request);
|
||||
|
||||
try {
|
||||
// Build the response object.
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
|
||||
if (addCookies != null) {
|
||||
CookieEncoder cookieEncoder = new CookieEncoder(true);
|
||||
for (Map.Entry<String, String> cookie : addCookies.entrySet())
|
||||
cookieEncoder.addCookie(cookie.getKey(), cookie.getValue());
|
||||
response.setHeader(SET_COOKIE, cookieEncoder.encode());
|
||||
}
|
||||
|
||||
int length = 0;
|
||||
if (document != null) {
|
||||
DOMSource domSource = new DOMSource(document);
|
||||
StringWriter writer = new StringWriter();
|
||||
StreamResult result = new StreamResult(writer);
|
||||
TransformerFactory tf = TransformerFactory.newInstance();
|
||||
Transformer transformer = tf.newTransformer();
|
||||
transformer.transform(domSource, result);
|
||||
|
||||
String responseString = writer.toString();
|
||||
response.setContent(ChannelBuffers.copiedBuffer(responseString, CharsetUtil.UTF_8));
|
||||
response.setHeader(CONTENT_TYPE, "application/xml; charset=UTF-8");
|
||||
|
||||
length = responseString.length();
|
||||
}
|
||||
|
||||
if (keepAlive) {
|
||||
// Add 'Content-Length' header only for a keep-alive connection.
|
||||
response.setHeader(CONTENT_LENGTH, length);
|
||||
}
|
||||
|
||||
// Write the response.
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
} catch (Exception exp) {
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(500));
|
||||
|
||||
if (keepAlive) {
|
||||
// Add 'Content-Length' header only for a keep-alive connection.
|
||||
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
|
||||
}
|
||||
|
||||
// Write the response.
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void writeHttpHtmlResponse(HttpRequest request, String html, MessageEvent e) {
|
||||
// Decide whether to close the connection or not.
|
||||
boolean keepAlive = isKeepAlive(request);
|
||||
|
||||
try {
|
||||
// Build the response object.
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
|
||||
response.setContent(ChannelBuffers.copiedBuffer(html, CharsetUtil.UTF_8));
|
||||
response.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
|
||||
int length = html.length();
|
||||
|
||||
if (keepAlive) {
|
||||
// Add 'Content-Length' header only for a keep-alive connection.
|
||||
response.setHeader(CONTENT_LENGTH, length);
|
||||
}
|
||||
|
||||
// Write the response.
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
} catch (Exception exp) {
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.valueOf(500));
|
||||
|
||||
if (keepAlive) {
|
||||
// Add 'Content-Length' header only for a keep-alive connection.
|
||||
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
|
||||
}
|
||||
|
||||
// Write the response.
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void send400Error(HttpRequest request, MessageEvent e) {
|
||||
boolean keepAlive = isKeepAlive(request);
|
||||
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, BAD_REQUEST);
|
||||
ChannelFuture future = e.getChannel().write(response);
|
||||
if (!keepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
private void send100Continue(MessageEvent e) {
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, CONTINUE);
|
||||
e.getChannel().write(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
|
||||
throws Exception {
|
||||
_log.error("Error while processing request", e.getCause());
|
||||
e.getChannel().close();
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,23 @@ import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpServerPipelineFactory implements ChannelPipelineFactory {
|
||||
public class LotroServerPipelineFactory implements ChannelPipelineFactory {
|
||||
private Map<Type, Object> _context;
|
||||
private UriRequestHandler _uriRequestHandler;
|
||||
|
||||
public LotroServerPipelineFactory() {
|
||||
Map<Type, Object> objects = new HashMap<Type, Object>();
|
||||
objects.put(PacksStorage.class, PacksStorageBuilder.createPacksStorage());
|
||||
DaoBuilder.fillObjectMap(objects);
|
||||
ServerBuilder.fillObjectMap(objects);
|
||||
ServerBuilder.constructObjects(objects);
|
||||
|
||||
objects.put(LoggedUserHolder.class, new LoggedUserHolder());
|
||||
|
||||
_context = objects;
|
||||
_uriRequestHandler = new RootUriRequestHandler(_context);
|
||||
}
|
||||
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
// Create a default pipeline implementation.
|
||||
ChannelPipeline pipeline = Channels.pipeline();
|
||||
@@ -32,13 +48,7 @@ public class HttpServerPipelineFactory implements ChannelPipelineFactory {
|
||||
// Remove the following line if you don't want automatic content compression.
|
||||
pipeline.addLast("deflater", new HttpContentCompressor());
|
||||
|
||||
Map<Type, Object> objects = new HashMap<Type, Object>();
|
||||
objects.put(PacksStorage.class, PacksStorageBuilder.createPacksStorage());
|
||||
DaoBuilder.fillObjectMap(objects);
|
||||
ServerBuilder.fillObjectMap(objects);
|
||||
ServerBuilder.constructObjects(objects);
|
||||
|
||||
pipeline.addLast("handler", new HttpRequestHandler(objects));
|
||||
pipeline.addLast("handler", new LotroHttpRequestHandler(_context, _uriRequestHandler));
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import com.gempukku.lotro.db.PlayerDAO;
|
||||
import com.gempukku.lotro.game.Player;
|
||||
import org.jboss.netty.handler.codec.http.HttpRequest;
|
||||
import org.jboss.netty.handler.codec.http.QueryStringDecoder;
|
||||
import org.jboss.netty.handler.codec.http.multipart.Attribute;
|
||||
import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
|
||||
import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class LotroServerRequestHandler {
|
||||
protected PlayerDAO _playerDao;
|
||||
protected LoggedUserHolder _loggedUserHolder;
|
||||
|
||||
public LotroServerRequestHandler(Map<Type, Object> context) {
|
||||
_playerDao = extractObject(context, PlayerDAO.class);
|
||||
_loggedUserHolder = extractObject(context, LoggedUserHolder.class);
|
||||
}
|
||||
|
||||
private boolean isTest() {
|
||||
return Boolean.valueOf(System.getProperty("test"));
|
||||
}
|
||||
|
||||
protected final Player getResourceOwnerSafely(HttpRequest request, String participantId) throws HttpProcessingException {
|
||||
String loggedUser = _loggedUserHolder.getLoggedUser(request);
|
||||
if (isTest() && loggedUser == null)
|
||||
loggedUser = participantId;
|
||||
|
||||
if (loggedUser == null)
|
||||
throw new HttpProcessingException(401);
|
||||
|
||||
Player resourceOwner = _playerDao.getPlayer(loggedUser);
|
||||
|
||||
if (resourceOwner == null)
|
||||
throw new HttpProcessingException(401);
|
||||
|
||||
if (resourceOwner.getType().contains("a") && participantId != null && !participantId.equals("null") && !participantId.equals("")) {
|
||||
resourceOwner = _playerDao.getPlayer(participantId);
|
||||
if (resourceOwner == null)
|
||||
throw new HttpProcessingException(401);
|
||||
}
|
||||
return resourceOwner;
|
||||
}
|
||||
|
||||
protected String getQueryParameterSafely(QueryStringDecoder queryStringDecoder, String parameterName) {
|
||||
List<String> parameterValues = queryStringDecoder.getParameters().get(parameterName);
|
||||
if (parameterValues.size() > 0)
|
||||
return parameterValues.get(0);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getFormParameterSafely(HttpPostRequestDecoder postRequestDecoder, String parameterName) throws IOException, HttpPostRequestDecoder.NotEnoughDataDecoderException {
|
||||
InterfaceHttpData data = postRequestDecoder.getBodyHttpData(parameterName);
|
||||
if (data == null)
|
||||
return null;
|
||||
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
|
||||
Attribute attribute = (Attribute) data;
|
||||
return attribute.getValue();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> T extractObject(Map<Type, Object> context, Class<T> clazz) {
|
||||
Object value = context.get(clazz);
|
||||
return (T) value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
public interface ResponseWriter {
|
||||
public void writeError(int status);
|
||||
|
||||
public void writeFile(File file);
|
||||
|
||||
public void writeHtmlResponse(String html);
|
||||
|
||||
public void writeResponse(Document document);
|
||||
|
||||
public void writeResponse(Document document, Map<String, String> addCookies);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.handler.codec.http.HttpRequest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public class RootUriRequestHandler implements UriRequestHandler {
|
||||
private String _serverContextPath ="/gemp-lotr-server/";
|
||||
private String _webContextPath="/gemp-lotr/";
|
||||
private HallRequestHandler _hallRequestHandler;
|
||||
private WebRequestHandler _webRequestHandler = new WebRequestHandler();
|
||||
private LoginRequestHandler _loginRequestHandler;
|
||||
private StatusRequestHandler _statusRequestHandler;
|
||||
|
||||
public RootUriRequestHandler(Map<Type, Object> context) {
|
||||
_hallRequestHandler = new HallRequestHandler(context);
|
||||
_loginRequestHandler = new LoginRequestHandler(context);
|
||||
_statusRequestHandler = new StatusRequestHandler(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(String uri, HttpRequest request, Map<Type, Object> context, ResponseWriter responseWriter, MessageEvent e) {
|
||||
if (uri.startsWith(_webContextPath)) {
|
||||
_webRequestHandler.handleRequest(uri.substring(_webContextPath.length()), request, context, responseWriter, e);
|
||||
} else if (uri.startsWith(_serverContextPath +"hall")) {
|
||||
_hallRequestHandler.handleRequest(uri.substring(_serverContextPath.length()+4), request, context, responseWriter, e);
|
||||
} else if (uri.startsWith(_serverContextPath+"login")) {
|
||||
_loginRequestHandler.handleRequest(uri.substring(_serverContextPath.length()+5), request, context, responseWriter, e);
|
||||
} else if (uri.equals(_serverContextPath)) {
|
||||
_statusRequestHandler.handleRequest(uri.substring(_serverContextPath.length()), request, context, responseWriter, e);
|
||||
} else {
|
||||
responseWriter.writeError(404);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import com.gempukku.lotro.chat.ChatServer;
|
||||
import com.gempukku.lotro.game.GameHistoryService;
|
||||
import com.gempukku.lotro.hall.HallServer;
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.handler.codec.http.HttpMethod;
|
||||
import org.jboss.netty.handler.codec.http.HttpRequest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public class StatusRequestHandler extends LotroServerRequestHandler implements UriRequestHandler {
|
||||
private HallServer _hallServer;
|
||||
private GameHistoryService _gameHistoryService;
|
||||
private ChatServer _chatServer;
|
||||
|
||||
public StatusRequestHandler(Map<Type, Object> context) {
|
||||
super(context);
|
||||
_hallServer = extractObject(context, HallServer.class);
|
||||
_gameHistoryService = extractObject(context, GameHistoryService.class);
|
||||
_chatServer = extractObject(context, ChatServer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(String uri, HttpRequest request, Map<Type, Object> context, ResponseWriter responseWriter, MessageEvent e) {
|
||||
if (uri.equals("") && request.getMethod() == HttpMethod.GET) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int day = 1000 * 60 * 60 * 24;
|
||||
int week = 1000 * 60 * 60 * 24 * 7;
|
||||
sb.append("Tables count: ").append(_hallServer.getTablesCount()).append(", players in hall: ").append(_chatServer.getChatRoom("Game Hall").getUsersInRoom().size())
|
||||
.append(", games played in last 24 hours: ").append(_gameHistoryService.getGamesPlayedCount(System.currentTimeMillis() - day, day))
|
||||
.append(",<br/> active players in last week: ").append(_gameHistoryService.getActivePlayersCount(System.currentTimeMillis() - week, week));
|
||||
|
||||
responseWriter.writeHtmlResponse(sb.toString());
|
||||
} else {
|
||||
responseWriter.writeError(404);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.handler.codec.http.HttpRequest;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public interface UriRequestHandler {
|
||||
public void handleRequest(String uri, HttpRequest request, Map<Type, Object> context, ResponseWriter responseWriter, MessageEvent e);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.gempukku.lotro.async;
|
||||
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.handler.codec.http.HttpRequest;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
public class WebRequestHandler implements UriRequestHandler {
|
||||
private String _root = "I:\\dev\\projects\\gemp-lotr\\gemp-lotr-web\\src\\main\\webapp\\";
|
||||
|
||||
@Override
|
||||
public void handleRequest(String uri, HttpRequest request, Map<Type, Object> context, ResponseWriter responseWriter, MessageEvent e) {
|
||||
if (uri.equals(""))
|
||||
uri = "index.html";
|
||||
|
||||
uri = uri.replace('/', File.separatorChar);
|
||||
|
||||
if ((uri.contains(".."))
|
||||
|| uri.contains(File.separator + ".")
|
||||
|| uri.startsWith(".") || uri.endsWith(".")) {
|
||||
responseWriter.writeError(403);
|
||||
} else {
|
||||
File file = new File(_root + uri);
|
||||
responseWriter.writeFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
gemp-lotr/gemp-lotr-async/src/main/resources/test-log4j.xml
Normal file
43
gemp-lotr/gemp-lotr-async/src/main/resources/test-log4j.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
|
||||
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<!-- Pattern to output the caller's file name and line number -->
|
||||
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n"/>
|
||||
</layout>
|
||||
</appender>
|
||||
<appender name="R" class="org.apache.log4j.RollingFileAppender">
|
||||
<param name="file" value="${catalina.base}/logs/gemp-lotr.log"/>
|
||||
<param name="MaxFileSize" value="10MB"/>
|
||||
<param name="MaxBackupIndex" value="20"/>
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n"/>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="chat" class="org.apache.log4j.RollingFileAppender">
|
||||
<param name="file" value="${catalina.base}/logs/chat.log"/>
|
||||
<param name="MaxFileSize" value="10MB"/>
|
||||
<!-- Keep one backup file -->
|
||||
<param name="MaxBackupIndex" value="20"/>
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n"/>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<logger name="com.gempukku" additivity="false">
|
||||
<level value="debug"/>
|
||||
<appender-ref ref="R"/>
|
||||
<appender-ref ref="stdout"/>
|
||||
</logger>
|
||||
<logger name="chat">
|
||||
<level value="ALL"/>
|
||||
<appender-ref ref="chat"/>
|
||||
</logger>
|
||||
<root>
|
||||
<level value="error"/>
|
||||
<appender-ref ref="R"/>
|
||||
<appender-ref ref="stdout"/>
|
||||
</root>
|
||||
</log4j:configuration>
|
||||
@@ -34,9 +34,11 @@ public class CollectionsManager {
|
||||
|
||||
// Hunters have 1-194 normal cards, 9 "O" cards, and 3 extra to cover the different culture versions of 15_60
|
||||
|
||||
boolean test = Boolean.valueOf(System.getProperty("test"));
|
||||
|
||||
final int[] cardCounts = new int[]{129, 365, 122, 122, 365, 128, 128, 365, 122, 52, 122, 266, 203, 203, 15, 207, 6, 157, 149, 40};
|
||||
|
||||
for (int i = 0; i <= 19; i++) {
|
||||
for (int i = 0; i <= (test?1:19); i++) {
|
||||
_logger.debug("Loading set " + i);
|
||||
for (int j = 1; j <= cardCounts[i]; j++) {
|
||||
String blueprintId = i + "_" + j;
|
||||
|
||||
Reference in New Issue
Block a user