RandomFeature.java
5.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
* Decompiled with CFR 0_118.
*
* Could not load the following classes:
* javax.servlet.Filter
* javax.servlet.FilterChain
* javax.servlet.FilterConfig
* javax.servlet.ServletException
* javax.servlet.ServletRequest
* javax.servlet.ServletResponse
* javax.servlet.http.Cookie
* javax.servlet.http.HttpServletRequest
* javax.servlet.http.HttpServletResponse
* org.apache.felix.scr.annotations.Component
* org.apache.felix.scr.annotations.ConfigurationPolicy
* org.apache.felix.scr.annotations.Properties
* org.apache.felix.scr.annotations.Property
* org.apache.felix.scr.annotations.Service
* org.apache.sling.commons.osgi.PropertiesUtil
* org.apache.sling.featureflags.ExecutionContext
* org.apache.sling.featureflags.Feature
*/
package com.adobe.granite.frags.impl;
import com.adobe.granite.frags.impl.AbstractFeature;
import java.io.IOException;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.featureflags.ExecutionContext;
import org.apache.sling.featureflags.Feature;
@Service(value={Feature.class, Filter.class})
@Properties(value={@Property(name="service.ranking", intValue={200}), @Property(name="feature.name", label="Name", value={"com.adobe.granite.frags.RandomFeature"}), @Property(name="feature.description", label="Description", value={"Displays the feature only for a small percentage of users"})})
@Component(label="Adobe Granite Random Feature Flag", description="Displays the feature only for a small percentage of users", configurationFactory=1, policy=ConfigurationPolicy.REQUIRE, metatype=1)
public final class RandomFeature
extends AbstractFeature
implements Filter {
@Property(label="Active percentage", description="How often this flag returns true, randomly, in percent")
public static String PROP_ACTIVE_PERCENTAGE = "active.percentage";
@Property(label="Cookie name", description="The Cookie name where stored RandomFeature informations", value={"Granite-Random-Feature"})
public static String PROP_COOKIE_NAME = "cookie.name";
@Property(label="Cookie max age", description="The Cookie max age", intValue={Integer.MAX_VALUE})
public static String PROP_COOKIE_MAX_AGE = "cookie.maxAge";
static final String FEATURE_NAME = "com.adobe.granite.frags.RandomFeature";
static final String LABEL = "Adobe Granite Random Feature Flag";
static final String DESCRIPTION = "Displays the feature only for a small percentage of users";
static final String DEFAULT_COOKIE_NAME = "Granite-Random-Feature";
static final int DEFAULT_MAX_AGE = Integer.MAX_VALUE;
private String cookieName;
private int cookieMaxAge;
private double activeRatio;
@Override
protected void configure(Map<String, Object> config) {
this.cookieName = PropertiesUtil.toString((Object)config.get(PROP_COOKIE_NAME), (String)"Granite-Random-Feature");
this.cookieMaxAge = PropertiesUtil.toInteger((Object)config.get(PROP_COOKIE_MAX_AGE), (int)Integer.MAX_VALUE);
this.activeRatio = PropertiesUtil.toDouble((Object)config.get(PROP_ACTIVE_PERCENTAGE), (double)50.0) / 100.0;
}
public boolean isEnabled(ExecutionContext context) {
HttpServletRequest request = context.getRequest();
double assignedRandom = this.getAssignedRandom(request);
return assignedRandom <= this.activeRatio;
}
private double getAssignedRandom(HttpServletRequest request) {
if (request != null) {
String cookieValue = null;
Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length && cookieValue != null; ++i) {
Cookie cookie = cookies[i];
if (!this.cookieName.equals(cookie.getName())) continue;
cookieValue = cookie.getValue();
}
if (cookieValue == null) {
cookieValue = (String)request.getAttribute(this.cookieName);
}
if (cookieValue != null && !cookieValue.isEmpty()) {
return Double.valueOf(cookieValue);
}
}
return Double.MAX_VALUE;
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Cookie[] cookies;
HttpServletRequest servletRequest;
if (request instanceof HttpServletRequest && !RandomFeature.contains(this.cookieName, cookies = (servletRequest = (HttpServletRequest)request).getCookies())) {
String random = String.valueOf(Math.random());
Cookie randomCookie = new Cookie(this.cookieName, random);
randomCookie.setMaxAge(this.cookieMaxAge);
HttpServletResponse servletResponse = (HttpServletResponse)response;
servletResponse.addCookie(randomCookie);
servletRequest.setAttribute(this.cookieName, (Object)random);
}
chain.doFilter(request, response);
}
private static boolean contains(String cookieName, Cookie[] cookies) {
for (Cookie cookie : cookies) {
if (!cookieName.equals(cookie.getName())) continue;
return true;
}
return false;
}
public void destroy() {
}
public String toString() {
return Object.super.toString() + ", active percentage=" + this.activeRatio * 100.0;
}
}