mirror of
https://github.com/magefree/mage.git
synced 2025-12-24 12:31:59 -08: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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue