Commit f6dd9831 by Nepxion

简化服务和网关上下文获取Header的方式

parent f0055103
...@@ -9,10 +9,7 @@ package com.nepxion.discovery.plugin.strategy.gateway.adapter; ...@@ -9,10 +9,7 @@ package com.nepxion.discovery.plugin.strategy.gateway.adapter;
* @version 1.0 * @version 1.0
*/ */
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.server.ServerWebExchange;
import com.nepxion.discovery.common.constant.DiscoveryConstant; import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.plugin.strategy.adapter.AbstractDiscoveryEnabledAdapter; import com.nepxion.discovery.plugin.strategy.adapter.AbstractDiscoveryEnabledAdapter;
...@@ -20,50 +17,21 @@ import com.nepxion.discovery.plugin.strategy.gateway.context.GatewayStrategyCont ...@@ -20,50 +17,21 @@ import com.nepxion.discovery.plugin.strategy.gateway.context.GatewayStrategyCont
import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.Server;
public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdapter { public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdapter {
private static final Logger LOG = LoggerFactory.getLogger(DefaultDiscoveryEnabledAdapter.class);
@Autowired @Autowired
private GatewayStrategyContextHolder gatewayStrategyContextHolder; private GatewayStrategyContextHolder gatewayStrategyContextHolder;
@Override @Override
protected String getVersionValue(Server server) { protected String getVersionValue(Server server) {
ServerWebExchange exchange = gatewayStrategyContextHolder.getExchange(); return gatewayStrategyContextHolder.getHeader(DiscoveryConstant.N_D_VERSION);
if (exchange == null) {
String serviceId = pluginAdapter.getServerServiceId(server);
LOG.warn("The ServerWebExchange object is null, ignore to do version filter for service={}...", serviceId);
return null;
}
return exchange.getRequest().getHeaders().getFirst(DiscoveryConstant.N_D_VERSION);
} }
@Override @Override
protected String getRegionValue(Server server) { protected String getRegionValue(Server server) {
ServerWebExchange exchange = gatewayStrategyContextHolder.getExchange(); return gatewayStrategyContextHolder.getHeader(DiscoveryConstant.N_D_REGION);
if (exchange == null) {
String serviceId = pluginAdapter.getServerServiceId(server);
LOG.warn("The ServerWebExchange object is null, ignore to do region filter for service={}...", serviceId);
return null;
}
return exchange.getRequest().getHeaders().getFirst(DiscoveryConstant.N_D_REGION);
} }
@Override @Override
protected String getAddressValue(Server server) { protected String getAddressValue(Server server) {
ServerWebExchange exchange = gatewayStrategyContextHolder.getExchange(); return gatewayStrategyContextHolder.getHeader(DiscoveryConstant.N_D_ADDRESS);
if (exchange == null) {
String serviceId = pluginAdapter.getServerServiceId(server);
LOG.warn("The ServerWebExchange object is null, ignore to do region filter for service={}...", serviceId);
return null;
}
return exchange.getRequest().getHeaders().getFirst(DiscoveryConstant.N_D_ADDRESS);
} }
} }
\ No newline at end of file
...@@ -9,10 +9,25 @@ package com.nepxion.discovery.plugin.strategy.gateway.context; ...@@ -9,10 +9,25 @@ package com.nepxion.discovery.plugin.strategy.gateway.context;
* @version 1.0 * @version 1.0
*/ */
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
public class GatewayStrategyContextHolder { public class GatewayStrategyContextHolder {
private static final Logger LOG = LoggerFactory.getLogger(GatewayStrategyContextHolder.class);
public ServerWebExchange getExchange() { public ServerWebExchange getExchange() {
return GatewayStrategyContext.getCurrentContext().getExchange(); return GatewayStrategyContext.getCurrentContext().getExchange();
} }
public String getHeader(String name) {
ServerWebExchange exchange = getExchange();
if (exchange == null) {
LOG.warn("The ServerWebExchange object is null");
return null;
}
return exchange.getRequest().getHeaders().getFirst(name);
}
} }
\ No newline at end of file
...@@ -9,10 +9,7 @@ package com.nepxion.discovery.plugin.strategy.service.adapter; ...@@ -9,10 +9,7 @@ package com.nepxion.discovery.plugin.strategy.service.adapter;
* @version 1.0 * @version 1.0
*/ */
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.nepxion.discovery.common.constant.DiscoveryConstant; import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.plugin.strategy.adapter.AbstractDiscoveryEnabledAdapter; import com.nepxion.discovery.plugin.strategy.adapter.AbstractDiscoveryEnabledAdapter;
...@@ -20,50 +17,21 @@ import com.nepxion.discovery.plugin.strategy.service.context.ServiceStrategyCont ...@@ -20,50 +17,21 @@ import com.nepxion.discovery.plugin.strategy.service.context.ServiceStrategyCont
import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.Server;
public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdapter { public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdapter {
private static final Logger LOG = LoggerFactory.getLogger(DefaultDiscoveryEnabledAdapter.class);
@Autowired @Autowired
private ServiceStrategyContextHolder serviceStrategyContextHolder; private ServiceStrategyContextHolder serviceStrategyContextHolder;
@Override @Override
protected String getVersionValue(Server server) { protected String getVersionValue(Server server) {
ServletRequestAttributes attributes = serviceStrategyContextHolder.getRestAttributes(); return serviceStrategyContextHolder.getHeader(DiscoveryConstant.N_D_VERSION);
if (attributes == null) {
String serviceId = pluginAdapter.getServerServiceId(server);
LOG.warn("The ServletRequestAttributes object is null, ignore to do version filter for service={}...", serviceId);
return null;
}
return attributes.getRequest().getHeader(DiscoveryConstant.N_D_VERSION);
} }
@Override @Override
protected String getRegionValue(Server server) { protected String getRegionValue(Server server) {
ServletRequestAttributes attributes = serviceStrategyContextHolder.getRestAttributes(); return serviceStrategyContextHolder.getHeader(DiscoveryConstant.N_D_REGION);
if (attributes == null) {
String serviceId = pluginAdapter.getServerServiceId(server);
LOG.warn("The ServletRequestAttributes object is null, ignore to do region filter for service={}...", serviceId);
return null;
}
return attributes.getRequest().getHeader(DiscoveryConstant.N_D_REGION);
} }
@Override @Override
protected String getAddressValue(Server server) { protected String getAddressValue(Server server) {
ServletRequestAttributes attributes = serviceStrategyContextHolder.getRestAttributes(); return serviceStrategyContextHolder.getHeader(DiscoveryConstant.N_D_ADDRESS);
if (attributes == null) {
String serviceId = pluginAdapter.getServerServiceId(server);
LOG.warn("The ServletRequestAttributes object is null, ignore to do region filter for service={}...", serviceId);
return null;
}
return attributes.getRequest().getHeader(DiscoveryConstant.N_D_ADDRESS);
} }
} }
\ No newline at end of file
...@@ -12,11 +12,15 @@ package com.nepxion.discovery.plugin.strategy.service.context; ...@@ -12,11 +12,15 @@ package com.nepxion.discovery.plugin.strategy.service.context;
import java.util.Map; import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
public class ServiceStrategyContextHolder { public class ServiceStrategyContextHolder {
private static final Logger LOG = LoggerFactory.getLogger(ServiceStrategyContextHolder.class);
public ServletRequestAttributes getRestAttributes() { public ServletRequestAttributes getRestAttributes() {
RequestAttributes requestAttributes = RestStrategyContext.getCurrentContext().getRequestAttributes(); RequestAttributes requestAttributes = RestStrategyContext.getCurrentContext().getRequestAttributes();
if (requestAttributes == null) { if (requestAttributes == null) {
...@@ -29,4 +33,15 @@ public class ServiceStrategyContextHolder { ...@@ -29,4 +33,15 @@ public class ServiceStrategyContextHolder {
public Map<String, Object> getRpcAttributes() { public Map<String, Object> getRpcAttributes() {
return RpcStrategyContext.getCurrentContext().getAttributes(); return RpcStrategyContext.getCurrentContext().getAttributes();
} }
public String getHeader(String name) {
ServletRequestAttributes attributes = getRestAttributes();
if (attributes == null) {
LOG.warn("The ServletRequestAttributes object is null");
return null;
}
return attributes.getRequest().getHeader(name);
}
} }
\ No newline at end of file
...@@ -9,11 +9,6 @@ package com.nepxion.discovery.plugin.strategy.zuul.adapter; ...@@ -9,11 +9,6 @@ package com.nepxion.discovery.plugin.strategy.zuul.adapter;
* @version 1.0 * @version 1.0
*/ */
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import com.nepxion.discovery.common.constant.DiscoveryConstant; import com.nepxion.discovery.common.constant.DiscoveryConstant;
...@@ -22,65 +17,21 @@ import com.nepxion.discovery.plugin.strategy.zuul.context.ZuulStrategyContextHol ...@@ -22,65 +17,21 @@ import com.nepxion.discovery.plugin.strategy.zuul.context.ZuulStrategyContextHol
import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.Server;
public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdapter { public class DefaultDiscoveryEnabledAdapter extends AbstractDiscoveryEnabledAdapter {
private static final Logger LOG = LoggerFactory.getLogger(DefaultDiscoveryEnabledAdapter.class);
@Autowired @Autowired
private ZuulStrategyContextHolder zuulStrategyContextHolder; private ZuulStrategyContextHolder zuulStrategyContextHolder;
@Override @Override
protected String getVersionValue(Server server) { protected String getVersionValue(Server server) {
HttpServletRequest request = zuulStrategyContextHolder.getRequest(); return zuulStrategyContextHolder.getHeader(DiscoveryConstant.N_D_VERSION);
if (request == null) {
String serviceId = pluginAdapter.getServerServiceId(server);
LOG.warn("The HttpServletRequest object is null, ignore to do version filter for service={}...", serviceId);
return null;
}
String version = request.getHeader(DiscoveryConstant.N_D_VERSION);
if (StringUtils.isEmpty(version)) {
version = zuulStrategyContextHolder.getZuulRequestHeaders().get(DiscoveryConstant.N_D_VERSION);
}
return version;
} }
@Override @Override
protected String getRegionValue(Server server) { protected String getRegionValue(Server server) {
HttpServletRequest request = zuulStrategyContextHolder.getRequest(); return zuulStrategyContextHolder.getHeader(DiscoveryConstant.N_D_REGION);
if (request == null) {
String serviceId = pluginAdapter.getServerServiceId(server);
LOG.warn("The HttpServletRequest object is null, ignore to do region filter for service={}...", serviceId);
return null;
}
String region = request.getHeader(DiscoveryConstant.N_D_REGION);
if (StringUtils.isEmpty(region)) {
region = zuulStrategyContextHolder.getZuulRequestHeaders().get(DiscoveryConstant.N_D_REGION);
}
return region;
} }
@Override @Override
protected String getAddressValue(Server server) { protected String getAddressValue(Server server) {
HttpServletRequest request = zuulStrategyContextHolder.getRequest(); return zuulStrategyContextHolder.getHeader(DiscoveryConstant.N_D_ADDRESS);
if (request == null) {
String serviceId = pluginAdapter.getServerServiceId(server);
LOG.warn("The HttpServletRequest object is null, ignore to do region filter for service={}...", serviceId);
return null;
}
String address = request.getHeader(DiscoveryConstant.N_D_ADDRESS);
if (StringUtils.isEmpty(address)) {
address = zuulStrategyContextHolder.getZuulRequestHeaders().get(DiscoveryConstant.N_D_ADDRESS);
}
return address;
} }
} }
\ No newline at end of file
...@@ -14,9 +14,15 @@ import java.util.Map; ...@@ -14,9 +14,15 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.context.RequestContext;
public class ZuulStrategyContextHolder { public class ZuulStrategyContextHolder {
private static final Logger LOG = LoggerFactory.getLogger(ZuulStrategyContextHolder.class);
public HttpServletRequest getRequest() { public HttpServletRequest getRequest() {
HttpServletRequest request = ZuulStrategyContext.getCurrentContext().getRequest(); HttpServletRequest request = ZuulStrategyContext.getCurrentContext().getRequest();
if (request == null) { if (request == null) {
...@@ -29,4 +35,22 @@ public class ZuulStrategyContextHolder { ...@@ -29,4 +35,22 @@ public class ZuulStrategyContextHolder {
public Map<String, String> getZuulRequestHeaders() { public Map<String, String> getZuulRequestHeaders() {
return RequestContext.getCurrentContext().getZuulRequestHeaders(); return RequestContext.getCurrentContext().getZuulRequestHeaders();
} }
public String getHeader(String name) {
HttpServletRequest request = getRequest();
if (request == null) {
LOG.warn("The HttpServletRequest object is null");
return null;
}
// 来自于外界的Header,例如,从Postman传递过来的Header
String header = request.getHeader(name);
if (StringUtils.isEmpty(header)) {
// 来自于Zuul Filter的Header
header = getZuulRequestHeaders().get(name);
}
return header;
}
} }
\ No newline at end of file
...@@ -15,7 +15,6 @@ import org.apache.commons.lang3.StringUtils; ...@@ -15,7 +15,6 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.server.ServerWebExchange;
import com.nepxion.discovery.plugin.framework.adapter.PluginAdapter; import com.nepxion.discovery.plugin.framework.adapter.PluginAdapter;
import com.nepxion.discovery.plugin.strategy.adapter.DiscoveryEnabledStrategy; import com.nepxion.discovery.plugin.strategy.adapter.DiscoveryEnabledStrategy;
...@@ -40,17 +39,10 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy { ...@@ -40,17 +39,10 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy {
// 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例 // 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例
private boolean applyFromHeader(Server server, Map<String, String> metadata) { private boolean applyFromHeader(Server server, Map<String, String> metadata) {
ServerWebExchange exchange = gatewayStrategyContextHolder.getExchange(); String token = gatewayStrategyContextHolder.getHeader("token");
if (exchange == null) {
return true;
}
String token = exchange.getRequest().getHeaders().getFirst("token");
// String value = exchange.getRequest().getQueryParams().getFirst("value");
String serviceId = pluginAdapter.getServerServiceId(server); String serviceId = pluginAdapter.getServerServiceId(server);
LOG.info("Gateway端负载均衡用户定制触发:serviceId={}, host={}, metadata={}", serviceId, server.toString(), metadata); LOG.info("Gateway端负载均衡用户定制触发:token={}, serviceId={}, metadata={}", token, serviceId, metadata);
String filterToken = "abc"; String filterToken = "abc";
if (StringUtils.isNotEmpty(token) && token.contains(filterToken)) { if (StringUtils.isNotEmpty(token) && token.contains(filterToken)) {
......
...@@ -15,7 +15,6 @@ import org.apache.commons.lang3.StringUtils; ...@@ -15,7 +15,6 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.nepxion.discovery.common.constant.DiscoveryConstant; import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.plugin.framework.adapter.PluginAdapter; import com.nepxion.discovery.plugin.framework.adapter.PluginAdapter;
...@@ -48,17 +47,10 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy { ...@@ -48,17 +47,10 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy {
// 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例 // 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例
private boolean applyFromHeader(Server server, Map<String, String> metadata) { private boolean applyFromHeader(Server server, Map<String, String> metadata) {
ServletRequestAttributes attributes = serviceStrategyContextHolder.getRestAttributes(); String token = serviceStrategyContextHolder.getHeader("token");
if (attributes == null) {
return true;
}
String token = attributes.getRequest().getHeader("token");
// String value = attributes.getRequest().getParameter("value");
String serviceId = pluginAdapter.getServerServiceId(server); String serviceId = pluginAdapter.getServerServiceId(server);
LOG.info("Serivice端负载均衡用户定制触发:serviceId={}, host={}, metadata={}, attributes={}", serviceId, server.toString(), metadata, attributes); LOG.info("Serivice端负载均衡用户定制触发:token={}, serviceId={}, metadata={}", token, serviceId, metadata);
String filterServiceId = "discovery-springcloud-example-c"; String filterServiceId = "discovery-springcloud-example-c";
String filterToken = "123"; String filterToken = "123";
...@@ -79,7 +71,7 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy { ...@@ -79,7 +71,7 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy {
String serviceId = pluginAdapter.getServerServiceId(server); String serviceId = pluginAdapter.getServerServiceId(server);
String version = metadata.get(DiscoveryConstant.VERSION); String version = metadata.get(DiscoveryConstant.VERSION);
LOG.info("Serivice端负载均衡用户定制触发:serviceId={}, host={}, metadata={}, attributes={}", serviceId, server.toString(), metadata, attributes); LOG.info("Serivice端负载均衡用户定制触发:attributes={}, serviceId={}, metadata={}", attributes, serviceId, metadata);
String filterServiceId = "discovery-springcloud-example-b"; String filterServiceId = "discovery-springcloud-example-b";
String filterVersion = "1.0"; String filterVersion = "1.0";
......
...@@ -11,8 +11,6 @@ package com.nepxion.discovery.plugin.example.zuul.impl; ...@@ -11,8 +11,6 @@ package com.nepxion.discovery.plugin.example.zuul.impl;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -41,22 +39,10 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy { ...@@ -41,22 +39,10 @@ public class MyDiscoveryEnabledStrategy implements DiscoveryEnabledStrategy {
// 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例 // 根据Rest调用传来的Header参数(例如Token),选取执行调用请求的服务实例
private boolean applyFromHeader(Server server, Map<String, String> metadata) { private boolean applyFromHeader(Server server, Map<String, String> metadata) {
HttpServletRequest request = zuulStrategyContextHolder.getRequest(); String token = zuulStrategyContextHolder.getHeader("token");
if (request == null) {
return true;
}
// 来自于外界的Header,例如,从Postman传递过来的Header
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
// 来自于Zuul Filter的Header
token = zuulStrategyContextHolder.getZuulRequestHeaders().get("token");
}
// String value = request.getParameter("value");
String serviceId = pluginAdapter.getServerServiceId(server); String serviceId = pluginAdapter.getServerServiceId(server);
LOG.info("Zuul端负载均衡用户定制触发:serviceId={}, host={}, metadata={}", serviceId, server.toString(), metadata); LOG.info("Zuul端负载均衡用户定制触发:token={}, serviceId={}, metadata={}", token, serviceId, metadata);
String filterToken = "abc"; String filterToken = "abc";
if (StringUtils.isNotEmpty(token) && token.contains(filterToken)) { if (StringUtils.isNotEmpty(token) && token.contains(filterToken)) {
......
...@@ -9,11 +9,9 @@ package com.nepxion.discovery.plugin.example.zuul.impl; ...@@ -9,11 +9,9 @@ package com.nepxion.discovery.plugin.example.zuul.impl;
* @version 1.0 * @version 1.0
*/ */
import org.apache.commons.lang3.StringUtils;
import com.nepxion.discovery.common.constant.DiscoveryConstant; import com.nepxion.discovery.common.constant.DiscoveryConstant;
import com.nepxion.discovery.plugin.strategy.zuul.filter.ZuulStrategyFilterResolver;
import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
public class MyZuulFilter extends ZuulFilter { public class MyZuulFilter extends ZuulFilter {
@Override @Override
...@@ -33,12 +31,7 @@ public class MyZuulFilter extends ZuulFilter { ...@@ -33,12 +31,7 @@ public class MyZuulFilter extends ZuulFilter {
@Override @Override
public Object run() { public Object run() {
RequestContext context = RequestContext.getCurrentContext(); ZuulStrategyFilterResolver.setHeader(DiscoveryConstant.N_D_VERSION, "{\"discovery-springcloud-example-a\":\"1.0\", \"discovery-springcloud-example-b\":\"1.0\", \"discovery-springcloud-example-c\":\"1.0;1.2\"}");
// 来自于外界的Header,例如,从Postman传递过来的Header
String version = context.getRequest().getHeader(DiscoveryConstant.N_D_VERSION);
if (StringUtils.isEmpty(version)) {
context.addZuulRequestHeader(DiscoveryConstant.N_D_VERSION, "{\"discovery-springcloud-example-a\":\"1.0\", \"discovery-springcloud-example-b\":\"1.0\", \"discovery-springcloud-example-c\":\"1.0;1.2\"}");
}
return null; return null;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment