mirror of
https://github.com/correl/mage.git
synced 2024-11-14 19:19:32 +00:00
Mage.Stats WS module for getting server stats in json format
This commit is contained in:
parent
78c0d76088
commit
71614becc2
43 changed files with 1587 additions and 0 deletions
180
Mage.Stats/pom.xml
Normal file
180
Mage.Stats/pom.xml
Normal file
|
@ -0,0 +1,180 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-root</artifactId>
|
||||
<version>1.3.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-stats</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>XMage Stats Web Service</name>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>JBoss repository</id>
|
||||
<url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mage</groupId>
|
||||
<artifactId>mage-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.minidev</groupId>
|
||||
<artifactId>json-smart</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.6.11</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.sf.opencsv</groupId>
|
||||
<artifactId>opencsv</artifactId>
|
||||
<version>2.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Web services -->
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxrs</artifactId>
|
||||
<version>2.3.5.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.minidev</groupId>
|
||||
<artifactId>json-smart</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.6.11</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.0.10</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.sling</groupId>
|
||||
<artifactId>org.apache.sling.commons.json</artifactId>
|
||||
<version>2.0.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-multipart-provider</artifactId>
|
||||
<version>2.2.0.GA</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-httpclient</groupId>
|
||||
<artifactId>commons-httpclient</artifactId>
|
||||
<version>3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>mage-stats-ws</finalName>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.0.2</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<webXml>src\main\webapp\WEB-INF\web.xml</webXml>
|
||||
<outputDirectory>.</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>aspectj-maven-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>
|
||||
<basedir>src/main/java</basedir>
|
||||
</source>
|
||||
</sources>
|
||||
<complianceLevel>1.6</complianceLevel>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal> <!-- use this goal to weave all your main classes -->
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</project>
|
|
@ -0,0 +1,17 @@
|
|||
package com.xmage.core.builders;
|
||||
|
||||
public abstract class Builder<E> {
|
||||
|
||||
protected E entity;
|
||||
|
||||
protected Builder() {
|
||||
//entity = E.class.newInstance();
|
||||
}
|
||||
|
||||
abstract protected void validate();
|
||||
|
||||
public final E build() {
|
||||
validate();
|
||||
return entity;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.xmage.core.constants;
|
||||
|
||||
public class Constants {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.xmage.core.decorators;
|
||||
|
||||
/**
|
||||
* @author noxx
|
||||
*/
|
||||
public interface Decorator {
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.xmage.core.entity.model;
|
||||
|
||||
|
||||
/**
|
||||
* Marker interface for entity models.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public interface EntityModel {
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.xmage.core.entity.model;
|
||||
|
||||
|
||||
/**
|
||||
* Class representing XMage server stats.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class ServerStats implements EntityModel {
|
||||
|
||||
private int numberOfGamesPlayed;
|
||||
|
||||
private int numberOfUniquePlayers;
|
||||
|
||||
private String top3Players;
|
||||
|
||||
private int numberOfPlayersPlayedOnce;
|
||||
|
||||
public int getNumberOfGamesPlayed() {
|
||||
return numberOfGamesPlayed;
|
||||
}
|
||||
|
||||
public void setNumberOfGamesPlayed(int numberOfGamesPlayed) {
|
||||
this.numberOfGamesPlayed = numberOfGamesPlayed;
|
||||
}
|
||||
|
||||
public int getNumberOfUniquePlayers() {
|
||||
return numberOfUniquePlayers;
|
||||
}
|
||||
|
||||
public void setNumberOfUniquePlayers(int numberOfUniquePlayers) {
|
||||
this.numberOfUniquePlayers = numberOfUniquePlayers;
|
||||
}
|
||||
|
||||
public int getNumberOfPlayersPlayedOnce() {
|
||||
return numberOfPlayersPlayedOnce;
|
||||
}
|
||||
|
||||
public void setNumberOfPlayersPlayedOnce(int numberOfPlayersPlayedOnce) {
|
||||
this.numberOfPlayersPlayedOnce = numberOfPlayersPlayedOnce;
|
||||
}
|
||||
|
||||
public String getTop3Players() {
|
||||
return top3Players;
|
||||
}
|
||||
|
||||
public void setTop3Players(String top3Players) {
|
||||
this.top3Players = top3Players;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ServerStats stats = (ServerStats) o;
|
||||
|
||||
if (numberOfGamesPlayed != stats.numberOfGamesPlayed) return false;
|
||||
if (numberOfUniquePlayers != stats.numberOfUniquePlayers) return false;
|
||||
if (numberOfPlayersPlayedOnce != stats.numberOfPlayersPlayedOnce) return false;
|
||||
if (top3Players != null ? !top3Players.equals(stats.top3Players) : stats.top3Players != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = numberOfGamesPlayed;
|
||||
result = 31 * result + numberOfUniquePlayers;
|
||||
result = 31 * result + numberOfPlayersPlayedOnce;
|
||||
result = 31 * result + (top3Players != null ? top3Players.hashCode() : 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.xmage.core.entity.repositories;
|
||||
|
||||
import com.xmage.core.entity.model.ServerStats;
|
||||
|
||||
/**
|
||||
* Repository interface for XMage server stats.
|
||||
*
|
||||
* Responsible for fetching stats information.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public interface XMageStatsRepository {
|
||||
|
||||
ServerStats getServerStats();
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
package com.xmage.core.entity.repositories.impl;
|
||||
|
||||
import com.xmage.core.entity.model.ServerStats;
|
||||
import com.xmage.core.entity.repositories.XMageStatsRepository;
|
||||
import mage.db.EntityManager;
|
||||
import mage.db.model.Log;
|
||||
import mage.server.services.LogKeys;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Implementation for {@link com.xmage.core.entity.repositories.XMageStatsRepository}
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class XMageStatsRepositoryImpl implements XMageStatsRepository {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(XMageStatsRepositoryImpl.class);
|
||||
|
||||
@Override
|
||||
public ServerStats getServerStats() {
|
||||
ServerStats serverStats = new ServerStats();
|
||||
|
||||
List<Log> logs = EntityManager.instance.getAllLogs();
|
||||
logger.info("logs found count: " + logs.size());
|
||||
|
||||
int numberOfGamesPlayed = 0;
|
||||
Set<String> playerNames = new HashSet<String>();
|
||||
|
||||
// Get nicknames and games started count
|
||||
Map<String, Integer> nicknames = new HashMap<String, Integer>();
|
||||
for (Log log : logs) {
|
||||
if (log.getKey().equals(LogKeys.KEY_GAME_STARTED)) {
|
||||
if (log.getArguments() != null) {
|
||||
int index = 0;
|
||||
for (String argument : log.getArguments()) {
|
||||
if (index > 0) {
|
||||
inc(nicknames, argument);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
numberOfGamesPlayed++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort games
|
||||
Collection<Integer> values = nicknames.values();
|
||||
List<Integer> games = new ArrayList<Integer>();
|
||||
games.addAll(values);
|
||||
Collections.sort(games, new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer i1, Integer i2) {
|
||||
return i2.compareTo(i1);
|
||||
}
|
||||
});
|
||||
|
||||
// Top-3
|
||||
List<Integer> numbersToFind = new ArrayList<Integer>();
|
||||
for (Integer numberOfGames : games) {
|
||||
numbersToFind.add(numberOfGames);
|
||||
if (numbersToFind.size() == 3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Map<Integer, String> players = new LinkedHashMap<Integer, String>();
|
||||
for (Integer number : numbersToFind) {
|
||||
for (Map.Entry<String, Integer> entry : nicknames.entrySet()) {
|
||||
if (entry.getValue().equals(number)) {
|
||||
players.put(entry.getValue(), entry.getKey());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (players.size() == 3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Build top-3 string
|
||||
StringBuilder top3 = new StringBuilder();
|
||||
for (Map.Entry<Integer, String> entry : players.entrySet()) {
|
||||
top3.append("[").append(entry.getValue()).append(":").append(entry.getKey()).append("]");
|
||||
}
|
||||
|
||||
// Played only once
|
||||
Integer oneGamePlayers = 0;
|
||||
for (Integer numberOfGames : games) {
|
||||
if (numberOfGames == 1) {
|
||||
oneGamePlayers++;
|
||||
}
|
||||
}
|
||||
|
||||
serverStats.setNumberOfGamesPlayed(numberOfGamesPlayed);
|
||||
serverStats.setNumberOfUniquePlayers(nicknames.size());
|
||||
serverStats.setTop3Players(top3.toString());
|
||||
serverStats.setNumberOfPlayersPlayedOnce(oneGamePlayers);
|
||||
|
||||
return serverStats;
|
||||
}
|
||||
|
||||
private static void inc(Map<String, Integer> map, String player) {
|
||||
if (map.containsKey(player)) {
|
||||
Integer count = map.get(player);
|
||||
count++;
|
||||
map.put(player, count);
|
||||
} else {
|
||||
map.put(player, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean check(List<Integer> numbers, Integer value) {
|
||||
for (Integer number : numbers) {
|
||||
if (number.equals(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.xmage.core.exceptions;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class XMageStatsNotFoundException extends Exception {
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.xmage.ws.aspect;
|
||||
|
||||
import com.xmage.ws.json.ResponseBuilder;
|
||||
import com.xmage.ws.model.DomainErrors;
|
||||
import com.xmage.ws.resource.ErrorResource;
|
||||
import com.xmage.ws.resource.Resource;
|
||||
import com.xmage.ws.util.IPHolderUtil;
|
||||
import net.minidev.json.JSONObject;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* Base aspect for getting request metadata
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
@Aspect
|
||||
public class RequestAspect {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RequestAspect.class);
|
||||
|
||||
@Around("execution(* *(..)) && within(com.xmage.ws.rest.services.*)")
|
||||
public Object advice(ProceedingJoinPoint pjp) throws Throwable {
|
||||
|
||||
try {
|
||||
String ip = IPHolderUtil.getRememberedIP();
|
||||
String userAgent = IPHolderUtil.getRememberedUserAgent();
|
||||
logger.info("ip: " + ip + ", user-agent: " + userAgent);
|
||||
|
||||
return pjp.proceed();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error: ", e);
|
||||
}
|
||||
|
||||
Resource resource = new ErrorResource(DomainErrors.Errors.STATUS_SERVER_ERROR, "server_error");
|
||||
JSONObject serverError = ResponseBuilder.build(resource);
|
||||
|
||||
return Response.status(200).entity(serverError.toJSONString()).build();
|
||||
}
|
||||
|
||||
|
||||
}
|
46
Mage.Stats/src/main/java/com/xmage/ws/filter/IPFilter.java
Normal file
46
Mage.Stats/src/main/java/com/xmage/ws/filter/IPFilter.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
package com.xmage.ws.filter;
|
||||
|
||||
import com.xmage.ws.util.IPHolderUtil;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Filter gets ip address and user agent and stores it using {@link com.xmage.ws.util.IPHolderUtil}
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class IPFilter implements Filter {
|
||||
|
||||
private FilterConfig config;
|
||||
|
||||
public IPFilter() {}
|
||||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
this.config = filterConfig;
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
|
||||
String ip = request.getRemoteAddr();
|
||||
IPHolderUtil.rememberIP(ip);
|
||||
|
||||
if (request instanceof HttpServletRequest) {
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
String uaString = req.getHeader("User-Agent");
|
||||
IPHolderUtil.rememberUserAgent(uaString);
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
|
||||
}// doFilter
|
||||
|
||||
public void destroy() {
|
||||
/*
|
||||
* called before the Filter instance is removed from service by the web
|
||||
* container
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
15
Mage.Stats/src/main/java/com/xmage/ws/json/JSONBuilder.java
Normal file
15
Mage.Stats/src/main/java/com/xmage/ws/json/JSONBuilder.java
Normal file
|
@ -0,0 +1,15 @@
|
|||
package com.xmage.ws.json;
|
||||
|
||||
import com.xmage.core.entity.model.EntityModel;
|
||||
import com.xmage.ws.resource.Resource;
|
||||
import net.minidev.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Converts {@link com.xmage.core.entity.model.EntityModel} to json.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public interface JSONBuilder<R extends EntityModel> {
|
||||
|
||||
JSONObject buildFrom(Resource<R> resource);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.xmage.ws.json;
|
||||
|
||||
import com.xmage.ws.model.DomainErrors;
|
||||
import com.xmage.ws.resource.Resource;
|
||||
import net.minidev.json.JSONObject;
|
||||
|
||||
public class ResponseBuilder {
|
||||
|
||||
public static JSONObject build(int code) {
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("code", code);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public static JSONObject build(int code, String name, JSONObject jsonObject) {
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("code", code);
|
||||
response.put(name, jsonObject);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public static JSONObject build(Resource resource) {
|
||||
if (resource.getError() != DomainErrors.Errors.STATUS_OK.getCode()) {
|
||||
JSONObject response = ResponseBuilder.build(resource.getError());
|
||||
response.put("message", resource.getErrorMessage());
|
||||
return response;
|
||||
} else {
|
||||
JSONObject json = resource.getJSONBody();
|
||||
return ResponseBuilder.build(DomainErrors.Errors.STATUS_OK.getCode(), resource.getName(), json);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.xmage.ws.json;
|
||||
|
||||
import com.xmage.core.entity.model.ServerStats;
|
||||
import com.xmage.ws.resource.Resource;
|
||||
import net.minidev.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
/**
|
||||
* Converts {@link com.xmage.core.entity.model.ServerStats} resource to json.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class XMageStatsJSONBuilder implements JSONBuilder<ServerStats> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(XMageStatsJSONBuilder.class);
|
||||
|
||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
|
||||
|
||||
static class StaticHolder {
|
||||
static XMageStatsJSONBuilder instance = new XMageStatsJSONBuilder();
|
||||
}
|
||||
|
||||
public static XMageStatsJSONBuilder getInstance() {
|
||||
return StaticHolder.instance;
|
||||
}
|
||||
|
||||
public JSONObject buildFrom(Resource<ServerStats> resource) {
|
||||
|
||||
ServerStats serverStats = resource.getDefault();
|
||||
|
||||
JSONObject statsJson = new JSONObject();
|
||||
|
||||
statsJson.put("numberOfGamesPlayed", serverStats.getNumberOfGamesPlayed());
|
||||
statsJson.put("numberOfUniquePlayers", serverStats.getNumberOfUniquePlayers());
|
||||
statsJson.put("numberOfPlayersPlayedOnlyOnce", serverStats.getNumberOfPlayersPlayedOnce());
|
||||
statsJson.put("top3Players", serverStats.getTop3Players());
|
||||
|
||||
return statsJson;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.xmage.ws.model;
|
||||
|
||||
/**
|
||||
* Domain status error codes.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class DomainErrors {
|
||||
|
||||
public enum Errors {
|
||||
STATUS_OK(100, "OK"),
|
||||
STATUS_SERVER_ERROR(101, "Server Internal Error"),
|
||||
STATUS_AUTH_FAILED(102, "Auth failed"),
|
||||
STATUS_ACCESS_DENIED(108, "Access denied"),
|
||||
STATUS_NOT_ENOUGH_PARAMETERS(301, "Not enough parameters"),
|
||||
STATUS_WRONG_PARAM_FORMAT(302, "Wrong param format"),
|
||||
STATUS_NOT_IMPLEMENTED(800, "Not implemented"),
|
||||
STATUS_NOT_FOUND(1000, "Resource Not Found");
|
||||
|
||||
private int code;
|
||||
private String message;
|
||||
|
||||
Errors(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setCustomMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.xmage.ws.model;
|
||||
|
||||
|
||||
/**
|
||||
* Some services may return simple response that is not related to domain or contain minor information.
|
||||
* Example: return OK or FALSE only for checking server state.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class SimpleResponse {
|
||||
|
||||
private int code;
|
||||
|
||||
private String message;
|
||||
|
||||
public SimpleResponse(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public SimpleResponse(DomainErrors.Errors error) {
|
||||
this(error.getCode(), error.getMessage());
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.xmage.ws.representer;
|
||||
|
||||
import com.xmage.ws.resource.Resource;
|
||||
import net.minidev.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Now we have only JSON based representation.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public interface Representer<R> {
|
||||
|
||||
JSONObject toJSON(Resource<R> resource);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.xmage.ws.representer;
|
||||
|
||||
import com.xmage.ws.model.SimpleResponse;
|
||||
import com.xmage.ws.resource.Resource;
|
||||
import net.minidev.json.JSONObject;
|
||||
|
||||
/**
|
||||
* This is useful when we have {@link SimpleResponse}
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class SimpleResponseRepresenter implements Representer<SimpleResponse> {
|
||||
|
||||
public JSONObject toJSON(Resource<SimpleResponse> resource) {
|
||||
SimpleResponse response = resource.getDefault();
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("code", response.getCode());
|
||||
json.put("message", response.getMessage());
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.xmage.ws.representer;
|
||||
|
||||
import com.xmage.core.entity.model.ServerStats;
|
||||
import com.xmage.ws.json.XMageStatsJSONBuilder;
|
||||
import com.xmage.ws.resource.Resource;
|
||||
import net.minidev.json.JSONObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class XMageStatsRepresenter implements Representer<ServerStats> {
|
||||
|
||||
public XMageStatsRepresenter() {
|
||||
}
|
||||
|
||||
public JSONObject toJSON(Resource<ServerStats> resource) {
|
||||
return XMageStatsJSONBuilder.getInstance().buildFrom(resource);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.xmage.ws.resource;
|
||||
|
||||
import com.xmage.core.decorators.Decorator;
|
||||
import com.xmage.ws.model.DomainErrors;
|
||||
import com.xmage.ws.representer.Representer;
|
||||
import net.minidev.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public abstract class DefaultResource<R> implements Resource<R> {
|
||||
|
||||
protected DomainErrors.Errors error = DomainErrors.Errors.STATUS_OK;
|
||||
|
||||
protected R defaultResource;
|
||||
|
||||
protected Representer<R> representer;
|
||||
|
||||
protected java.util.List<Decorator> decorators = new ArrayList<Decorator>();
|
||||
|
||||
protected int version;
|
||||
|
||||
protected DefaultResource(Representer<R> representer) {
|
||||
this.representer = representer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getError() {
|
||||
return error.getCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R getDefault() {
|
||||
return defaultResource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.List<Decorator> getDecorators() {
|
||||
return decorators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDecorator(Decorator decorator) {
|
||||
if (decorator != null) {
|
||||
this.decorators.add(decorator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getJSONBody() {
|
||||
return representer.toJSON(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMessage() {
|
||||
return error.getMessage();
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.xmage.ws.resource;
|
||||
|
||||
import com.xmage.ws.model.DomainErrors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class ErrorResource extends DefaultResource {
|
||||
|
||||
private String name;
|
||||
|
||||
public ErrorResource(DomainErrors.Errors error, String name) {
|
||||
super(null);
|
||||
this.name = name;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
25
Mage.Stats/src/main/java/com/xmage/ws/resource/Resource.java
Normal file
25
Mage.Stats/src/main/java/com/xmage/ws/resource/Resource.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
package com.xmage.ws.resource;
|
||||
|
||||
import com.xmage.core.decorators.Decorator;
|
||||
import net.minidev.json.JSONObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public interface Resource<R> {
|
||||
|
||||
int getError();
|
||||
|
||||
String getErrorMessage();
|
||||
|
||||
String getName();
|
||||
|
||||
JSONObject getJSONBody();
|
||||
|
||||
R getDefault();
|
||||
|
||||
java.util.List<Decorator> getDecorators();
|
||||
|
||||
void addDecorator(Decorator decorator);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.xmage.ws.resource;
|
||||
|
||||
import com.xmage.core.entity.model.ServerStats;
|
||||
import com.xmage.core.entity.repositories.XMageStatsRepository;
|
||||
import com.xmage.core.entity.repositories.impl.XMageStatsRepositoryImpl;
|
||||
import com.xmage.ws.model.DomainErrors;
|
||||
import com.xmage.ws.representer.XMageStatsRepresenter;
|
||||
import com.xmage.ws.representer.Representer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class XMageStatsResource extends DefaultResource<ServerStats> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(XMageStatsResource.class);
|
||||
|
||||
private static XMageStatsRepository xmageStatsRepository = new XMageStatsRepositoryImpl();
|
||||
|
||||
private static final Representer<ServerStats> defaultRepresenter = new XMageStatsRepresenter();
|
||||
|
||||
public XMageStatsResource() {
|
||||
super(defaultRepresenter);
|
||||
}
|
||||
|
||||
public XMageStatsResource(ServerStats event) {
|
||||
super(defaultRepresenter);
|
||||
defaultResource = event;
|
||||
}
|
||||
|
||||
public Resource getAll() {
|
||||
try {
|
||||
ServerStats serverStats = xmageStatsRepository.getServerStats();
|
||||
if (serverStats != null) {
|
||||
defaultResource = serverStats;
|
||||
} else {
|
||||
error = DomainErrors.Errors.STATUS_NOT_FOUND;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Getting server stats error:", e);
|
||||
error = DomainErrors.Errors.STATUS_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "serverStats";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.xmage.ws.resource.impl;
|
||||
|
||||
import com.xmage.ws.model.SimpleResponse;
|
||||
import com.xmage.ws.representer.SimpleResponseRepresenter;
|
||||
import com.xmage.ws.resource.DefaultResource;
|
||||
|
||||
public class SimpleResource extends DefaultResource<SimpleResponse> {
|
||||
|
||||
public SimpleResource() {
|
||||
super(new SimpleResponseRepresenter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "simple";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.xmage.ws.rest;
|
||||
|
||||
import javax.ws.rs.ApplicationPath;
|
||||
import javax.ws.rs.core.Application;
|
||||
|
||||
@ApplicationPath("/api")
|
||||
public class XMageStatsAPIApplication extends Application {
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.xmage.ws.rest.services;
|
||||
|
||||
import com.xmage.ws.resource.XMageStatsResource;
|
||||
import com.xmage.ws.resource.Resource;
|
||||
import com.xmage.ws.rest.services.base.AbstractService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
@Path("/xmage/stats")
|
||||
@Produces("application/json;charset=utf-8")
|
||||
public class XMageStatsService extends AbstractService {
|
||||
|
||||
static final Logger logger = LoggerFactory.getLogger(XMageStatsService.class);
|
||||
|
||||
@GET
|
||||
@Path("/getAll")
|
||||
public Response getAllStats() {
|
||||
logger.trace("getAllStats");
|
||||
Resource resource = new XMageStatsResource().getAll();
|
||||
|
||||
return responseWithError(resource);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.xmage.ws.rest.services.base;
|
||||
|
||||
import com.xmage.ws.json.ResponseBuilder;
|
||||
import com.xmage.ws.model.DomainErrors;
|
||||
import com.xmage.ws.resource.Resource;
|
||||
import net.minidev.json.JSONObject;
|
||||
import org.apache.sling.commons.json.JSONException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* General approach for ws requests/responses.
|
||||
*
|
||||
* Consists of building response object, verifying response, prettifying, execution time calculating.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public abstract class AbstractService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractService.class);
|
||||
|
||||
/**
|
||||
* Create {@link Response} from {@link com.xmage.ws.resource.Resource}
|
||||
*
|
||||
* @param resource Resource to build response based on
|
||||
* @return
|
||||
*/
|
||||
public final Response responseWithError(Resource resource) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
JSONObject response = buildResponse(resource);
|
||||
response = verifyResponse(response);
|
||||
String json = prettifyResponse(response);
|
||||
|
||||
Response responseObject = Response.status(200).entity(json).build();
|
||||
long t2 = System.currentTimeMillis();
|
||||
logger.info("responseWithError time: " + (t2 - t1) + "ms");
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
private JSONObject buildResponse(Resource resource) {
|
||||
JSONObject response = null;
|
||||
try {
|
||||
response = ResponseBuilder.build(resource);
|
||||
} catch (Exception e) {
|
||||
logger.error("responseWithError: ", e);
|
||||
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private String prettifyResponse(JSONObject response) {
|
||||
String json = response.toJSONString();
|
||||
|
||||
try {
|
||||
json = new org.apache.sling.commons.json.JSONObject(json).toString(1);
|
||||
} catch (JSONException jse) {
|
||||
jse.printStackTrace();
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
private JSONObject verifyResponse(JSONObject response) {
|
||||
if (response == null) {
|
||||
logger.error("Something bad happened on response creation");
|
||||
response = ResponseBuilder.build(DomainErrors.Errors.STATUS_SERVER_ERROR.getCode());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
32
Mage.Stats/src/main/java/com/xmage/ws/util/IPHolderUtil.java
Normal file
32
Mage.Stats/src/main/java/com/xmage/ws/util/IPHolderUtil.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
package com.xmage.ws.util;
|
||||
|
||||
/**
|
||||
* Stores ip addresses to allow access from.
|
||||
* Stores user-agents to allow access for.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class IPHolderUtil {
|
||||
|
||||
private static final ThreadLocal<String> ipThreadLocal = new ThreadLocal<String>();
|
||||
private static final ThreadLocal<String> userAgentThreadLocal = new ThreadLocal<String>();
|
||||
|
||||
private IPHolderUtil() {}
|
||||
|
||||
public static void rememberIP(String ip) {
|
||||
ipThreadLocal.set(ip);
|
||||
}
|
||||
|
||||
public static String getRememberedIP() {
|
||||
return ipThreadLocal.get();
|
||||
}
|
||||
|
||||
public static void rememberUserAgent(String userAgent) {
|
||||
userAgentThreadLocal.set(userAgent);
|
||||
}
|
||||
|
||||
public static String getRememberedUserAgent() {
|
||||
return userAgentThreadLocal.get();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.xmage.ws.util.json;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class JSONOperationErrorException extends RuntimeException {
|
||||
|
||||
public JSONOperationErrorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
198
Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONParser.java
Normal file
198
Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONParser.java
Normal file
|
@ -0,0 +1,198 @@
|
|||
package com.xmage.ws.util.json;
|
||||
|
||||
|
||||
import net.minidev.json.JSONArray;
|
||||
import net.minidev.json.JSONObject;
|
||||
import net.minidev.json.JSONValue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Enhances working with json.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class JSONParser {
|
||||
|
||||
public enum CachePolicy {
|
||||
CACHE_ONE_LEVEL_ONLY,
|
||||
CACHE_ALL_LEVELS
|
||||
}
|
||||
|
||||
private static final Map<String, Integer> extendedIndexes = new HashMap<String, Integer>() {{
|
||||
put("$first", 0);
|
||||
put("$second", 1);
|
||||
put("$third", 2);
|
||||
put("$fourth", 3);
|
||||
put("$fifth", 4);
|
||||
}};
|
||||
|
||||
private String json;
|
||||
private JSONObject root;
|
||||
private boolean hitCache;
|
||||
|
||||
private CachePolicy cachePolicy = CachePolicy.CACHE_ONE_LEVEL_ONLY;
|
||||
|
||||
private Map<String, Object> cache = new HashMap<String, Object>();
|
||||
|
||||
public void parseJSON(String jsonString) throws JSONValidationException {
|
||||
parseJSON(jsonString, true);
|
||||
}
|
||||
|
||||
public void parseJSON(String jsonString, boolean validate) throws JSONValidationException {
|
||||
this.json = jsonString;
|
||||
prepare();
|
||||
if (validate) {
|
||||
validate();
|
||||
}
|
||||
}
|
||||
|
||||
public Object get(String path) {
|
||||
return getObject(path);
|
||||
}
|
||||
|
||||
public int getInt(String path) {
|
||||
return (Integer)getObject(path);
|
||||
}
|
||||
|
||||
public int getIntSafe(String path) {
|
||||
if (getObject(path) == null) {
|
||||
return 0;
|
||||
}
|
||||
return (Integer)getObject(path);
|
||||
}
|
||||
|
||||
public String getString(String path) {
|
||||
return (String)getObject(path);
|
||||
}
|
||||
|
||||
public JSONObject getJSON(String path) {
|
||||
return (JSONObject)getObject(path);
|
||||
}
|
||||
|
||||
private Object getObject(String path) {
|
||||
this.hitCache = false;
|
||||
if (cache.containsKey(path)) {
|
||||
this.hitCache = true;
|
||||
return cache.get(path);
|
||||
}
|
||||
String[] params = path.split("\\.");
|
||||
JSONObject json = this.root;
|
||||
JSONArray jsonArray = null;
|
||||
String currentPath = "";
|
||||
for (int i = 0; i < params.length - 1; i++) {
|
||||
String param = params[i];
|
||||
if (cachePolicy.equals(CachePolicy.CACHE_ALL_LEVELS)) {
|
||||
if (!currentPath.isEmpty()) {
|
||||
currentPath += ".";
|
||||
}
|
||||
currentPath += param;
|
||||
}
|
||||
if (param.startsWith("$")) {
|
||||
if (jsonArray == null) {
|
||||
throw new JSONOperationErrorException("Not illegal syntax at this place: " + param);
|
||||
}
|
||||
int index = getIndex(param);
|
||||
json = (JSONObject) jsonArray.get(index);
|
||||
jsonArray = null;
|
||||
} else if (param.contains("[")) {
|
||||
int find = param.indexOf("[");
|
||||
String newParam = param.substring(0, find);
|
||||
String s = param.substring(find+1, param.indexOf("]"));
|
||||
if (s.isEmpty()) {
|
||||
jsonArray = (JSONArray) json.get(newParam);
|
||||
json = null;
|
||||
} else {
|
||||
int index = Integer.parseInt(s);
|
||||
json = (JSONObject)((JSONArray) json.get(newParam)).get(index);
|
||||
jsonArray = null;
|
||||
}
|
||||
} else {
|
||||
Object obj = json.get(param);
|
||||
if (obj instanceof JSONObject) {
|
||||
json = (JSONObject) obj;
|
||||
jsonArray = null;
|
||||
} else if (obj instanceof JSONArray) {
|
||||
jsonArray = (JSONArray) obj;
|
||||
json = null;
|
||||
} else if (obj == null) {
|
||||
throw new IllegalStateException("json object is null");
|
||||
} else {
|
||||
throw new IllegalStateException("json object ('"+param+"') has wrong type: " + obj.getClass());
|
||||
}
|
||||
|
||||
}
|
||||
if (cachePolicy.equals(CachePolicy.CACHE_ALL_LEVELS)) {
|
||||
saveToCache(currentPath, json);
|
||||
}
|
||||
}
|
||||
String name = params[params.length - 1];
|
||||
|
||||
Object value;
|
||||
if (name.startsWith("$")) {
|
||||
if (jsonArray == null) {
|
||||
throw new JSONOperationErrorException("Not illegal syntax at this place: " + name);
|
||||
}
|
||||
int index = getIndex(name);
|
||||
value = jsonArray.get(index);
|
||||
} else {
|
||||
value = json.get(name);
|
||||
}
|
||||
|
||||
saveToCache(path, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private int getIndex(String extendedIndex) {
|
||||
if (extendedIndexes.containsKey(extendedIndex)) {
|
||||
return extendedIndexes.get(extendedIndex);
|
||||
} else {
|
||||
throw new JSONOperationErrorException("Can't parse extended index: " + extendedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveToCache(String path, Object value) {
|
||||
cache.put(path, value);
|
||||
}
|
||||
|
||||
public JSONArray getJSONArray(String path) {
|
||||
return (JSONArray)getObject(path);
|
||||
}
|
||||
|
||||
private void prepare() {
|
||||
reset();
|
||||
if (this.json != null) {
|
||||
this.json = this.json.trim();
|
||||
}
|
||||
}
|
||||
|
||||
private void validate() throws JSONValidationException {
|
||||
if (this.json == null) {
|
||||
throw new JSONValidationException("JSON is null");
|
||||
}
|
||||
try {
|
||||
this.root = (JSONObject) JSONValue.parse(this.json);
|
||||
if (this.root == null) {
|
||||
throw new JSONValidationException("Root json is null");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new JSONValidationException("JSON is not valid", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
this.hitCache = false;
|
||||
this.cachePolicy = CachePolicy.CACHE_ONE_LEVEL_ONLY;
|
||||
this.cache.clear();
|
||||
}
|
||||
|
||||
public boolean isHitCache() {
|
||||
return hitCache;
|
||||
}
|
||||
|
||||
public void setCachePolicy(CachePolicy cachePolicy) {
|
||||
this.cachePolicy = cachePolicy;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.xmage.ws.util.json;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class JSONValidationException extends Exception {
|
||||
|
||||
public JSONValidationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public JSONValidationException(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
}
|
4
Mage.Stats/src/main/resources/META-INF/c3p0.properties
Normal file
4
Mage.Stats/src/main/resources/META-INF/c3p0.properties
Normal file
|
@ -0,0 +1,4 @@
|
|||
###c3p0
|
||||
с3p0.testConnectionOnCheckout=true
|
||||
с3p0.acquireRetryDelay=1000
|
||||
с3p0.acquireRetryAttempts=1
|
21
Mage.Stats/src/main/resources/logback.xml
Normal file
21
Mage.Stats/src/main/resources/logback.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>server.log</file>
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
<appender-ref ref="FILE" />
|
||||
</root>
|
||||
</configuration>
|
0
Mage.Stats/src/main/resources/messages.properties
Normal file
0
Mage.Stats/src/main/resources/messages.properties
Normal file
0
Mage.Stats/src/main/resources/messages_en.properties
Normal file
0
Mage.Stats/src/main/resources/messages_en.properties
Normal file
0
Mage.Stats/src/main/resources/messages_ru.properties
Normal file
0
Mage.Stats/src/main/resources/messages_ru.properties
Normal file
2
Mage.Stats/src/main/resources/xmage.properties
Normal file
2
Mage.Stats/src/main/resources/xmage.properties
Normal file
|
@ -0,0 +1,2 @@
|
|||
db.log.url=jdbc:h2:file:../Mage.Server/db/mage.h2;AUTO_SERVER=TRUE
|
||||
db.feedback.url=jdbc:h2:file:../Mage.Server/db/feedback.h2;AUTO_SERVER=TRUE
|
19
Mage.Stats/src/main/webapp/WEB-INF/web.xml
Normal file
19
Mage.Stats/src/main/webapp/WEB-INF/web.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE web-app PUBLIC
|
||||
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
|
||||
"http://java.sun.com/dtd/web-app_2_3.dtd" >
|
||||
|
||||
<web-app>
|
||||
|
||||
<display-name>XMage Stats Restful Web Application</display-name>
|
||||
|
||||
<filter>
|
||||
<filter-name>IPFilter</filter-name>
|
||||
<filter-class>com.xmage.ws.filter.IPFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>IPFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
</web-app>
|
5
Mage.Stats/src/main/webapp/index.jsp
Normal file
5
Mage.Stats/src/main/webapp/index.jsp
Normal file
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<body>
|
||||
<h2>Hello World!</h2>
|
||||
</body>
|
||||
</html>
|
145
Mage.Stats/src/test/java/com/anygo/ws/json/TestJSONParser.java
Normal file
145
Mage.Stats/src/test/java/com/anygo/ws/json/TestJSONParser.java
Normal file
|
@ -0,0 +1,145 @@
|
|||
package com.anygo.ws.json;
|
||||
|
||||
import com.xmage.ws.util.json.JSONParser;
|
||||
import com.xmage.ws.util.json.JSONValidationException;
|
||||
import junit.framework.Assert;
|
||||
import net.minidev.json.JSONArray;
|
||||
import net.minidev.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class TestJSONParser {
|
||||
|
||||
@Test
|
||||
public void testParse() throws Exception {
|
||||
JSONParser parser = new JSONParser();
|
||||
parser.parseJSON("{}");
|
||||
parser.parseJSON("{\"test\" : 1}");
|
||||
parser.parseJSON("{\"test\" : \"test\"}");
|
||||
parser.parseJSON("{\"list\" : [\"1\", \"2\", \"3\"]}");
|
||||
parser.parseJSON("{test:test}");
|
||||
|
||||
testError(parser, "{");
|
||||
testError(parser, "}");
|
||||
testError(parser, "{{}");
|
||||
testError(parser, "{\"test\" : [}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryForInt() throws Exception {
|
||||
JSONParser parser = new JSONParser();
|
||||
parser.parseJSON("{\"test\" : 1}");
|
||||
Assert.assertEquals(1, parser.getInt("test"));
|
||||
|
||||
parser = new JSONParser();
|
||||
parser.parseJSON("{test : { internal : {level : 2}}}");
|
||||
Assert.assertEquals(2, parser.getInt("test.internal.level"));
|
||||
Assert.assertFalse("No cache should have been used", parser.isHitCache());
|
||||
|
||||
Assert.assertEquals(2, parser.getInt("test.internal.level"));
|
||||
Assert.assertTrue("Cache should have been used this time!", parser.isHitCache());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryForJSONArray() throws Exception {
|
||||
JSONParser parser = new JSONParser();
|
||||
parser.parseJSON("{\"test\" : [\"1\", \"2\", \"3\"]}");
|
||||
Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray);
|
||||
Assert.assertEquals("1", parser.getJSONArray("test").get(0));
|
||||
|
||||
parser = new JSONParser();
|
||||
parser.parseJSON("{\"test\" : [1,2,3]}");
|
||||
Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray);
|
||||
Assert.assertFalse(parser.isHitCache());
|
||||
Assert.assertEquals(2, parser.getJSONArray("test").get(1));
|
||||
Assert.assertTrue(parser.isHitCache());
|
||||
|
||||
Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray);
|
||||
Assert.assertEquals(2, parser.getJSONArray("test").get(1));
|
||||
Assert.assertTrue(parser.isHitCache());
|
||||
|
||||
parser = new JSONParser();
|
||||
parser.parseJSON("{\"test\" : [{second_level: \"3\"}, {\"third_level\" : 2}]}");
|
||||
Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray);
|
||||
Assert.assertTrue(parser.getJSONArray("test").get(0) instanceof JSONObject);
|
||||
Assert.assertEquals(2, parser.getInt("test[1].third_level"));
|
||||
Assert.assertEquals("3", parser.getString("test[0].second_level"));
|
||||
|
||||
parser = new JSONParser();
|
||||
parser.parseJSON("{\"test\" : [{1:1},{1:1},{1:1},{1:1},{1:1},{1:1},{1:1},{1:1},{1:1},{2:3},{4:5}]}");
|
||||
Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray);
|
||||
Assert.assertEquals(5, parser.getInt("test[10].4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
//TODO: implement
|
||||
public void testErrors() throws Exception {
|
||||
//JSONParser parser = new JSONParser();
|
||||
//parser.parseJSON("{test : { internal : {level : \"2\"}}}");
|
||||
//parser.getInt("test.internal.level");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtendedCache() throws Exception {
|
||||
JSONParser parser = new JSONParser();
|
||||
parser.parseJSON("{test : { internal : {level : 2}}}");
|
||||
Assert.assertEquals(2, parser.getInt("test.internal.level"));
|
||||
Assert.assertFalse("No cache should have been used", parser.isHitCache());
|
||||
|
||||
Assert.assertTrue(parser.getJSON("test") instanceof JSONObject);
|
||||
Assert.assertFalse("No cache should have been used", parser.isHitCache());
|
||||
Assert.assertTrue(parser.getJSON("test.internal") instanceof JSONObject);
|
||||
Assert.assertFalse("No cache should have been used", parser.isHitCache());
|
||||
|
||||
parser = new JSONParser();
|
||||
parser.parseJSON("{test : { internal : {level : 2}}}");
|
||||
parser.setCachePolicy(JSONParser.CachePolicy.CACHE_ALL_LEVELS);
|
||||
Assert.assertEquals(2, parser.getInt("test.internal.level"));
|
||||
Assert.assertFalse("No cache should have been used", parser.isHitCache());
|
||||
|
||||
Assert.assertTrue(parser.getJSON("test") instanceof JSONObject);
|
||||
Assert.assertTrue("Cache should have been used this time!", parser.isHitCache());
|
||||
Assert.assertTrue(parser.getJSON("test.internal") instanceof JSONObject);
|
||||
Assert.assertTrue("Cache should have been used this time!", parser.isHitCache());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtendedIndexes() throws Exception {
|
||||
JSONParser parser = new JSONParser();
|
||||
parser.parseJSON("{\"test\" : [1,2,3,4,5]}");
|
||||
Assert.assertEquals(1, parser.getInt("test[].$first"));
|
||||
Assert.assertEquals(2, parser.getInt("test[].$second"));
|
||||
Assert.assertEquals(3, parser.getInt("test[].$third"));
|
||||
Assert.assertEquals(4, parser.getInt("test[].$fourth"));
|
||||
Assert.assertEquals(5, parser.getInt("test[].$fifth"));
|
||||
|
||||
parser = new JSONParser();
|
||||
parser.parseJSON("{\"test\" : [{1:1},{2:2},{3:3},{4:4},{5:5}]}");
|
||||
Assert.assertEquals(1, parser.getInt("test[].$first.1"));
|
||||
Assert.assertEquals(2, parser.getInt("test[].$second.2"));
|
||||
Assert.assertEquals(3, parser.getInt("test[].$third.3"));
|
||||
Assert.assertEquals(4, parser.getInt("test[].$fourth.4"));
|
||||
Assert.assertEquals(5, parser.getInt("test[].$fifth.5"));
|
||||
|
||||
parser = new JSONParser();
|
||||
parser.parseJSON("{\"contacts\": {\"phones\": [\n" +
|
||||
" {\"phone\": \"100000\"},\n" +
|
||||
" {\"phone\": \"+7 999 1234567\"}\n" +
|
||||
" ]}}");
|
||||
|
||||
Assert.assertEquals("100000", parser.getString("contacts.phones[].$first.phone"));
|
||||
|
||||
}
|
||||
|
||||
private void testError(JSONParser parser, String jsonToTest) throws Exception {
|
||||
try {
|
||||
parser.parseJSON(jsonToTest);
|
||||
Assert.assertTrue("Should have thrown an exception", false);
|
||||
} catch (JSONValidationException j) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.anygo.ws.rest;
|
||||
|
||||
import com.xmage.ws.model.DomainErrors;
|
||||
import com.xmage.ws.rest.services.XMageStatsService;
|
||||
import com.xmage.ws.util.json.JSONParser;
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* Testings XMage stats service without need to deploy.
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class XMageStatsServiceTest {
|
||||
|
||||
@Test
|
||||
public void testAddNewAndGet() throws Exception {
|
||||
|
||||
XMageStatsService xMageStatsService = new XMageStatsService();
|
||||
|
||||
Response response = xMageStatsService.getAllStats();
|
||||
|
||||
JSONParser parser = new JSONParser();
|
||||
parser.parseJSON((String) response.getEntity());
|
||||
|
||||
Assert.assertEquals(DomainErrors.Errors.STATUS_OK.getCode(), parser.getInt("code"));
|
||||
System.out.println("response = " + response.getEntity().toString());
|
||||
}
|
||||
|
||||
|
||||
}
|
32
Mage.Stats/src/test/java/com/anygo/ws/util/FileUtil.java
Normal file
32
Mage.Stats/src/test/java/com/anygo/ws/util/FileUtil.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
package com.anygo.ws.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author noxx
|
||||
*/
|
||||
public class FileUtil {
|
||||
|
||||
private FileUtil() {}
|
||||
|
||||
public static String readFile(String file) throws IOException {
|
||||
InputStream in = FileUtil.class.getResourceAsStream(file);
|
||||
if (in == null) {
|
||||
throw new FileNotFoundException("Couldn't find file " + file);
|
||||
}
|
||||
Reader fr = new InputStreamReader(in, "utf-8");
|
||||
|
||||
BufferedReader reader = new BufferedReader(fr);
|
||||
String line;
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String ls = System.getProperty("line.separator");
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
stringBuilder.append(line);
|
||||
stringBuilder.append(ls);
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
1
pom.xml
1
pom.xml
|
@ -53,6 +53,7 @@
|
|||
<module>Mage.Server.Console</module>
|
||||
<module>Mage.Tests</module>
|
||||
<module>Mage.Updater</module>
|
||||
<module>Mage.Stats</module>
|
||||
</modules>
|
||||
|
||||
<repositories>
|
||||
|
|
Loading…
Reference in a new issue