提交 a4486c17 编写于 作者: Y yong.you

Merge branch 'biz' of github.com:dianping/cat into biz

......@@ -14,7 +14,7 @@
<dependencies>
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-core</artifactId>
<artifactId>cat-client</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
......
......@@ -34,7 +34,7 @@ public class ABTestSampleServlet extends HttpServlet {
}
public static enum MyABTestId implements ABTestName {
CASE1("demo1");
CASE1("SampleTest");
private String m_id;
......
......@@ -5,40 +5,37 @@ import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.unidal.helper.Splitters;
import org.unidal.lookup.annotation.Inject;
import org.unidal.lookup.util.StringUtils;
import com.dianping.cat.abtest.spi.ABTestContext;
import com.dianping.cat.abtest.spi.ABTestEntity;
import com.dianping.cat.abtest.spi.ABTestGroupStrategy;
public class IPDistributionStrategy implements ABTestGroupStrategy {
public static final String ID = "ip-distribution";
public IPDistributionStrategy(){
public IPDistributionStrategy() {
System.out.println("new " + ID + " created");
}
@Inject("IP")
private String m_ipAddress;
private List<String> m_ips;
@Override
public void apply(ABTestContext ctx) {
ABTestEntity entity = ctx.getEntity();
String config = entity.getGroupStrategyConfiguration();
List<String> ips = Splitters.by(',').trim().noEmptyItem().split(config);
HttpServletRequest req = ctx.getHttpServletRequest();
String address = getRemoteAddr(req);
String group = ctx.getCookielet("ab");
if(group != null && group.equals("A")){
ctx.setGroupName("A");
}else{
for (String ip : ips) {
if (ip.equals(address)) {
ctx.setGroupName("A");
ctx.setCookielet("ab", "A");
ctx.setCookielet("hit", "1");
return;
}
for (String ip : m_ips) {
if (ip.equals(address)) {
ctx.setGroupName("A");
return;
}
}
ctx.setGroupName("B");
}
public String getRemoteAddr(HttpServletRequest req) {
......@@ -58,7 +55,7 @@ public class IPDistributionStrategy implements ABTestGroupStrategy {
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = req.getRemoteAddr();
if(ip.equals("127.0.0.1") || ip.startsWith("0:0:0:0:0:0:0:1")){
if (ip.equals("127.0.0.1") || ip.startsWith("0:0:0:0:0:0:0:1")) {
ip = IPUtils.getFirstNoLoopbackIP4Address();
}
}
......@@ -67,6 +64,7 @@ public class IPDistributionStrategy implements ABTestGroupStrategy {
}
@Override
public void init(ABTestEntity entity) {
}
public void init() {
m_ips = Splitters.by(',').trim().noEmptyItem().split(m_ipAddress);
}
}
<config mode="client" xmlns:xsi="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="config.xsd">
<domain id="Cat"/>
<domain id="TuanGouWeb"/>
</config>
......@@ -16,6 +16,11 @@
<artifactId>foundation-service</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>java-fragment</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
......@@ -55,8 +60,7 @@
<manifest>
${basedir}/src/main/resources/META-INF/dal/model/client-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/status-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/abtest-manifest.xml,
</manifest>
${basedir}/src/main/resources/META-INF/dal/model/abtest-manifest.xml,</manifest>
</configuration>
</execution>
<execution>
......@@ -69,6 +73,16 @@
<className>com.dianping.cat.build.ComponentsConfigurator</className>
</configuration>
</execution>
<execution>
<id>generate dal model files</id>
<phase>generate-sources</phase>
<goals>
<goal>dal-model</goal>
</goals>
<configuration>
<manifest><![CDATA[${basedir}/src/main/resources/META-INF/dal/model/abtest-manifest.xml,]]></manifest>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
......
......@@ -3,6 +3,8 @@ package com.dianping.cat.abtest.repository;
import java.util.Map;
import java.util.Set;
import javax.script.Invocable;
import com.dianping.cat.abtest.spi.ABTestEntity;
public interface ABTestEntityRepository {
......@@ -10,5 +12,7 @@ public interface ABTestEntityRepository {
public Set<String> getActiveRuns();
public Invocable getInvocable(int runID);
public String getAbtestModel();
}
package com.dianping.cat.abtest.repository;
import com.dianping.cat.abtest.model.entity.Field;
import com.dianping.cat.abtest.model.entity.GroupstrategyDescriptor;
import com.dianping.cat.abtest.spi.ABTestGroupStrategy;
public class FieldInjectUtil {
public void inject(ABTestGroupStrategy targetGroupStrategy, GroupstrategyDescriptor descriptor) throws Exception {
for (Field field : descriptor.getFields()) {
java.lang.reflect.Field modifiersField = targetGroupStrategy.getClass().getDeclaredField(
field.getModifierName());
modifiersField.setAccessible(true);
if (field.getType().equals("String")) {
modifiersField.set(targetGroupStrategy, field.getValue());
} else if (field.getType().equals("int") || field.getType().equals("Integer")) {
modifiersField.setInt(targetGroupStrategy, Integer.parseInt(field.getValue()));
} else if (field.getType().equals("boolean") || field.getType().equals("Boolean")) {
modifiersField.setBoolean(targetGroupStrategy, Boolean.parseBoolean(field.getValue()));
} else if (field.getType().equals("long") || field.getType().equals("Long")) {
modifiersField.setLong(targetGroupStrategy, Long.parseLong(field.getValue()));
} else if (field.getType().equals("double") || field.getType().equals("Double")) {
modifiersField.setDouble(targetGroupStrategy, Double.parseDouble(field.getValue()));
} else if (field.getType().equals("float") || field.getType().equals("Float")) {
modifiersField.setFloat(targetGroupStrategy, Float.parseFloat(field.getValue()));
} else {
modifiersField.set(targetGroupStrategy, field.getValue());
}
}
}
}
package com.dianping.cat.abtest.repository;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.LockSupport;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.unidal.helper.Files;
......@@ -32,18 +36,28 @@ public class HttpABTestEntityRepository extends ContainerHolder implements ABTes
@Inject
private ClientConfigManager m_configManager;
private String m_domain;
@Inject
private int m_refreshTimeInSeconds = 60; // seconds
private Map<String, ABTestEntity> m_entities = new HashMap<String, ABTestEntity>();
private Map<String, ABTestEntity> m_entities = new ConcurrentHashMap<String, ABTestEntity>();
private Set<String> m_activeRuns = new HashSet<String>();
private Set<String> m_activeRuns = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
@Inject
private int m_refreshTimeInSeconds = 60; // seconds
private Map<Integer, ABTestGroupStrategy> m_strategies = new ConcurrentHashMap<Integer, ABTestGroupStrategy>();
private String m_abtestModel;
private Map<Integer, Invocable> m_invokeMap = new ConcurrentHashMap<Integer, Invocable>();
private FieldInjectUtil m_fieldInjector = new FieldInjectUtil();
private ScriptEngineManager m_mgr;
private Map<String, ABTestGroupStrategy> m_strategies = new HashMap<String, ABTestGroupStrategy>();
private ScriptEngine m_engine;
private String m_domain;
private long m_lastUpdateTime = -1;
private String m_abtestModel;
@Override
public Map<String, ABTestEntity> getCurrentEntities() {
......@@ -55,34 +69,42 @@ public class HttpABTestEntityRepository extends ContainerHolder implements ABTes
return getClass().getSimpleName();
}
public Invocable getInvocable(int runID) {
return m_invokeMap.get(runID);
}
@Override
public void initialize() throws InitializationException {
m_domain = m_configManager.getDomain().getId();
m_mgr = new ScriptEngineManager();
m_engine = m_mgr.getEngineByExtension("java");
}
private void refresh() {
m_abtestModel = null;
for (Server server : m_configManager.getServers()) {
String ip = server.getIp();
int port = server.getHttpPort();
String url = String.format("http://%s:%s/cat/s/abtest?op=model", ip, port);
String url = String.format("http://%s:%s/cat/s/abtest?op=model&lastUpdateTime=%s", ip, port, m_lastUpdateTime);
Transaction t = Cat.newTransaction("ABTest", url);
try {
InputStream inputStream = Urls.forIO().connectTimeout(300).readTimeout(2000).openStream(url);
String content = Files.forIO().readFrom(inputStream, "utf-8");
AbtestModel abtest = DefaultSaxParser.parse(content);
ABTestVisitor visitor = new ABTestVisitor(m_domain);
abtest.accept(visitor);
if (abtest.getCases() != null && abtest.getCases().size() > 0) {
ABTestVisitor visitor = new ABTestVisitor(m_domain);
// switch the entities
m_entities = visitor.getEntities();
m_activeRuns = visitor.getActiveRuns();
m_abtestModel = abtest.toString();
break;
abtest.accept(visitor);
// switch the entities
m_entities = visitor.getEntities();
m_activeRuns = visitor.getActiveRuns();
m_abtestModel = abtest.toString();
break;
}
} catch (Throwable e) {
t.setStatus(e);
Cat.logError(e);
......@@ -124,8 +146,6 @@ public class HttpABTestEntityRepository extends ContainerHolder implements ABTes
public ABTestVisitor(String domain) {
m_domain = domain;
m_entities = new HashMap<String, ABTestEntity>();
m_activeRuns = new HashSet<String>();
}
public Map<String, ABTestEntity> getEntities() {
......@@ -138,44 +158,62 @@ public class HttpABTestEntityRepository extends ContainerHolder implements ABTes
private void prepareEntity(Case _case, Run run) {
ABTestEntity entity = new ABTestEntity(_case, run);
String strategyKey = String.format("%s:%s:%s", _case.getId(), entity.getGroupStrategyName(),
entity.getGroupStrategyConfiguration());
ABTestGroupStrategy strategy = m_strategies.get(strategyKey);
if (strategy != null) {
entity.setGroupStrategy(strategy);
} else {
try {
strategy = lookup(ABTestGroupStrategy.class, entity.getGroupStrategyName());
strategy.init(entity);
try {
if (m_strategies.get(run.getId()) != null && m_lastUpdateTime >= run.getLastModifiedDate().getTime()) {
entity.setGroupStrategy(m_strategies.get(run.getId()));
} else {
ABTestGroupStrategy strategy = lookup(ABTestGroupStrategy.class, entity.getGroupStrategyName());
m_fieldInjector.inject(strategy, run.getGroupstrategyDescriptor());
strategy.init();
entity.setGroupStrategy(strategy);
m_strategies.put(run.getId(), strategy);
}
m_strategies.put(strategyKey, strategy);
} catch (Exception e) {
Cat.logError(e);
if (m_invokeMap.get(run.getId()) != null && m_lastUpdateTime >= run.getLastModifiedDate().getTime()) {
entity.setInvocable(m_invokeMap.get(run.getId()));
} else {
String javaFragement = run.getConditionsFragement();
ABTestEntity origin = HttpABTestEntityRepository.this.m_entities.get(_case.getId());
Invocable inv = (Invocable) m_engine.eval(javaFragement);
entity.setInvocable(inv);
m_invokeMap.put(run.getId(), inv);
}
if (origin != null) {
entity = origin;
} else {
entity.setDisabled(true);
}
} catch (Throwable e) {
Cat.logError(e);
ABTestEntity origin = m_entities.get(_case.getName());
if (origin != null) {
entity = origin;
} else {
entity.setDisabled(true);
}
} finally {
m_entities.put(entity.getName(), entity);
}
m_entities.put(entity.getName(), entity);
}
@Override
public void visitCase(Case _case) {
long maxUpdateTime = -1;
for (Run run : _case.getRuns()) {
m_activeRuns.add(String.valueOf(run.getId()));
if (run.getDomains() != null && run.getDomains().contains(m_domain)) {
prepareEntity(_case, run);
if (run.getLastModifiedDate().getTime() > maxUpdateTime) {
maxUpdateTime = run.getLastModifiedDate().getTime();
}
}
}
if (maxUpdateTime > m_lastUpdateTime) {
m_lastUpdateTime = maxUpdateTime;
}
}
}
......
......@@ -4,7 +4,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface ABTestContext {
public final String DEFAULT_GROUP = "";
public final String DEFAULT_GROUP = "Control";
public ABTestEntity getEntity();
......
package com.dianping.cat.abtest.spi;
import java.util.Date;
import java.util.List;
import javax.script.Invocable;
import com.dianping.cat.abtest.model.entity.Case;
import com.dianping.cat.abtest.model.entity.Condition;
import com.dianping.cat.abtest.model.entity.ConversionRule;
import com.dianping.cat.abtest.model.entity.GroupstrategyDescriptor;
import com.dianping.cat.abtest.model.entity.Run;
import com.dianping.cat.abtest.spi.internal.ABTestCodec;
import com.dianping.cat.message.spi.MessageManager;
public class ABTestEntity {
......@@ -12,6 +20,12 @@ public class ABTestEntity {
private Run m_run;
private ABTestGroupStrategy m_groupStrategy;
private Invocable m_invocable;
private MessageManager m_messageManager;
private ABTestCodec m_cookieCodec;
private String m_groupStrategyName;
......@@ -27,35 +41,51 @@ public class ABTestEntity {
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ABTestEntity other = (ABTestEntity) obj;
if (m_groupStrategy == null) {
if (other.m_groupStrategy != null)
return false;
} else if (!m_groupStrategy.equals(other.m_groupStrategy))
return false;
if (m_groupStrategyName == null) {
if (other.m_groupStrategyName != null)
return false;
} else if (!m_groupStrategyName.equals(other.m_groupStrategyName))
return false;
if (m_name == null) {
if (other.m_name != null)
return false;
} else if (!m_name.equals(other.m_name))
return false;
if (m_run == null) {
if (other.m_run != null)
return false;
} else if (!m_run.equals(other.m_run))
return false;
return true;
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ABTestEntity other = (ABTestEntity) obj;
if (m_groupStrategy == null) {
if (other.m_groupStrategy != null)
return false;
} else if (!m_groupStrategy.equals(other.m_groupStrategy))
return false;
if (m_groupStrategyName == null) {
if (other.m_groupStrategyName != null)
return false;
} else if (!m_groupStrategyName.equals(other.m_groupStrategyName))
return false;
if (m_name == null) {
if (other.m_name != null)
return false;
} else if (!m_name.equals(other.m_name))
return false;
if (m_run == null) {
if (other.m_run != null)
return false;
} else if (!m_run.equals(other.m_run))
return false;
return true;
}
public List<Condition> getConditions() {
return m_run.getConditions() != null ? m_run.getConditions() : null;
}
public String getConditionsFragement() {
return m_run.getConditionsFragement();
}
public List<ConversionRule> getConversionRules() {
return m_run.getConversionRules();
}
public ABTestCodec getCookieCodec() {
return m_cookieCodec;
}
public Date getEndDate() {
......@@ -66,14 +96,22 @@ public class ABTestEntity {
return m_groupStrategy;
}
public String getGroupStrategyConfiguration() {
return m_run.getGroupStrategyConfiguration() != null ? m_run.getGroupStrategyConfiguration() : null;
public GroupstrategyDescriptor getGroupStrategyDescriptor() {
return m_run.getGroupstrategyDescriptor() != null ? m_run.getGroupstrategyDescriptor() : null;
}
public String getGroupStrategyName() {
return m_groupStrategyName != null ? m_groupStrategyName : null;
}
public Invocable getInvocable() {
return m_invocable;
}
public MessageManager getMessageManager() {
return m_messageManager;
}
public String getName() {
return m_name;
}
......@@ -87,20 +125,20 @@ public class ABTestEntity {
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((m_groupStrategy == null) ? 0 : m_groupStrategy.hashCode());
result = prime * result + ((m_groupStrategyName == null) ? 0 : m_groupStrategyName.hashCode());
result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
result = prime * result + ((m_run == null) ? 0 : m_run.hashCode());
return result;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((m_groupStrategy == null) ? 0 : m_groupStrategy.hashCode());
result = prime * result + ((m_groupStrategyName == null) ? 0 : m_groupStrategyName.hashCode());
result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
result = prime * result + ((m_run == null) ? 0 : m_run.hashCode());
return result;
}
public boolean isDisabled() {
return m_run.isDisabled();
}
public boolean isEligible(Date date) {
if (m_run.isDisabled()) {
return false;
......@@ -123,6 +161,10 @@ public class ABTestEntity {
return true;
}
public void setCookieCodec(ABTestCodec cookieCodec) {
m_cookieCodec = cookieCodec;
}
public void setDisabled(boolean disabled) {
m_run.setDisabled(disabled);
}
......@@ -131,13 +173,21 @@ public class ABTestEntity {
m_groupStrategy = groupStrategy;
}
public void setName(String name) {
m_name = name;
public void setInvocable(Invocable invocable) {
m_invocable = invocable;
}
public void setMessageManager(MessageManager messageManager) {
m_messageManager = messageManager;
}
public void setName(String name) {
m_name = name;
}
@Override
public String toString() {
return "ABTestEntity [m_name=" + m_name + ", m_groupStrategyName=" + m_groupStrategyName + ", m_run=" + m_run
+ ", m_groupStrategy=" + m_groupStrategy + "]";
}
public String toString() {
return "ABTestEntity [m_name=" + m_name + ", m_groupStrategyName=" + m_groupStrategyName + ", m_run=" + m_run
+ ", m_groupStrategy=" + m_groupStrategy + "]";
}
}
\ No newline at end of file
......@@ -3,5 +3,5 @@ package com.dianping.cat.abtest.spi;
public interface ABTestGroupStrategy {
public void apply(ABTestContext ctx);
public void init(ABTestEntity entity);
public void init();
}
\ No newline at end of file
......@@ -5,8 +5,11 @@ import java.util.Set;
public interface ABTestCodec {
public String encode(Map<String, Map<String, String>> map);
public String encode(String runId, Map<String, String> map);
public Map<String, String> decode(String value);
public Map<String, Map<String, String>> decode(String value, Set<String> keys);
}
......@@ -12,13 +12,18 @@ public class DefaultABTestCodec implements ABTestCodec {
@Override
protected boolean removeEldestEntry(Entry<String, Map<String, String>> arg0) {
return true;
return size() >= 1000;
}
};
public Map<String, Map<String, String>> decode(String value, Set<String> keys) {
int len = value.length();
Map<String, Map<String, String>> map = new LinkedHashMap<String, Map<String, String>>();
if (len == 0) {
return map;
}
StringBuilder key = new StringBuilder();
StringBuilder name = new StringBuilder();
StringBuilder val = new StringBuilder();
......@@ -120,25 +125,41 @@ public class DefaultABTestCodec implements ABTestCodec {
sb.append('&');
}
boolean first2 = true;
String part = encode(runId, cookielets);
sb.append(part);
}
return sb.toString();
}
@Override
public String encode(String runId, Map<String, String> map) {
StringBuilder sb;
if (map != null && map.size() > 0) {
sb = new StringBuilder(32);
sb.append(runId).append('=');
} else {
return "";
}
for (Map.Entry<String, String> e : cookielets.entrySet()) {
if (first2) {
first2 = false;
} else {
sb.append('|');
}
boolean first = true;
String key = e.getKey();
String value = e.getValue();
if(value == null){
sb.append(key).append(':');
}else{
sb.append(key).append(':').append(value);
}
for (Map.Entry<String, String> e : map.entrySet()) {
if (first) {
first = false;
} else {
sb.append('|');
}
String key = e.getKey();
String value = e.getValue();
if (value == null) {
sb.append(key).append(':');
} else {
sb.append(key).append(':').append(value);
}
}
......@@ -156,7 +177,7 @@ public class DefaultABTestCodec implements ABTestCodec {
for (Entry<String, Map<String, String>> entry : maps.entrySet()) {
String key = entry.getKey();
Map<String, String> entryValue = entry.getValue();
if (entryValue != null) {
String val = entryValue.get("ab");
......
......@@ -2,17 +2,21 @@ package com.dianping.cat.abtest.spi.internal;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.script.Invocable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dianping.cat.Cat;
import com.dianping.cat.abtest.model.entity.ConversionRule;
import com.dianping.cat.abtest.spi.ABTestContext;
import com.dianping.cat.abtest.spi.ABTestEntity;
import com.dianping.cat.abtest.spi.ABTestGroupStrategy;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.internal.DefaultMessageManager;
public class DefaultABTestContext implements ABTestContext {
private String m_groupName = DEFAULT_GROUP;
......@@ -80,24 +84,35 @@ public class DefaultABTestContext implements ABTestContext {
@Override
public void setGroupName(String groupName) {
m_groupName = groupName;
setCookielet("ab", groupName);
}
public void setGroupStrategy(ABTestGroupStrategy groupStrategy) {
m_groupStrategy = groupStrategy;
}
public void setCookielets(Map<String, String> cookielets) {
m_cookielets = cookielets;
}
public void setup(HttpServletRequest request, HttpServletResponse response, Map<String, String> cookielets) {
m_request = request;
m_response = response;
m_cookielets = cookielets;
if (m_entity.isEligible(new Date())) {
Invocable inv = m_entity.getInvocable();
if (inv != null && m_entity.isEligible(new Date())) {
boolean isAccept = false;
Transaction t = Cat.newTransaction("GroupStrategy", m_entity.getGroupStrategyName());
try {
m_groupStrategy.apply(this);
isAccept = (Boolean) inv.invokeFunction("isEligible", request);
t.setStatus(Message.SUCCESS);
if (isAccept) {
m_groupStrategy.apply(this);
t.setStatus(Message.SUCCESS);
}
} catch (Throwable e) {
t.setStatus(e);
Cat.logError(e);
......@@ -105,5 +120,31 @@ public class DefaultABTestContext implements ABTestContext {
t.complete();
}
}
String actual = (String) request.getAttribute("url-rewrite-original-url");
List<ConversionRule> conversionRules = m_entity.getConversionRules();
if (conversionRules != null) {
for (ConversionRule rule : conversionRules) {
if (actual.equalsIgnoreCase(rule.getText())) {
String key = String.valueOf(m_entity.getRun().getId());
String appendMetricType = m_entity.getCookieCodec().encode(key, m_cookielets);
if (appendMetricType != null && appendMetricType.length() > 0) {
// DefaultMessageManager manager = (DefaultMessageManager) Cat.getManager();
DefaultMessageManager defaultMessageManager = (DefaultMessageManager) m_entity.getMessageManager();
String metricType = defaultMessageManager.getMetricType();
if (metricType != null && metricType.length() > 0) {
defaultMessageManager.setMetricType(metricType + "&" + appendMetricType);
} else {
defaultMessageManager.setMetricType(appendMetricType);
}
}
break;
}
}
}
}
}
......@@ -16,8 +16,6 @@ import com.dianping.cat.abtest.ABTestName;
import com.dianping.cat.abtest.spi.ABTestContext;
import com.dianping.cat.abtest.spi.ABTestEntity;
import com.dianping.cat.abtest.spi.ABTestGroupStrategy;
import com.dianping.cat.message.internal.DefaultMessageManager;
import com.dianping.cat.message.spi.MessageManager;
public class DefaultABTestContextManager extends ContainerHolder implements ABTestContextManager {
private static final String ABTEST_COOKIE_NAME = "ab";
......@@ -25,9 +23,6 @@ public class DefaultABTestContextManager extends ContainerHolder implements ABTe
@Inject
private ABTestEntityManager m_entityManager;
@Inject
private MessageManager m_messageManager;
@Inject
private ABTestCodec m_cookieCodec;
......@@ -49,8 +44,11 @@ public class DefaultABTestContextManager extends ContainerHolder implements ABTe
@Override
public void onRequestBegin(HttpServletRequest request, HttpServletResponse response) {
Entry entry = m_threadLocal.get();
String requestUrl = (String) request.getAttribute("url-rewrite-original-url");
entry.setup(request, response);
if (requestUrl == null || !requestUrl.contains("ajax")) {
entry.setup(request, response);
}
}
@Override
......@@ -145,10 +143,6 @@ public class DefaultABTestContextManager extends ContainerHolder implements ABTe
String newValue = m_cookieCodec.encode(map);
setCookie(request, response, ABTEST_COOKIE_NAME, newValue);
if (newValue != null && newValue.length() > 0) {
((DefaultMessageManager) m_messageManager).setMetricType(newValue);
}
}
}
}
......@@ -13,13 +13,19 @@ import com.dianping.cat.Cat;
import com.dianping.cat.abtest.ABTestName;
import com.dianping.cat.abtest.repository.ABTestEntityRepository;
import com.dianping.cat.abtest.spi.ABTestEntity;
import com.dianping.cat.abtest.spi.ABTestGroupStrategy;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.spi.MessageManager;
public class DefaultABTestEntityManager extends ContainerHolder implements ABTestEntityManager, Initializable {
@Inject
private ABTestEntityRepository m_repository;
@Inject
private MessageManager m_messageManager;
@Inject
private ABTestCodec m_cookieCodec;
@Override
public ABTestEntity getEntity(ABTestName name) {
String id = name.getValue();
......@@ -42,27 +48,24 @@ public class DefaultABTestEntityManager extends ContainerHolder implements ABTes
List<ABTestEntity> entitiesList = new ArrayList<ABTestEntity>();
for (ABTestEntity entity : m_repository.getCurrentEntities().values()) {
entity.setMessageManager(m_messageManager);
entity.setCookieCodec(m_cookieCodec);
entitiesList.add(entity);
}
return entitiesList;
}
public Set<String> getActiveRun(){
public Set<String> getActiveRun() {
return m_repository.getActiveRuns();
}
@Override
public void initialize() throws InitializationException {
for (ABTestEntity entity : m_repository.getCurrentEntities().values()) {
try {
ABTestGroupStrategy groupStrategy = lookup(ABTestGroupStrategy.class, entity.getGroupStrategyName());
entity.setGroupStrategy(groupStrategy);
} catch (Exception e) {
Cat.logError(e);
entity.setDisabled(true);
}
entity.setMessageManager(m_messageManager);
entity.setCookieCodec(m_cookieCodec);
}
}
}
\ No newline at end of file
package com.dianping.cat.abtest.spi.internal.conditions;
import javax.servlet.http.HttpServletRequest;
public interface ABTestCondition {
public boolean accept(HttpServletRequest request);
}
package com.dianping.cat.abtest.spi.internal.groupstrategy;
import org.unidal.lookup.annotation.Inject;
import com.dianping.cat.abtest.spi.ABTestContext;
import com.dianping.cat.abtest.spi.ABTestGroupStrategy;
public class TrafficDistributionGroupStrategy implements ABTestGroupStrategy {
public static final String ID = "OneVariationStrategy";
@Inject("Control")
private int m_percentControl = 50;
@Inject("Variation-A")
private int m_percentA = 50;
private final int m_total = 100;
private int m_scoreControl = 0;
private int m_scoreA = 0;
@Override
public void apply(ABTestContext ctx) {
m_scoreControl += m_percentControl;
m_scoreA += m_percentA;
if (m_scoreA >= m_scoreControl) {
ctx.setGroupName("A");
m_scoreA -= m_total;
} else {
ctx.setGroupName(ABTestContext.DEFAULT_GROUP);
m_scoreControl -= m_total;
}
}
@Override
public void init() {
if ((m_percentA + m_percentControl) > 100) {
m_percentControl = 50;
m_percentA = 50;
}
}
}
......@@ -8,12 +8,14 @@ import org.unidal.lookup.configuration.Component;
import com.dianping.cat.abtest.repository.ABTestEntityRepository;
import com.dianping.cat.abtest.repository.HttpABTestEntityRepository;
import com.dianping.cat.abtest.spi.ABTestGroupStrategy;
import com.dianping.cat.abtest.spi.internal.ABTestCodec;
import com.dianping.cat.abtest.spi.internal.ABTestContextManager;
import com.dianping.cat.abtest.spi.internal.ABTestEntityManager;
import com.dianping.cat.abtest.spi.internal.DefaultABTestCodec;
import com.dianping.cat.abtest.spi.internal.DefaultABTestContextManager;
import com.dianping.cat.abtest.spi.internal.DefaultABTestEntityManager;
import com.dianping.cat.abtest.spi.internal.groupstrategy.TrafficDistributionGroupStrategy;
import com.dianping.cat.configuration.ClientConfigManager;
import com.dianping.cat.message.spi.MessageManager;
......@@ -23,14 +25,16 @@ public class ABTestComponentConfigurator extends AbstractResourceConfigurator {
List<Component> all = new ArrayList<Component>();
all.add(C(ABTestContextManager.class, DefaultABTestContextManager.class) //
.req(ABTestEntityManager.class, MessageManager.class, ABTestCodec.class));
.req(ABTestEntityManager.class, ABTestCodec.class));
all.add(C(ABTestCodec.class, DefaultABTestCodec.class));
all.add(C(ABTestEntityRepository.class, HttpABTestEntityRepository.class) //
.req(ClientConfigManager.class).config(E("refreshTimeInSeconds").value("60")));
all.add(C(ABTestEntityManager.class, DefaultABTestEntityManager.class) //
.req(ABTestEntityRepository.class));
.req(ABTestEntityRepository.class, MessageManager.class,ABTestCodec.class));
all.add(C(ABTestGroupStrategy.class, TrafficDistributionGroupStrategy.ID, TrafficDistributionGroupStrategy.class));
return all;
}
......
......@@ -37,7 +37,8 @@ public class CatFilter implements Filter {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
Context ctx = new Context((HttpServletRequest) request, (HttpServletResponse) response, chain, m_handlers);
ctx.handle();
......@@ -247,15 +248,27 @@ public class CatFilter implements Filter {
@Override
public void handle(Context ctx) throws IOException, ServletException {
if (ctx.isTop()) {
HttpServletRequest req = ctx.getRequest();
HttpServletResponse res = ctx.getResponse();
ABTestManager.onRequestBegin(req, res);
DefaultMessageManager manager = (DefaultMessageManager) Cat.getManager();
String metricType = manager.getMetricType();
if (metricType != null && metricType.length() > 0) {
Cat.logEvent(ctx.getType(), "ABTest", Message.SUCCESS, metricType);
}
try {
ctx.handle();
} finally {
ABTestManager.onRequestEnd();
}
} else {
ctx.handle();
}
ctx.handle();
}
},
......
......@@ -18,10 +18,39 @@
<attribute name="id" value-type="int" />
<attribute name="start-date" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<attribute name="end-date" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<attribute name="created-date" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<attribute name="last-modified-date" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<attribute name="disabled" value-type="boolean" />
<element name="creator" value-type="String" />
<element name="domain" value-type="String" type="list" names="domains" />
<element name="group-strategy-configuration" value-type="String" />
<element name="conditions-fragement" value-type="String" />
<entity-ref name="conversion-rule" type="list" names="conversion-rules" xml-indent="true" />
<entity-ref name="condition" type="list" names="conditions" xml-indent="true" />
<entity-ref name="groupstrategy-descriptor" />
</entity>
<entity name="conversion-rule">
<attribute name="name" value-type="String" />
<element name="text" value-type="String" text="true" />
</entity>
<entity name="condition">
<attribute name="name" value-type="String" />
<attribute name="seq" value-type="int" />
<attribute name="operator" value-type="String" />
<attribute name="comparator" value-type="int" />
<element name="text" value-type="String" text="true" />
</entity>
<entity name="groupstrategy-descriptor">
<attribute name="name" value-type="String" />
<attribute name="className" value-type="String" />
<attribute name="fullyQualifiedName" value-type="String" />
<entity-ref name="field" type="list" names="fields" xml-indent="true" />
</entity>
<entity name="field">
<attribute name="name" value-type="String" />
<attribute name="type" value-type="String" />
<attribute name="input-type" value-type="String" />
<attribute name="modifier-name" value-type="String" />
<element name="text" value-type="String" text="true" />
</entity>
</model>
<?xml version="1.0" encoding="UTF-8"?>
<model model-package="com.dianping.cat.abtest.model" enable-sax-parser="true" enable-base-visitor="true">
<model model-package="com.dianping.cat.abtest.model" enable-sax-parser="true" enable-base-visitor="true" enable-json-builder="true">
<entity name="case">
<attribute name="id" value-type="int" key="true" primitive="true"/>
<element name="domain" value-type="String" type="set" names="domains" />
......@@ -8,5 +8,16 @@
<attribute name="id" value-type="int" key="true" primitive="true"/>
<element name="domain" value-type="String" type="set" names="domains" />
</entity>
<entity name="field">
<attribute name="name" value-type="String" />
<attribute name="type" value-type="String" default-value="String" />
<attribute name="input-type" value-type="String" default-value="input" />
<element name="text" value-type="String" text="true" alias="value"/>
</entity>
<entity name="condition">
<attribute name="seq" value-type="int" key="true" primitive="true"/>
<attribute name="comparator" value-type="int" default-value="1" />
<attribute name="operator" value-type="String" default-value="and" />
</entity>
</model>
......@@ -137,9 +137,6 @@
<requirement>
<role>com.dianping.cat.abtest.spi.internal.ABTestEntityManager</role>
</requirement>
<requirement>
<role>com.dianping.cat.message.spi.MessageManager</role>
</requirement>
<requirement>
<role>com.dianping.cat.abtest.spi.internal.ABTestCodec</role>
</requirement>
......@@ -168,7 +165,18 @@
<requirement>
<role>com.dianping.cat.abtest.repository.ABTestEntityRepository</role>
</requirement>
<requirement>
<role>com.dianping.cat.message.spi.MessageManager</role>
</requirement>
<requirement>
<role>com.dianping.cat.abtest.spi.internal.ABTestCodec</role>
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.abtest.spi.ABTestGroupStrategy</role>
<role-hint>OneVariationStrategy</role-hint>
<implementation>com.dianping.cat.abtest.spi.internal.groupstrategy.TrafficDistributionGroupStrategy</implementation>
</component>
</components>
</plexus>
......@@ -2,5 +2,5 @@
<wizard package="com.dianping.cat">
<model package="com.dianping.cat.abtest.model" name="abtest">
<sample-model>src/test/resources/com/dianping/cat/abtest/spi/internal/abtest.xml</sample-model>
</model>
</model>
</wizard>
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<?xml version="1.0" encoding="utf-8"?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="status" type="StatusType"/>
<xs:complexType name="StatusType">
<xs:sequence>
......
......@@ -3,7 +3,6 @@ package com.dianping.cat.abtest.demo.roundrobin;
import java.util.concurrent.atomic.AtomicInteger;
import com.dianping.cat.abtest.spi.ABTestContext;
import com.dianping.cat.abtest.spi.ABTestEntity;
import com.dianping.cat.abtest.spi.ABTestGroupStrategy;
public class RoundRobinGroupStrategy implements ABTestGroupStrategy {
......@@ -23,6 +22,6 @@ public class RoundRobinGroupStrategy implements ABTestGroupStrategy {
}
@Override
public void init(ABTestEntity entity) {
public void init() {
}
}
......@@ -15,6 +15,9 @@ public class ABTestContextManagerTest extends ComponentTestCase {
check("1=ab:A|cd:B&2=ab:A|cd:B", "1=ab:A|cd:B&2=ab:A|cd:B");
check("1=ab:|cd:B&2=ab:A|cd:B", "1=ab:|cd:B&2=ab:A|cd:B");
check("1=ab:A|cd:B&2=ab:A|cd:", "1=ab:A|cd:B&2=ab:A|cd:");
check("1=ab:|cd:B&2=ab:A|cd:", "1=ab:|cd:B&2=ab:A|cd:");
check("1=ab:|cd:", "1=ab:|cd:");
check("1=ab:|cd:A", "1=ab:|cd:A");
check("", "");
check("1=ab:A|cd:B&2=ab:A|cd:B", "1=ab:A|cd:B&2=ab:A|cd:B", "1", "2");
......@@ -35,6 +38,9 @@ public class ABTestContextManagerTest extends ComponentTestCase {
check2("1=ab:A&2=ab:A|cd:B", "{1=A, 2=A}");
check2("1=ab:A|cd:B&2=ab:|cd:B", "{1=A, 2=}");
check2("1=cd:B&2=ab:A|cd:B", "{2=A}");
check2("30=l:A|ab:A", "{30=A}");
check2("1=ab:|cd:", "{1=}");
check2("1=ab:|cd:A", "{1=}");
check2("", "{}");
}
......@@ -44,4 +50,20 @@ public class ABTestContextManagerTest extends ComponentTestCase {
Assert.assertEquals(expected, map.toString());
}
@Test
public void testCodec3() throws Exception{
check3("1", "1=ab:A");
}
private void check3(String runId, String source) throws Exception {
ABTestCodec codec = lookup(ABTestCodec.class);
Map<String, Map<String, String>> map = codec.decode(source,null);
System.out.println(map.get(runId));
String actual = codec.encode(runId,map.get(runId));
Assert.assertEquals(source, actual);
}
}
......@@ -45,7 +45,7 @@ public class ABTestEntityManagerTest extends ComponentTestCase {
}
if (expectedGroupStrategy != null) {
Assert.assertEquals(expectedGroupStrategyConfiguration, entity.getGroupStrategyConfiguration());
Assert.assertEquals(expectedGroupStrategyConfiguration, entity.getGroupStrategyDescriptor());
}
Assert.assertEquals(expectedEntityName, entity.getName());
......
package com.dianping.cat.abtest.spi.internal;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Test;
import org.xml.sax.SAXException;
import com.dianping.cat.abtest.model.entity.AbtestModel;
import com.dianping.cat.abtest.model.transform.DefaultSaxParser;
public class AbtestModelTest {
@Test
public void test() throws SAXException, IOException {
InputStream in = getClass().getResourceAsStream("abtest.xml");
AbtestModel abtest = DefaultSaxParser.parse(in);
System.out.println(abtest);
}
}
<plexus>
<components>
<component>
<role>com.dianping.cat.abtest.spi.interanl.conditions.ABTestCondition</role>
<role-hint>true</role-hint>
<implementation>com.dianping.cat.abtest.spi.internal.ABTestFilterManagerTest$TestCondition</implementation>
<configuration>
<march>true</march>
</configuration>
</component>
<component>
<role>com.dianping.cat.abtest.spi.interanl.conditions.ABTestCondition</role>
<role-hint>false</role-hint>
<implementation>com.dianping.cat.abtest.spi.internal.ABTestFilterManagerTest$TestCondition</implementation>
<configuration>
<march>false</march>
</configuration>
</component>
</components>
</plexus>
......@@ -7,11 +7,33 @@
<domain>TuanGouWeb</domain>
<domain>TuanGouRemote</domain>
<runs>
<run id="1" start-date="2013-04-10 17:00:00" end-date="2013-12-30 18:00:00" disabled="false">
<run id="1" start-date="2013-04-10 17:00:00" end-date="2013-12-30 18:00:00" created-date="2013-04-10 17:00:00" last-modified-date="2013-04-10 17:00:00" disabled="false">
<creator>hao.zhu@dianping.com</creator>
<domain>TuanGouWeb</domain>
<domain>TuanGouRemote</domain>
<group-strategy-configuration><![CDATA[This is the configuration]]></group-strategy-configuration>
<conditions-fragement><![CDATA[This is value]]></conditions-fragement>
<conversion-rules>
<conversion-rule name="Goal-1"><![CDATA[This is value]]></conversion-rule>
<conversion-rule name="Goal-2"><![CDATA[This is value]]></conversion-rule>
<conversion-rule name="Goal-3"><![CDATA[This is value]]></conversion-rule>
</conversion-rules>
<conditions>
<condition name="url" seq="1" operator="and" comparator="1"><![CDATA[This is value]]></condition>
<condition name="url" seq="1" operator="and" comparator="1"><![CDATA[This is value]]></condition>
</conditions>
<groupstrategy-descriptor name="roundrobin" className="GroupStrategyParser" fullyQualifiedName="com.dianping.cat.system.page.abtest.GroupStrategyParser">
<fields>
<field name="package" type="String" input-type="input" modifier-name="m_package">
<![CDATA[This is value]]>
</field>
<field name="class" type="String" input-type="textarea" modifier-name="m_class">
<![CDATA[This is value]]>
</field>
<field name="inject" type="String" input-type="input" modifier-name="m_inject">
<![CDATA[This is value]]>
</field>
</fields>
</groupstrategy-descriptor>
</run>
<run />
</runs>
......
<?xml version="1.0" encoding="UTF-8"?>
<model>
<entity name="abtest-report" root="true">
<attribute name="runId" value-type="int" />
<attribute name="startTime" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<attribute name="endTime" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<entity-ref name="group" type="list" names="groups" />
</entity>
<entity name="group">
<attribute name="name" value-type="String" />
<entity-ref name="goal" type="list" names="goals" />
</entity>
<entity name="goal">
<attribute name="name" value-type="String" />
<attribute name="type" value-type="String" />
<attribute name="count" value-type="int" />
<attribute name="sum" value-type="int" />
<attribute name="avg" value-type="double" />
</entity>
</model>
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<file path="abtest-report-codegen.xml" />
<file path="abtest-report-model.xml" />
</manifest>
<?xml version="1.0" encoding="UTF-8"?>
<model model-package="com.dianping.cat.advanced.abtest.report"
enable-merger="true" enable-sax-parser="true" enable-native-parser="true"
enable-native-builder="true" enable-base-visitor="true">
<entity name="abtest-report" root="true">
<attribute name="runId" value-type="int" />
<attribute name="startTime" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<attribute name="endTime" value-type="Date" format="yyyy-MM-dd HH:mm:ss" />
<entity-ref name="group" type="list" names="groups" method-find-or-create="true" />
</entity>
<entity name="group">
<attribute name="name" value-type="String" key="true" />
<entity-ref name="goal" type="list" names="goals" method-find-or-create="true"/>
</entity>
<entity name="goal">
<attribute name="name" value-type="String" key="true" />
<attribute name="type" value-type="String" />
<attribute name="count" value-type="int" />
<attribute name="sum" value-type="int" />
<attribute name="avg" value-type="double" />
</entity>
</model>
\ No newline at end of file
......@@ -20,4 +20,6 @@ public class Constants {
public static final String REPORT_UTILIZATION = "utilization";
public static final String REPORT_HEAVY = "heavy";
public static final String ABTEST = "abtest";
}
package com.dianping.cat.abtest.mockit;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import org.unidal.lookup.ComponentTestCase;
import org.unidal.test.mock.HttpServletRequestMock;
import org.unidal.test.mock.HttpServletResponseMock;
import org.xml.sax.SAXException;
import com.dianping.cat.abtest.model.entity.AbtestModel;
import com.dianping.cat.abtest.model.entity.Case;
import com.dianping.cat.abtest.model.entity.Run;
import com.dianping.cat.abtest.model.transform.BaseVisitor;
import com.dianping.cat.abtest.model.transform.DefaultSaxParser;
import com.dianping.cat.abtest.spi.ABTestEntity;
import com.dianping.cat.abtest.spi.ABTestGroupStrategy;
import com.dianping.cat.abtest.spi.internal.DefaultABTestContext;
public class GroupStrategyTester extends ComponentTestCase {
protected int m_id = 1;
protected String m_url = "abtest.xml";
private ABTestEntity m_entity;
private ABTestGroupStrategy m_groupStrategy;
private Map<String, String> m_cookielets = new LinkedHashMap<String, String>();
private boolean isFirst = true;
public void assertGroupStrategy(HttpServletRequest req, HttpServletResponse res,
String expectedGroup) throws IOException, SAXException,Exception{
DefaultABTestContext context = initContext();
if (m_entity.isEligible(new Date())) {
if(isFirst){
m_groupStrategy.init();
isFirst = false;
}
m_groupStrategy.apply(context);
}
Assert.assertEquals(expectedGroup, context.getGroupName());
}
private DefaultABTestContext initContext() throws IOException, SAXException {
ABTestEntity entity = buildEntity();
DefaultABTestContext context = new DefaultABTestContext(entity);
context.setCookielets(m_cookielets);
if (!entity.isDisabled()) {
ABTestGroupStrategy groupStrategy = entity.getGroupStrategy();
context.setGroupStrategy(groupStrategy);
m_groupStrategy = groupStrategy;
}
m_entity = context.getEntity();
return context;
}
private ABTestEntity buildEntity() throws IOException, SAXException {
InputStream in = getClass().getResourceAsStream(m_url);
AbtestModel abtest = DefaultSaxParser.parse(in);
ABTestVisitor visitor = new ABTestVisitor();
abtest.accept(visitor);
return visitor.getEntity();
}
protected void setId(int id) {
m_id = id;
}
protected void setUrl(String url) {
m_url = url;
}
protected HttpServletRequestMock mockHttpRequest(){
return null;
}
protected HttpServletResponseMock mockHttpResponse(){
return null;
}
private class ABTestVisitor extends BaseVisitor {
private ABTestEntity m_entity;
public ABTestEntity getEntity() {
return m_entity;
}
@Override
public void visitCase(Case _case) {
for (Run run : _case.getRuns()) {
if (run.getId() == m_id) {
m_entity = new ABTestEntity(_case, run);
try {
ABTestGroupStrategy strategy = lookup(
ABTestGroupStrategy.class,
m_entity.getGroupStrategyName());
strategy.init();
m_entity.setGroupStrategy(strategy);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
}
......@@ -6,4 +6,7 @@
<model package="com.dianping.cat.configuration.server" name="server">
<sample-model>src/test/resources/com/dianping/cat/message/configuration/server.xml</sample-model>
</model>
<model package="com.dianping.cat.abtest.model" name="abtest">
<sample-model>src/test/resources/com/dianping/cat/abtest/spi/internal/abtest.xml</sample-model>
</model>
</wizard>
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<groupId>com.dianping.cat</groupId>
<artifactId>parent</artifactId>
<version>0.6.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cat-home</artifactId>
<name>cat-home</name>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>foundation-service</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-consumer</artifactId>
</dependency>
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-consumer-advanced</artifactId>
</dependency>
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-hadoop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.unidal.webres</groupId>
<artifactId>WebResServer</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>web-framework</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jsp-api-2.1</artifactId>
<version>6.1.14</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jsp-2.1</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>test-framework</artifactId>
<version>2.0.3-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>dal-jdbc</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.4</version>
</dependency>
</dependencies>
<build>
<finalName>cat</finalName>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<webResources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<targetPath>WEB-INF/classes</targetPath>
</resource>
<resource>
<directory>src/main/webapp</directory>
<filtering>false</filtering>
<includes>
<include>WEB-INF/web.xml</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.unidal.maven.plugins</groupId>
<artifactId>codegen-maven-plugin</artifactId>
<version>2.0.5</version>
<executions>
<execution>
<id>generate plexus component descriptor</id>
<phase>process-classes</phase>
<goals>
<goal>plexus</goal>
</goals>
<configuration>
<className>com.dianping.cat.build.ComponentsConfigurator</className>
<env>dev</env>
</configuration>
</execution>
<execution>
<id>generate dal model files</id>
<phase>generate-sources</phase>
<goals>
<goal>dal-model</goal>
</goals>
<configuration>
<manifest>
${basedir}/src/main/resources/META-INF/dal/model/topology-graph-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/topology-graph-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/info-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/exception-threshold-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/bug-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/bug-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/service-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/heavy-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/utilization-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/utilization-config-manifest.xml,</manifest>
</configuration>
</execution>
<execution>
<id>generate dal jdbc model</id>
<phase>generate-sources</phase>
<goals>
<goal>dal-jdbc</goal>
</goals>
<configuration>
<manifest><![CDATA[${basedir}/src/main/resources/META-INF/dal/jdbc/report-manifest.xml,
<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">
<parent>
<groupId>com.dianping.cat</groupId>
<artifactId>parent</artifactId>
<version>0.6.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cat-home</artifactId>
<name>cat-home</name>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.unidal.eunit</groupId>
<artifactId>EunitTestFwk</artifactId>
<version>1.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>foundation-service</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-consumer</artifactId>
</dependency>
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-consumer-advanced</artifactId>
</dependency>
<dependency>
<groupId>com.dianping.cat</groupId>
<artifactId>cat-hadoop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.unidal.webres</groupId>
<artifactId>WebResServer</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>web-framework</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jsp-api-2.1</artifactId>
<version>6.1.14</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jsp-2.1</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>test-framework</artifactId>
<version>2.0.3-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unidal.framework</groupId>
<artifactId>dal-jdbc</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.4</version>
</dependency>
<dependency>
<groupId>com.google.code.javaparser</groupId>
<artifactId>javaparser</artifactId>
<version>1.0.8</version>
</dependency>
</dependencies>
<build>
<finalName>cat</finalName>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<webResources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<targetPath>WEB-INF/classes</targetPath>
</resource>
<resource>
<directory>src/main/webapp</directory>
<filtering>false</filtering>
<includes>
<include>WEB-INF/web.xml</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.unidal.maven.plugins</groupId>
<artifactId>codegen-maven-plugin</artifactId>
<version>2.0.5</version>
<executions>
<execution>
<id>generate plexus component descriptor</id>
<phase>process-classes</phase>
<goals>
<goal>plexus</goal>
</goals>
<configuration>
<className>com.dianping.cat.build.ComponentsConfigurator</className>
<env>dev</env>
</configuration>
</execution>
<execution>
<id>generate dal model files</id>
<phase>generate-sources</phase>
<goals>
<goal>dal-model</goal>
</goals>
<configuration>
<manifest>
${basedir}/src/main/resources/META-INF/dal/model/topology-graph-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/topology-graph-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/info-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/exception-threshold-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/bug-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/bug-config-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/service-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/heavy-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/utilization-report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/model/utilization-config-manifest.xml,</manifest>
</configuration>
</execution>
<execution>
<id>generate dal jdbc model</id>
<phase>generate-sources</phase>
<goals>
<goal>dal-jdbc</goal>
</goals>
<configuration>
<manifest><![CDATA[${basedir}/src/main/resources/META-INF/dal/jdbc/report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/jdbc/alarm-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/jdbc/user-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/jdbc/abtest-manifest.xml,]]></manifest>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<index>true</index>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.dianping.cat.Server</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<packaging>war</packaging>
<env>alpha</env>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
</properties>
${basedir}/src/main/resources/META-INF/dal/jdbc/user-manifest.xml,]]> <![CDATA[${basedir}/src/main/resources/META-INF/dal/jdbc/report-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/jdbc/alarm-manifest.xml,
${basedir}/src/main/resources/META-INF/dal/jdbc/abtest-manifest.xml,]]></manifest>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<index>true</index>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.dianping.cat.Server</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<packaging>war</packaging>
<env>alpha</env>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
</properties>
</project>
......@@ -6,8 +6,18 @@ import java.util.List;
import org.unidal.lookup.configuration.AbstractResourceConfigurator;
import org.unidal.lookup.configuration.Component;
import com.dianping.cat.consumer.advanced.MetricConfigManager;
import com.dianping.cat.core.dal.ProjectDao;
import com.dianping.cat.home.dal.abtest.AbtestDao;
import com.dianping.cat.home.dal.abtest.AbtestReportDao;
import com.dianping.cat.home.dal.abtest.AbtestRunDao;
import com.dianping.cat.home.dal.abtest.GroupStrategyDao;
import com.dianping.cat.system.page.abtest.GroupStrategyParser;
import com.dianping.cat.system.page.abtest.GsonBuilderManager;
import com.dianping.cat.system.page.abtest.ListViewHandler;
import com.dianping.cat.system.page.abtest.ReportHandler;
import com.dianping.cat.system.page.abtest.advisor.ABTestAdvisor;
import com.dianping.cat.system.page.abtest.advisor.DefaultABTestAdvisor;
import com.dianping.cat.system.page.abtest.service.ABTestService;
import com.dianping.cat.system.page.abtest.service.ABTestServiceImpl;
......@@ -18,10 +28,21 @@ public class ABTestComponentConfigurator extends AbstractResourceConfigurator {
List<Component> all = new ArrayList<Component>();
all.add(C(ABTestService.class, ABTestServiceImpl.class)
.req(AbtestDao.class).req(AbtestRunDao.class));
all.add(C(GroupStrategyParser.class));
all.add(C(GsonBuilderManager.class));
all.add(C(ABTestAdvisor.class, DefaultABTestAdvisor.class));
all.add(C(ListViewHandler.class).req(AbtestDao.class).req(AbtestRunDao.class).config(E("pageSize").value("10")));
all.add(C(ReportHandler.class).req(AbtestDao.class).req(AbtestRunDao.class).req(AbtestReportDao.class)
.req(MetricConfigManager.class));
all.add(C(ABTestService.class, ABTestServiceImpl.class).req(AbtestDao.class).req(AbtestRunDao.class)
.req(GroupStrategyDao.class).req(ProjectDao.class).req(GsonBuilderManager.class)
.config(E("refreshTimeInSeconds").value("60")));
return all;
}
}
......@@ -11,8 +11,7 @@ final class CatDatabaseConfigurator extends AbstractJdbcResourceConfigurator {
public List<Component> defineComponents() {
List<Component> all = new ArrayList<Component>();
all.add(defineJdbcDataSourceComponent("cat", "com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:3306/cat", "root", "password", "<![CDATA[useUnicode=true&autoReconnect=true]]>"));
all.add(defineJdbcDataSourceComponent("cat", "com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:3306/cat", "root", "", "<![CDATA[useUnicode=true&autoReconnect=true]]>"));
defineSimpleTableProviderComponents(all, "cat", com.dianping.cat.home.dal.report._INDEX.getEntityClasses());
defineDaoComponents(all, com.dianping.cat.home.dal.report._INDEX.getDaoClasses());
......
......@@ -13,6 +13,7 @@ import com.dianping.cat.consumer.advanced.ProductLineConfigManager;
import com.dianping.cat.core.dal.DailyGraphDao;
import com.dianping.cat.core.dal.GraphDao;
import com.dianping.cat.core.dal.TaskDao;
import com.dianping.cat.home.dal.abtest.AbtestReportDao;
import com.dianping.cat.home.dal.report.BaselineDao;
import com.dianping.cat.home.dal.report.TopologyGraphDao;
import com.dianping.cat.report.baseline.BaselineConfigManager;
......@@ -25,6 +26,7 @@ import com.dianping.cat.report.page.model.spi.ModelService;
import com.dianping.cat.report.page.transaction.TransactionMergeManager;
import com.dianping.cat.report.service.ReportService;
import com.dianping.cat.report.task.DefaultTaskConsumer;
import com.dianping.cat.report.task.abtest.ABTestReportBuilder;
import com.dianping.cat.report.task.bug.BugReportBuilder;
import com.dianping.cat.report.task.cross.CrossReportBuilder;
import com.dianping.cat.report.task.dependency.DependencyReportBuilder;
......@@ -49,6 +51,7 @@ import com.dianping.cat.report.task.state.StateReportBuilder;
import com.dianping.cat.report.task.transaction.TransactionGraphCreator;
import com.dianping.cat.report.task.transaction.TransactionMerger;
import com.dianping.cat.report.task.transaction.TransactionReportBuilder;
import com.dianping.cat.system.page.abtest.service.ABTestService;
import com.dianping.cat.report.task.utilization.UtilizationReportBuilder;
public class TaskComponentConfigurator extends AbstractResourceConfigurator {
......@@ -120,12 +123,15 @@ public class TaskComponentConfigurator extends AbstractResourceConfigurator {
all.add(C(DependencyReportBuilder.class).req(ReportService.class, TopologyGraphBuilder.class,
TopologyGraphDao.class));
all.add(C(ABTestReportBuilder.class).req(ReportService.class, AbtestReportDao.class,
ProductLineConfigManager.class, ABTestService.class));
all.add(C(ReportFacade.class)//
.req(TransactionReportBuilder.class, EventReportBuilder.class, ProblemReportBuilder.class,
HeartbeatReportBuilder.class, MatrixReportBuilder.class, CrossReportBuilder.class,
SqlReportBuilder.class, StateReportBuilder.class, DependencyReportBuilder.class,
BugReportBuilder.class, ServiceReportBuilder.class, MetricBaselineReportBuilder.class,
HeavyReportBuilder.class, UtilizationReportBuilder.class));
HeavyReportBuilder.class, UtilizationReportBuilder.class, ABTestReportBuilder.class));
return all;
}
......
......@@ -236,4 +236,4 @@ public class MetricDisplay extends BaseVisitor {
return result;
}
}
\ No newline at end of file
}
......@@ -81,7 +81,7 @@ public class MetricDisplayMerger extends BaseVisitor {
private com.dianping.cat.home.dal.abtest.Abtest findAbTest(int id) {
com.dianping.cat.home.dal.abtest.Abtest abtest = null;
if (id >= 0) {
abtest = m_abtestService.getABTestNameByRunId(id);
abtest = m_abtestService.getABTestByRunId(id);
}
if (abtest == null) {
abtest = new com.dianping.cat.home.dal.abtest.Abtest();
......
package com.dianping.cat.report.task.abtest;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.unidal.dal.jdbc.DalException;
import org.unidal.lookup.annotation.Inject;
import com.dianping.cat.Cat;
import com.dianping.cat.consumer.advanced.ProductLineConfigManager;
import com.dianping.cat.consumer.metric.model.entity.MetricReport;
import com.dianping.cat.helper.TimeUtil;
import com.dianping.cat.home.dal.abtest.AbtestReportDao;
import com.dianping.cat.home.dal.abtest.AbtestReportEntity;
import com.dianping.cat.home.dal.abtest.AbtestRun;
import com.dianping.cat.report.abtest.entity.AbtestReport;
import com.dianping.cat.report.service.ReportService;
import com.dianping.cat.report.task.spi.ReportTaskBuilder;
import com.dianping.cat.system.page.abtest.AbtestStatus;
import com.dianping.cat.system.page.abtest.service.ABTestService;
public class ABTestReportBuilder implements ReportTaskBuilder, Initializable {
@Inject
protected ReportService m_reportService;
@Inject
private AbtestReportDao m_abtestReportDao;
@Inject
private ProductLineConfigManager m_productLineConfigManager;
@Inject
private ABTestService m_abtestService;
private Calendar m_calendar = Calendar.getInstance();
@Override
public boolean buildHourlyTask(String name, String domain, Date period) {
List<AbtestRun> runs = m_abtestService.getAbtestRunByStatus(AbtestStatus.RUNNING);
for (AbtestRun run : runs) {
Set<String> productLineSet = getProductLinesByRunID(run);
buildHourlyTaskInternal(period, productLineSet);
}
return true;
}
private Date resetTime(String period, Date time) {
m_calendar.setTime(time);
m_calendar.set(Calendar.MINUTE, 0);
m_calendar.set(Calendar.SECOND, 0);
m_calendar.set(Calendar.MILLISECOND, 0);
if (period.equals("day")) {
m_calendar.set(Calendar.HOUR_OF_DAY, 0);
}
return m_calendar.getTime();
}
@Override
public boolean buildDailyTask(String name, String domain, Date period) {
throw new UnsupportedOperationException("ABTest report don't support daily report!");
}
@Override
public boolean buildMonthlyTask(String name, String domain, Date period) {
throw new UnsupportedOperationException("ABTest line report don't support monthly report!");
}
@Override
public boolean buildWeeklyTask(String name, String domain, Date period) {
throw new UnsupportedOperationException("ABTest line report don't support weekly report!");
}
@Override
public void initialize() throws InitializationException {
Date now = resetTime("hour", new Date());
List<AbtestRun> runs = m_abtestService.getAbtestRunByStatus(AbtestStatus.RUNNING);
for (AbtestRun run : runs) {
Set<String> productLineSet = getProductLinesByRunID(run);
Date period = getLatestPeriod(now, run.getId());
m_calendar.setTime(period);
while (!period.after(now)) {
buildHourlyTaskInternal(period, productLineSet);
m_calendar.add(Calendar.HOUR, 1);
period = m_calendar.getTime();
}
}
}
private Date getLatestPeriod(Date now, int runId) {
com.dianping.cat.home.dal.abtest.AbtestReport latestReport = null;
Date period = null;
try {
latestReport = m_abtestReportDao.findLatestReportByRunId(runId, AbtestReportEntity.READSET_FULL);
} catch (Exception e) {
// ignore it
}
if (latestReport == null) {
m_calendar.setTime(now);
m_calendar.add(Calendar.DAY_OF_MONTH, -14);
period = m_calendar.getTime();
} else {
period = latestReport.getPeriod();
}
return period;
}
private Set<String> getProductLinesByRunID(AbtestRun run) {
String[] domains = run.getDomains().split(",");
Set<String> productLineSet = new HashSet<String>();
for (String _domain : domains) {
String productLine = m_productLineConfigManager.queryProductLineByDomain(_domain);
if (!productLine.equals("Default")) {
productLineSet.add(productLine);
}
}
return productLineSet;
}
private void buildHourlyTaskInternal(Date period, Set<String> productLineSet) {
MetricReportForABTestVisitor visitor = new MetricReportForABTestVisitor();
for (String productLine : productLineSet) {
MetricReport metricReport = m_reportService.queryMetricReport(productLine, period, new Date(period.getTime()
+ TimeUtil.ONE_HOUR));
metricReport.accept(visitor);
}
Map<Integer, AbtestReport> result = visitor.getReportMap();
for (AbtestReport report : result.values()) {
if (report.getRunId() != -1) {
com.dianping.cat.home.dal.abtest.AbtestReport _report = new com.dianping.cat.home.dal.abtest.AbtestReport();
_report.setRunId(report.getRunId());
_report.setPeriod(period);
_report.setContent(report.toString());
try {
m_abtestReportDao.insert(_report);
} catch (DalException e) {
Cat.logError(e);
}
}
}
}
}
package com.dianping.cat.report.task.abtest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.dianping.cat.consumer.metric.model.entity.Abtest;
import com.dianping.cat.consumer.metric.model.entity.Group;
import com.dianping.cat.consumer.metric.model.entity.MetricItem;
import com.dianping.cat.consumer.metric.model.entity.MetricReport;
import com.dianping.cat.consumer.metric.model.entity.Point;
import com.dianping.cat.consumer.metric.model.transform.BaseVisitor;
import com.dianping.cat.report.abtest.entity.AbtestReport;
import com.dianping.cat.report.abtest.entity.Goal;
import com.dianping.cat.report.abtest.entity.Variation;
public class MetricReportForABTestVisitor extends BaseVisitor {
private Map<Integer, AbtestReport> m_reportMap;
private Map<Integer, HashMap<String, String>> m_metrics;
private String m_id;
private String m_type;
private int m_runId;
private String m_variation;
private Date m_startDate;
private Date m_endDate;
public MetricReportForABTestVisitor() {
m_reportMap = new HashMap<Integer, AbtestReport>();
m_metrics = new HashMap<Integer, HashMap<String, String>>();
}
private AbtestReport findOrCreateAbtestReport(int runId) {
AbtestReport report = m_reportMap.get(runId);
if (report == null) {
report = new AbtestReport();
report.setRunId(runId);
report.setStartTime(m_startDate);
report.setEndTime(m_endDate);
m_reportMap.put(runId, report);
}
return report;
}
public Map<Integer, AbtestReport> getReportMap() {
for (AbtestReport report : m_reportMap.values()) {
HashMap<String, String> map = m_metrics.get(report.getRunId());
for (String metric : map.keySet()) {
for (Variation variation : report.getVariations().values()) {
Goal goal = variation.findOrCreateGoal(metric);
goal.setType(map.get(metric));
}
Goal goal = new Goal();
goal.setName(metric);
report.getGoals().add(goal);
}
}
return m_reportMap;
}
@Override
public void visitAbtest(Abtest abtest) {
try {
m_runId = Integer.parseInt(abtest.getRunId());
} catch (Exception e) {
m_runId = -1;
}
HashMap<String, String> map = m_metrics.get(m_runId);
if (map == null) {
map = new HashMap<String, String>();
m_metrics.put(m_runId, map);
}
map.put(m_id, m_type);
super.visitAbtest(abtest);
}
@Override
public void visitGroup(Group group) {
m_variation = group.getName();
if(m_variation.length() == 0){
m_variation = "Control";
}
super.visitGroup(group);
}
@Override
public void visitMetricItem(MetricItem metricItem) {
m_id = metricItem.getId();
m_type = metricItem.getType();
super.visitMetricItem(metricItem);
}
@Override
public void visitMetricReport(MetricReport metricReport) {
m_startDate = metricReport.getStartTime();
m_endDate = metricReport.getEndTime();
super.visitMetricReport(metricReport);
}
@Override
public void visitPoint(Point point) {
AbtestReport report = findOrCreateAbtestReport(m_runId);
Variation variation = report.findOrCreateVariation(m_variation);
Goal goal = variation.findOrCreateGoal(m_id);
int count = goal.getCount() + point.getCount();
double sum = goal.getSum() + point.getSum();
goal.setType(m_type);
goal.setCount(count);
goal.setSum(sum);
// avg?
}
}
......@@ -24,6 +24,7 @@ import com.dianping.cat.consumer.sql.SqlAnalyzer;
import com.dianping.cat.consumer.state.StateAnalyzer;
import com.dianping.cat.consumer.transaction.TransactionAnalyzer;
import com.dianping.cat.core.dal.Task;
import com.dianping.cat.report.task.abtest.ABTestReportBuilder;
import com.dianping.cat.report.task.bug.BugReportBuilder;
import com.dianping.cat.report.task.cross.CrossReportBuilder;
import com.dianping.cat.report.task.dependency.DependencyReportBuilder;
......@@ -83,7 +84,10 @@ public class ReportFacade implements LogEnabled, Initializable {
private DependencyReportBuilder m_dependendcyReportBuilder;
@Inject
private MetricBaselineReportBuilder m_metricBaselineReportBuilder;
private MetricBaselineReportBuilder m_metricBaselineReportBuilder;
@Inject
private ABTestReportBuilder m_abtestReportBuilder;
@Inject
private HeavyReportBuilder m_heavyReportBuilder;
......@@ -165,6 +169,7 @@ public class ReportFacade implements LogEnabled, Initializable {
m_reportBuilders.put(Constants.REPORT_SERVICE, m_serviceReportBuilder);
m_reportBuilders.put(Constants.REPORT_HEAVY, m_heavyReportBuilder);
m_reportBuilders.put(Constants.REPORT_UTILIZATION, m_utilizationReportBuilder);
m_reportBuilders.put(Constants.ABTEST, m_abtestReportBuilder);
}
}
package com.dianping.cat.system.page.abtest;
import java.util.Date;
import java.util.Map;
import com.dianping.cat.home.dal.abtest.Abtest;
import com.dianping.cat.home.dal.abtest.AbtestRun;
public class ABTestReport {
private Abtest m_entity;
private AbtestRun m_run;
private AbtestStatus m_status;
private Map<String, String> m_items;
public ABTestReport(Abtest entity, AbtestRun run) {
m_entity = entity;
m_run = run;
}
public ABTestReport(Abtest entity, AbtestRun run, Date now) {
m_entity = entity;
m_run = run;
setStatus(now);
// TODO m_items setting
}
private void setStatus(Date now) {
m_status = AbtestStatus.calculateStatus(m_run, now);
}
public Abtest getEntity() {
return m_entity;
}
public AbtestRun getRun() {
return m_run;
}
public void setStatus(AbtestStatus status) {
m_status = status;
}
public AbtestStatus getStatus() {
return m_status;
}
public Map<String, String> getItems() {
return m_items;
}
}
......@@ -10,9 +10,9 @@ public enum AbtestStatus {
CREATED, READY, RUNNING, TERMINATED, SUSPENDED;
private static final int s_deltaTime = -1; // -1 hour
private static final Calendar calendar = Calendar.getInstance();
public static AbtestStatus getByName(String name, AbtestStatus defaultStatus) {
for (AbtestStatus status : AbtestStatus.values()) {
if (status.name().equalsIgnoreCase(name)) {
......@@ -67,9 +67,8 @@ public enum AbtestStatus {
}
}
public String getStatus() {
return name().toLowerCase();
}
return name().toLowerCase();
}
}
......@@ -9,7 +9,17 @@ public enum Action implements org.unidal.web.mvc.Action {
MODEL("model"),
REPORT("report");
REPORT("report"),
AJAX_CREATE("ajax_create"),
AJAX_DETAIL("ajax_detail"),
AJAX_ADDGROUPSTRATEGY("ajax_addGs"),
AJAX_PARSEGROUPSTRATEGY("ajax_parseGs"),
ABTEST_CACULATOR("caculator");
private String m_name;
......
package com.dianping.cat.system.page.abtest;
import java.util.List;
import com.dianping.cat.system.SystemContext;
import com.dianping.cat.system.page.abtest.advisor.ABTestAdvice;
public class Context extends SystemContext<Payload> {
private String m_responseJson;
private List<ABTestAdvice> m_advices;
public String getResponseJson() {
return m_responseJson;
}
public void setResponseJson(String responseJson) {
m_responseJson = responseJson;
}
public void setAdvice(List<ABTestAdvice> advices) {
m_advices = advices;
}
public List<ABTestAdvice> getAdvice(){
return m_advices;
}
}
package com.dianping.cat.system.page.abtest;
import japa.parser.JavaParser;
import japa.parser.ParseException;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.ImportDeclaration;
import japa.parser.ast.body.FieldDeclaration;
import japa.parser.ast.body.TypeDeclaration;
import japa.parser.ast.body.VariableDeclarator;
import japa.parser.ast.expr.AnnotationExpr;
import japa.parser.ast.visitor.VoidVisitorAdapter;
import java.io.InputStream;
import java.util.List;
import com.dianping.cat.abtest.model.entity.Field;
import com.dianping.cat.abtest.model.entity.GroupstrategyDescriptor;
public class GroupStrategyParser {
public GroupstrategyDescriptor parse(InputStream input) throws ParseException {
final CompilationUnit result = JavaParser.parse(input);
TypeDeclaration type = (TypeDeclaration) result.getTypes().get(0);
final GroupstrategyDescriptor descriptor = new GroupstrategyDescriptor();
String name = type.getName();
descriptor.setClassName(name);
descriptor.setFullyQualifiedName(result.getPackage().getName() + "." + name);
new AnnotationVisitor(descriptor).visit(result, null);
return descriptor;
}
class AnnotationVisitor extends VoidVisitorAdapter<Object> {
private GroupstrategyDescriptor m_descriptor;
private boolean m_isImportInjectClass = false;
public AnnotationVisitor(GroupstrategyDescriptor descriptor) {
m_descriptor = descriptor;
}
public void visit(FieldDeclaration node, Object arg) {
if (m_isImportInjectClass) {
List<AnnotationExpr> annotations = node.getAnnotations();
if (annotations != null) {
for (AnnotationExpr expr : annotations) {
String annotation = expr.toString();
int pos = annotation.indexOf("@Inject");
System.out.println(expr.getData());
if (pos >= 0) {
int begin = annotation.indexOf('"');
int end = annotation.lastIndexOf('"');
String name = annotation.substring(begin + 1, end).trim();
String type = node.getType().toString();
List<VariableDeclarator> modifierName = node.getVariables();
VariableDeclarator firstVar = modifierName.get(0);
Field field = new Field();
field.setName(name);
field.setType(type);
field.setModifierName(firstVar.getId().getName());
if (firstVar.getInit() != null) {
field.setValue(firstVar.getInit().toString());
}
m_descriptor.getFields().add(field);
}
}
}
}
}
public void visit(ImportDeclaration n, Object arg) {
if (n.getName().toString().equals("org.unidal.lookup.annotation.Inject")) {
m_isImportInjectClass = true;
}
}
}
}
package com.dianping.cat.system.page.abtest;
import com.google.gson.FieldNamingStrategy;
import com.google.gson.GsonBuilder;
public class GsonBuilderManager {
private static GsonBuilder s_gsonBuilder = new GsonBuilder();
static {
s_gsonBuilder.setFieldNamingStrategy(new NonPrexFieldNamingStrategy());
}
public GsonBuilder getGsonBuilder() {
return s_gsonBuilder;
}
public static class NonPrexFieldNamingStrategy implements FieldNamingStrategy {
@Override
public String translateName(java.lang.reflect.Field f) {
String name = f.getName();
int pos = name.indexOf('_');
return name.substring(pos + 1);
}
}
}
......@@ -2,16 +2,20 @@ package com.dianping.cat.system.page.abtest;
public enum JspFile {
VIEW("/jsp/system/abtest/abtestAllTest.jsp"),
CREATE("/jsp/system/abtest/abtestCreate.jsp"),
DETAIL("/jsp/system/abtest/abtestDetail.jsp"),
VIEW("/jsp/system/abtest/abtestAllTest.jsp"),
REPORT("/jsp/system/abtest/abtestReport.jsp"),
MODEL("/jsp/system/abtest/abtestModel.jsp");
MODEL("/jsp/system/abtest/abtestModel.jsp"),
AJAX("/jsp/system/abtest/abtestAjax.jsp"),
ABTEST_CACULATOR("/jsp/system/abtest/abtestCaculator.jsp");
private String m_path;
private JspFile(String path) {
......
......@@ -14,13 +14,22 @@ public class JspViewer extends BaseJspViewer<SystemPage, Action, Context, Model>
return JspFile.VIEW.getPath();
case CREATE:
return JspFile.CREATE.getPath();
case AJAX_ADDGROUPSTRATEGY:
return JspFile.AJAX.getPath();
case AJAX_PARSEGROUPSTRATEGY:
return JspFile.AJAX.getPath();
case AJAX_CREATE:
return JspFile.AJAX.getPath();
case AJAX_DETAIL:
return JspFile.AJAX.getPath();
case DETAIL:
return JspFile.DETAIL.getPath();
case REPORT:
return JspFile.REPORT.getPath();
case MODEL:
return JspFile.MODEL.getPath();
case ABTEST_CACULATOR:
return JspFile.ABTEST_CACULATOR.getPath();
}
throw new RuntimeException("Unknown action: " + action);
......
package com.dianping.cat.system.page.abtest;
import java.util.ArrayList;
import java.util.List;
import org.unidal.lookup.annotation.Inject;
import com.dianping.cat.Cat;
import com.dianping.cat.home.dal.abtest.Abtest;
import com.dianping.cat.home.dal.abtest.AbtestDao;
import com.dianping.cat.home.dal.abtest.AbtestEntity;
import com.dianping.cat.home.dal.abtest.AbtestRun;
import com.dianping.cat.home.dal.abtest.AbtestRunDao;
import com.dianping.cat.home.dal.abtest.AbtestRunEntity;
import com.dianping.cat.system.page.abtest.ListViewModel.AbtestItem;
public class ListViewHandler implements SubHandler {
@Inject
private AbtestDao m_abtestDao;
@Inject
private AbtestRunDao m_abtestRunDao;
@Inject
private int m_pageSize = 10;
@Override
public void handle(Context ctx, Model model, Payload payload) {
ListViewModel listViewModel = new ListViewModel();
AbtestStatus status = AbtestStatus.getByName(payload.getStatus(), null);
List<AbtestItem> filterItems = new ArrayList<AbtestItem>();
List<AbtestItem> totalItems = new ArrayList<AbtestItem>();
int createdCount = 0, readyCount = 0, runningCount = 0, terminatedCount = 0, suspendedCount = 0;
List<AbtestRun> runs = new ArrayList<AbtestRun>();
try {
runs = m_abtestRunDao.findAll(AbtestRunEntity.READSET_FULL);
for (AbtestRun run : runs) {
Abtest abtest = m_abtestDao.findByPK(run.getCaseId(), AbtestEntity.READSET_FULL);
AbtestItem item = new AbtestItem(abtest, run);
totalItems.add(item);
if (status != null && item.getStatus() == status) {
filterItems.add(item);
}
switch (item.getStatus()) {
case CREATED:
createdCount++;
break;
case READY:
readyCount++;
break;
case RUNNING:
runningCount++;
break;
case TERMINATED:
terminatedCount++;
break;
case SUSPENDED:
suspendedCount++;
break;
}
}
} catch (Throwable e) {
Cat.logError(e);
}
listViewModel.setCreatedCount(createdCount);
listViewModel.setReadyCount(readyCount);
listViewModel.setRunningCount(runningCount);
listViewModel.setTerminatedCount(terminatedCount);
listViewModel.setSuspendedCount(suspendedCount);
if (status != null) {
totalItems = null;
totalItems = filterItems;
}
int totalSize = totalItems.size();
int totalPages = totalSize % m_pageSize == 0 ? (totalSize / m_pageSize) : (totalSize / m_pageSize + 1);
// safe guarder for pageNum
if (payload.getPageNum() >= totalPages) {
if (totalPages == 0) {
payload.setPageNum(1);
} else {
payload.setPageNum(totalPages);
}
} else if (payload.getPageNum() <= 0) {
payload.setPageNum(1);
}
int fromIndex = (payload.getPageNum() - 1) * m_pageSize;
int toIndex = (fromIndex + m_pageSize) <= totalSize ? (fromIndex + m_pageSize) : totalSize;
listViewModel.setTotalPages(totalPages);
listViewModel.setItems(totalItems.subList(fromIndex, toIndex));
model.setListViewModel(listViewModel);
}
public void setAbtestDao(AbtestDao abtestDao) {
m_abtestDao = abtestDao;
}
public void setAbtestRunDao(AbtestRunDao abtestRunDao) {
m_abtestRunDao = abtestRunDao;
}
public void setPageSize(int pageSize) {
m_pageSize = pageSize;
}
}
package com.dianping.cat.system.page.abtest;
import java.util.Date;
import java.util.List;
import com.dianping.cat.home.dal.abtest.Abtest;
import com.dianping.cat.home.dal.abtest.AbtestRun;
public class ListViewModel {
private int m_totalPages;
private int m_createdCount;
private int m_readyCount;
private int m_runningCount;
private int m_terminatedCount;
private int m_suspendedCount;
private List<AbtestItem> m_items;
public int getCreatedCount() {
return m_createdCount;
}
public List<AbtestItem> getItems() {
return m_items;
}
public int getReadyCount() {
return m_readyCount;
}
public int getRunningCount() {
return m_runningCount;
}
public int getSuspendedCount() {
return m_suspendedCount;
}
public int getTerminatedCount() {
return m_terminatedCount;
}
public int getTotalPages() {
return m_totalPages;
}
public void setCreatedCount(int createdCount) {
m_createdCount = createdCount;
}
public void setItems(List<AbtestItem> item) {
m_items = item;
}
public void setReadyCount(int readyCount) {
m_readyCount = readyCount;
}
public void setRunningCount(int runningCount) {
m_runningCount = runningCount;
}
public void setSuspendedCount(int suspendedCount) {
m_suspendedCount = suspendedCount;
}
public void setTerminatedCount(int terminatedCount) {
m_terminatedCount = terminatedCount;
}
public void setTotalPages(int totalPages) {
m_totalPages = totalPages;
}
public static class AbtestItem {
private Abtest m_abtest;
private AbtestRun m_run;
public AbtestItem(Abtest abtest, AbtestRun run) {
m_abtest = abtest;
m_run = run;
}
public Abtest getAbtest() {
return m_abtest;
}
public int getCaseId() {
return m_run.getCaseId();
}
public String getConditions() {
return m_run.getConditions();
}
public String getConversionGoals() {
return m_run.getConversionGoals();
}
public String getDescription() {
return m_abtest.getDescription();
}
public String getDomains() {
return m_run.getDomains();
}
public Date getEndDate() {
return m_run.getEndDate();
}
public int getGroupStrategy() {
return m_abtest.getGroupStrategy();
}
public int getId() {
return m_run.getId();
}
public String getName() {
return m_abtest.getName();
}
public String getOwner() {
return m_abtest.getOwner();
}
public AbtestRun getRun() {
return m_run;
}
public Date getStartDate() {
return m_run.getStartDate();
}
public AbtestStatus getStatus() {
return AbtestStatus.calculateStatus(m_run, new Date());
}
public String getStrategyConfiguration() {
return m_run.getStrategyConfiguration();
}
public void setAbtest(Abtest abtest) {
m_abtest = abtest;
}
public void setRun(AbtestRun run) {
m_run = run;
}
}
}
......@@ -6,12 +6,15 @@ import java.util.Map;
import org.unidal.web.mvc.ViewModel;
import com.dianping.cat.abtest.model.entity.AbtestModel;
import com.dianping.cat.abtest.spi.ABTestEntity;
import com.dianping.cat.advanced.metric.config.entity.MetricItemConfig;
import com.dianping.cat.core.dal.Project;
import com.dianping.cat.home.dal.abtest.Abtest;
import com.dianping.cat.home.dal.abtest.AbtestRun;
import com.dianping.cat.home.dal.abtest.GroupStrategy;
import com.dianping.cat.report.abtest.entity.AbtestReport;
import com.dianping.cat.system.SystemPage;
import com.dianping.cat.system.page.abtest.ListViewModel.AbtestItem;
import com.dianping.cat.system.page.abtest.ReportHandler.DataSets;
public class Model extends ViewModel<SystemPage, Action, Context> {
private String m_domain;
......@@ -20,27 +23,21 @@ public class Model extends ViewModel<SystemPage, Action, Context> {
private ABTestEntity m_entity;
private List<ABTestReport> m_reports;
private ListViewModel m_listViewModel;
private int m_totalPages;
private int m_createdCount;
private int m_readyCount;
private int m_runningCount;
private Map<String, List<Project>> m_projectMap;
private int m_terminatedCount;
private Map<String, MetricItemConfig> m_metricConfigItem;
private int m_suspendedCount;
private List<GroupStrategy> m_groupStrategyList;
private Map<String, List<Project>> m_projectMap;
private AbtestItem m_abtest;
private List<GroupStrategy> m_groupStrategyList;
private AbtestModel m_abtestModel;
private AbtestDaoModel m_abtest;
private AbtestReport m_report;
private String m_abtestModel;
private List<DataSets> m_dataSets;
private String m_ipAddress;
......@@ -48,16 +45,16 @@ public class Model extends ViewModel<SystemPage, Action, Context> {
super(ctx);
}
public AbtestDaoModel getAbtest() {
public AbtestItem getAbtest() {
return m_abtest;
}
public String getAbtestModel() {
public AbtestModel getAbtestModel() {
return m_abtestModel;
}
public int getCreatedCount() {
return m_createdCount;
public List<DataSets> getDataSets() {
return m_dataSets;
}
public Date getDate() {
......@@ -85,48 +82,36 @@ public class Model extends ViewModel<SystemPage, Action, Context> {
return m_ipAddress;
}
public Map<String, List<Project>> getProjectMap() {
return m_projectMap;
}
public int getReadyCount() {
return m_readyCount;
}
public List<ABTestReport> getReports() {
return m_reports;
}
public String getReportType(){
return "";
public ListViewModel getListViewModel() {
return m_listViewModel;
}
public int getRunningCount() {
return m_runningCount;
public Map<String, MetricItemConfig> getMetricConfigItem() {
return m_metricConfigItem;
}
public int getSuspendedCount() {
return m_suspendedCount;
public Map<String, List<Project>> getProjectMap() {
return m_projectMap;
}
public int getTerminatedCount() {
return m_terminatedCount;
public AbtestReport getReport() {
return m_report;
}
public int getTotalPages() {
return m_totalPages;
public String getReportType() {
return "";
}
public void setAbtest(AbtestDaoModel abtest) {
public void setAbtest(AbtestItem abtest) {
m_abtest = abtest;
}
public void setAbtestModel(String abtestModel) {
public void setAbtestModel(AbtestModel abtestModel) {
m_abtestModel = abtestModel;
}
public void setCreatedCount(int createdCount) {
m_createdCount = createdCount;
public void setDataSets(List<DataSets> dataSets) {
m_dataSets = dataSets;
}
public void setDate(Date date) {
......@@ -149,100 +134,19 @@ public class Model extends ViewModel<SystemPage, Action, Context> {
m_ipAddress = ipAddress;
}
public void setProjectMap(Map<String, List<Project>> projectMap) {
m_projectMap = projectMap;
}
public void setReadyCount(int readyCount) {
m_readyCount = readyCount;
public void setListViewModel(ListViewModel listViewModel) {
m_listViewModel = listViewModel;
}
public void setReports(List<ABTestReport> reports) {
m_reports = reports;
public void setMetricConfigItem(Map<String, MetricItemConfig> metricItemConfig) {
m_metricConfigItem = metricItemConfig;
}
public void setRunningCount(int runningCount) {
m_runningCount = runningCount;
}
public void setSuspendedCount(int suspendedCount) {
m_suspendedCount = suspendedCount;
}
public void setTerminatedCount(int terminatedCount) {
m_terminatedCount = terminatedCount;
}
public void setTotalPages(int totalPages) {
m_totalPages = totalPages;
public void setProjectMap(Map<String, List<Project>> projectMap) {
m_projectMap = projectMap;
}
public static class AbtestDaoModel {
private Abtest m_abtest;
private AbtestRun m_run;
public AbtestDaoModel(Abtest abtest, AbtestRun abtestRun) {
super();
m_abtest = abtest;
m_run = abtestRun;
}
public Abtest getAbtest() {
return m_abtest;
}
public int getCaseId() {
return m_run.getCaseId();
}
public String getDescription() {
return m_abtest.getDescription();
}
public String getDomains() {
return m_run.getDomains();
}
public Date getEndDate() {
return m_run.getEndDate();
}
public int getGroupStrategy() {
return m_abtest.getGroupStrategy();
}
public int getId() {
return m_run.getId();
}
public String getName() {
return m_abtest.getName();
}
public String getOwner() {
return m_abtest.getOwner();
}
public AbtestRun getRun() {
return m_run;
}
public Date getStartDate() {
return m_run.getStartDate();
}
public String getStrategyConfiguration() {
return m_run.getStrategyConfiguration();
}
public void setAbtest(Abtest abtest) {
m_abtest = abtest;
}
public void setRun(AbtestRun run) {
m_run = run;
}
public void setReport(AbtestReport report) {
m_report = report;
}
}
......@@ -4,8 +4,8 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.codehaus.plexus.util.StringUtils;
import org.unidal.web.mvc.ActionContext;
import org.unidal.web.mvc.ActionPayload;
import org.unidal.web.mvc.payload.annotation.FieldMeta;
......@@ -19,18 +19,14 @@ public class Payload implements ActionPayload<SystemPage, Action> {
@FieldMeta("op")
private Action m_action;
@FieldMeta("status")
private String m_status;
@FieldMeta("pageNum")
private int m_pageNum;
/* ===============Abtest================ */
@FieldMeta("name")
private String m_name;
@FieldMeta("owner")
private String m_owner;
@FieldMeta("description")
private String m_description;
......@@ -43,11 +39,13 @@ public class Payload implements ActionPayload<SystemPage, Action> {
@FieldMeta("domains")
private String[] m_domains;
@FieldMeta("strategyId")
private int m_strategyId;
@FieldMeta("conditions")
private String m_conditions;
@FieldMeta("strategyConfig")
private String m_strategyConfig;
@FieldMeta("goals")
private String m_conversionGoals;
/* ===============Abtest Controls================ */
@FieldMeta("enable")
private boolean m_enableAbtest;
......@@ -58,50 +56,150 @@ public class Payload implements ActionPayload<SystemPage, Action> {
@FieldMeta("ids")
private String m_ids;
@FieldMeta("status")
private String m_status;
@FieldMeta("pageNum")
private int m_pageNum;
@FieldMeta("id")
private int id;
@FieldMeta("lastUpdateTime")
private long m_lastUpdateTime;
/* ===============GroupStrategy================ */
@FieldMeta("strategyId")
private int m_strategyId;
@FieldMeta("strategyConfig")
private String m_strategyConfig;
@FieldMeta("groupStrategyName")
private String m_groupStrategyName;
@FieldMeta("groupStrategyClassName")
private String m_groupStrategyClassName;
@FieldMeta("groupStrategyFullName")
private String m_groupStrategyFullName;
@FieldMeta("groupStrategyDescriptor")
private String m_groupStrategyDescriptor;
@FieldMeta("groupStrategyDescription")
private String m_groupStrategyDescription;
@FieldMeta("srcCode")
private String m_srcCode;
/* ===============Caculator================ */
@FieldMeta("pv")
private int m_pv = 0;
@FieldMeta("conversionRate")
private int m_conversionRate;
/* ===============Report================ */
@FieldMeta("selectMetricType")
private String m_selectMetricType;
@FieldMeta("period")
private String m_period;
private boolean m_addGs;
private String m_startDateStr;
private String m_endDateStr;
private SimpleDateFormat m_sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm");
public void setAction(String action) {
if (action.equalsIgnoreCase(Action.REPORT.getName())) {
m_action = Action.getByName(action, Action.REPORT);
} else if (action.equalsIgnoreCase(Action.CREATE.getName())) {
m_action = Action.getByName(action, Action.CREATE);
} else {
m_action = Action.getByName(action, Action.VIEW);
}
}
private SimpleDateFormat m_dataFormater = new SimpleDateFormat("yyyy-MM-dd hh:mm");
@Override
public Action getAction() {
return m_action;
}
public String getStatus() {
return m_status;
public boolean getAddGs() {
return m_addGs;
}
public void setStatus(String status) {
AbtestStatus abstatus = AbtestStatus.getByName(status, null);
public String getConditions() {
return m_conditions;
}
if (abstatus != null) {
m_status = abstatus.name().toLowerCase();
public String getConversionGoals() {
return m_conversionGoals;
}
public int getConversionRate() {
return m_conversionRate;
}
public String getDescription() {
return m_description;
}
public int getDisableAbtest() {
return m_disableAbtest;
}
public String[] getDomains() {
return m_domains;
}
public Date getEndDate() {
return m_endDate;
}
public String getEndDateStr() {
return m_endDateStr;
}
public String getGroupStrategyClassName() {
return m_groupStrategyClassName;
}
public String getGroupStrategyDescription() {
return m_groupStrategyDescription;
}
public String getGroupStrategyDescriptor() {
return m_groupStrategyDescriptor;
}
public String getGroupStrategyFullName() {
return m_groupStrategyFullName;
}
public String getGroupStrategyName() {
return m_groupStrategyName;
}
public int getId() {
return id;
}
public String[] getIds() {
if (m_ids != null) {
String[] ids = m_ids.split("-");
return ids;
} else {
m_status = "all";
return null;
}
}
public int getPageNum() {
return m_pageNum;
public long getLastUpdateTime() {
return m_lastUpdateTime;
}
public void setPageNum(int pageNum) {
m_pageNum = pageNum;
public String getName() {
return m_name;
}
public String getOwner() {
return m_owner;
}
@Override
......@@ -109,128 +207,199 @@ public class Payload implements ActionPayload<SystemPage, Action> {
return m_page;
}
public int getPageNum() {
return m_pageNum;
}
public String getPeriod() {
return m_period;
}
public int getPv() {
return m_pv;
}
public String getReportType() {
return "";
}
@Override
public void setPage(String page) {
m_page = SystemPage.getByName(page, SystemPage.ABTEST);
public String getSelectMetricType() {
return m_selectMetricType;
}
public String getName() {
return m_name;
public String getSrcCode() {
return m_srcCode;
}
public void setName(String name) {
this.m_name = name;
public Date getStartDate() {
return m_startDate;
}
public String getOwner() {
return m_owner;
}
public void setOwner(String owner) {
m_owner = owner;
}
public String getStartDateStr() {
return m_startDateStr;
}
public String getDescription() {
return m_description;
public String getStatus() {
return m_status;
}
public void setDescription(String description) {
this.m_description = description;
public String getStrategyConfig() {
return m_strategyConfig;
}
public Date getStartDate() {
return m_startDate;
public int getStrategyId() {
return m_strategyId;
}
public Date getEndDate() {
return m_endDate;
public boolean isEnableAbtest() {
return m_enableAbtest;
}
public void setStartDate(String startDate) {
try {
m_startDateStr = startDate;
m_startDate = m_sdf.parse(startDate);
} catch (ParseException e) {
Cat.logError(e);
public void setAction(String action) {
if (action.equalsIgnoreCase(Action.REPORT.getName())) {
m_action = Action.getByName(action, Action.REPORT);
} else if (action.equalsIgnoreCase(Action.CREATE.getName())) {
m_action = Action.getByName(action, Action.CREATE);
} else {
m_action = Action.getByName(action, Action.VIEW);
}
}
public void setAddGs(boolean addGs) {
m_addGs = addGs;
}
public void setConditions(String conditions) {
m_conditions = conditions;
}
public void setConversionRate(int conversionRate) {
m_conversionRate = conversionRate;
}
public void setDescription(String description) {
this.m_description = description;
}
public void setDisableAbtest(int disableAbtest) {
m_disableAbtest = disableAbtest;
}
public void setDomains(String[] domains) {
this.m_domains = domains;
}
public void setEndDate(String endDate) {
try {
m_endDateStr = endDate;
m_endDate = m_sdf.parse(endDate);
m_endDate = m_dataFormater.parse(endDate);
} catch (ParseException e) {
Cat.logError(e);
}
}
public String getStartDateStr() {
return m_startDateStr;
public void setEndDate2(Date endDate) {
m_endDate = endDate;
}
public String getEndDateStr() {
return m_endDateStr;
public void setGoals(String goals) {
m_conversionGoals = goals;
}
public String[] getDomains() {
return m_domains;
public void setGroupStrategyClassName(String groupStrategyClassName) {
m_groupStrategyClassName = groupStrategyClassName;
}
public void setDomains(String[] domains) {
this.m_domains = domains;
public void setGroupStrategyDescription(String groupStrategyDescription) {
m_groupStrategyDescription = groupStrategyDescription;
}
public int getStrategyId() {
return m_strategyId;
public void setGroupStrategyDescriptor(String groupStrategyDescriptor) {
m_groupStrategyDescriptor = groupStrategyDescriptor;
}
public void setStrategyId(int strategyId) {
this.m_strategyId = strategyId;
public void setGroupStrategyFullName(String groupStrategyFullName) {
m_groupStrategyFullName = groupStrategyFullName;
}
public String getStrategyConfig() {
return m_strategyConfig;
public void setGroupStrategyName(String groupStrategyName) {
m_groupStrategyName = groupStrategyName;
}
public void setStrategyConfig(String strategyConfig) {
this.m_strategyConfig = strategyConfig;
public void setId(int id) {
this.id = id;
}
public boolean isEnableAbtest() {
return m_enableAbtest;
public void setIds(String ids) {
m_ids = ids;
}
public int getDisableAbtest() {
return m_disableAbtest;
public void setLastUpdateTime(long lastUpdateTime) {
m_lastUpdateTime = lastUpdateTime;
}
public void setDisableAbtest(int disableAbtest) {
m_disableAbtest = disableAbtest;
public void setName(String name) {
this.m_name = name;
}
public String[] getIds() {
if (m_ids != null) {
String[] ids = m_ids.split("-");
return ids;
} else {
return null;
public void setOwner(String owner) {
m_owner = owner;
}
@Override
public void setPage(String page) {
m_page = SystemPage.getByName(page, SystemPage.ABTEST);
}
public void setPageNum(int pageNum) {
m_pageNum = pageNum;
}
public void setPeriod(String period) {
m_period = period;
}
public void setPv(int pv) {
m_pv = pv;
}
public void setSelectMetricType(String selectMetricType) {
m_selectMetricType = selectMetricType;
}
public void setSrcCode(String srcCode) {
m_srcCode = srcCode;
}
public void setStartDate(String startDate) {
try {
m_startDateStr = startDate;
m_startDate = m_dataFormater.parse(startDate);
} catch (ParseException e) {
Cat.logError(e);
}
}
public void setIds(String ids) {
m_ids = ids;
public void setStartDate2(Date startDate) {
m_startDate = startDate;
}
public int getId() {
return id;
public void setStatus(String status) {
AbtestStatus abstatus = AbtestStatus.getByName(status, null);
if (abstatus != null) {
m_status = abstatus.name().toLowerCase();
} else {
m_status = "all";
}
}
public void setId(int id) {
this.id = id;
public void setStrategyConfig(String strategyConfig) {
this.m_strategyConfig = strategyConfig;
}
public void setStrategyId(int strategyId) {
this.m_strategyId = strategyId;
}
@Override
......@@ -238,27 +407,36 @@ public class Payload implements ActionPayload<SystemPage, Action> {
if (m_action == null) {
m_action = Action.VIEW;
}
// 验证doCreate的参数
if (m_action == Action.CREATE && ctx.getHttpServletRequest().getMethod().equalsIgnoreCase("post")) {
try {
Validate.isTrue(StringUtils.isNotBlank(m_name), "'ABTest Name' is required");
// Validate.isTrue(m_startDate != null, "'Start Time' is required, and formated 'yyyy-MM-dd hh:mm'");
// Validate.isTrue(m_endDate != null, "'End Time' is required, and formated 'yyyy-MM-dd hh:mm'");
Validate.isTrue(m_domains != null && m_domains.length > 0, "'Domains' is required, choose one at least");
for (String domain : m_domains) {
Validate.isTrue(StringUtils.isNotBlank(domain), "'Domains' should not be blank");
}
Validate.isTrue(m_strategyId > 0, "'Strategy' is required, choose one at least");
} catch (IllegalArgumentException e) {
ctx.setException(e);
}
}
if (m_status == null) {
m_status = "all";
}
if (m_disableAbtest != -1 && m_disableAbtest != 1) {
m_disableAbtest = 0;
}
if (ctx.getHttpServletRequest().getMethod().equalsIgnoreCase("post")) {
if (m_action == Action.CREATE) {
try {
Validate.isTrue(StringUtils.isNotBlank(m_name), "'ABTest Name' is required");
Validate.isTrue(m_domains != null && m_domains.length > 0, "'Domains' is required, choose one at least");
for (String domain : m_domains) {
Validate.isTrue(StringUtils.isNotBlank(domain), "'Domains' should not be blank");
}
Validate.isTrue(m_strategyId > 0, "'Strategy' is required, choose one at least");
} catch (IllegalArgumentException e) {
ctx.setException(e);
}
} else if (m_action == Action.AJAX_ADDGROUPSTRATEGY) {
try {
Validate.isTrue(StringUtils.isNotBlank(m_groupStrategyName), "'GroupStrategy Name' is required");
Validate.isTrue(StringUtils.isNotBlank(m_groupStrategyClassName),
"'GroupStrategy ClassName' is required");
} catch (IllegalArgumentException e) {
ctx.setException(e);
}
}
}
}
}
package com.dianping.cat.system.page.abtest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.unidal.lookup.ContainerLoader;
import org.unidal.lookup.annotation.Inject;
import com.dianping.cat.Cat;
import com.dianping.cat.advanced.metric.config.entity.MetricItemConfig;
import com.dianping.cat.consumer.advanced.MetricConfigManager;
import com.dianping.cat.home.dal.abtest.Abtest;
import com.dianping.cat.home.dal.abtest.AbtestDao;
import com.dianping.cat.home.dal.abtest.AbtestEntity;
import com.dianping.cat.home.dal.abtest.AbtestReportDao;
import com.dianping.cat.home.dal.abtest.AbtestReportEntity;
import com.dianping.cat.home.dal.abtest.AbtestRun;
import com.dianping.cat.home.dal.abtest.AbtestRunDao;
import com.dianping.cat.home.dal.abtest.AbtestRunEntity;
import com.dianping.cat.report.abtest.entity.AbtestReport;
import com.dianping.cat.report.abtest.entity.Chart;
import com.dianping.cat.report.abtest.entity.Goal;
import com.dianping.cat.report.abtest.entity.Variation;
import com.dianping.cat.report.abtest.transform.BaseVisitor;
import com.dianping.cat.report.abtest.transform.DefaultSaxParser;
import com.dianping.cat.report.task.abtest.ABTestReportBuilder;
import com.dianping.cat.system.page.abtest.ListViewModel.AbtestItem;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class ReportHandler implements SubHandler, Initializable {
@Inject
private AbtestDao m_abtestDao;
@Inject
private AbtestRunDao m_abtestRunDao;
@Inject
private AbtestReportDao m_abtestReportDao;
@Inject
private MetricConfigManager m_configManager;
private static GsonBuilderManager m_gsonBuilderManager = new GsonBuilderManager();
private Calendar m_calendar = Calendar.getInstance();
private DateFormat m_dateFormatForHour = new SimpleDateFormat("MM-dd HH:00");
private DateFormat m_dateFormatForDay = new SimpleDateFormat("MM-dd");
private AbtestReport buildDailyReport(AbtestReport query, String goal, Model model) {
Date startTime = query.getStartTime();
Date endTime = query.getEndTime();
m_calendar.setTime(startTime);
long deltaTime = endTime.getTime() - startTime.getTime();
long day = deltaTime / (24 * 60 * 60 * 1000L);
int step = ((int) day / 7 > 0) ? ((int) day / 7) : 1;
int count = 0;
List<AbtestReport> datas = new ArrayList<AbtestReport>();
List<String> labels = new ArrayList<String>();
m_calendar.add(Calendar.DAY_OF_MONTH, 1);
endTime = m_calendar.getTime();
while (startTime.before(query.getEndTime())) {
if (count % step == 0) {
List<AbtestReport> reports = queryReport(query.getRunId(), startTime, endTime);
AbtestReport report = mergeReport(reports);
datas.add(report);
labels.add(m_dateFormatForDay.format(endTime));
} else {
labels.add("");
}
count++;
startTime = endTime;
m_calendar.add(Calendar.DAY_OF_MONTH, 1);
endTime = m_calendar.getTime();
}
AbtestReport report = mergeReport(datas);
Chart chart = new Chart();
if (goal.length() == 0) {
for (Goal _goal : report.getGoals()) {
goal = _goal.getName();
if (goal.length() > 0) {
break;
}
}
}
String datasets = buildDateSets(datas, goal, report.getVariations().keySet(), model);
Gson gson = m_gsonBuilderManager.getGsonBuilder().create();
String label = gson.toJson(labels, new TypeToken<List<String>>() {
}.getType());
chart.setType("day");
chart.setLabels(label);
chart.setDatasets(datasets);
chart.setGoal(goal);
report.setChart(chart);
report.setRunId(query.getRunId());
report.setStartTime(query.getStartTime());
report.setEndTime(query.getEndTime());
return report;
}
private String buildDateSets(List<AbtestReport> reports, String goal, Set<String> set, Model model) {
List<DataSets> dataSets = new ArrayList<DataSets>();
for (String key : set) {
List<Number> data = new ArrayList<Number>();
for (AbtestReport report : reports) {
if (report.getStartTime() != null) {
Variation variation = report.findVariation(key);
if (variation != null) {
Goal tmp = variation.findGoal(goal);
if (tmp != null) {
if (tmp.getType().equals("C")) {
data.add(tmp.getCount());
} else if (tmp.getType().equals("S")) {
data.add(tmp.getSum());
} else {
data.add(tmp.getAvg());
}
} else {
data.add(0);
}
} else {
data.add(0);
}
} else {
data.add(0);
}
}
DataSets dataSet = DataSetsBuilder.buildDataSets(DataSetColor.getDataSetColor(key), data);
dataSets.add(dataSet);
}
model.setDataSets(dataSets);
Gson gson = m_gsonBuilderManager.getGsonBuilder().create();
return gson.toJson(dataSets, new TypeToken<List<DataSets>>() {
}.getType());
}
private AbtestReport buildHourlyReport(AbtestReport query, String goal, Model model) {
Date startTime = query.getStartTime();
Date endTime = query.getEndTime();
List<AbtestReport> reports = queryReport(query.getRunId(), startTime, endTime);
List<AbtestReport> datas = new ArrayList<AbtestReport>();
List<String> labels = new ArrayList<String>();
long deltaTime = endTime.getTime() - startTime.getTime();
long hour = deltaTime / (60 * 60 * 1000L);
int step = ((int) hour / 12 > 0) ? ((int) hour / 12) : 1;
int size = reports.size();
int count = 0;
int i = 0;
m_calendar.setTime(startTime);
m_calendar.add(Calendar.HOUR, 1);
endTime = m_calendar.getTime();
while (startTime.before(query.getEndTime())) {
if (count % step == 0) {
labels.add(m_dateFormatForHour.format(startTime));
} else {
labels.add("");
}
if (i < size) {
AbtestReport re = reports.get(i);
if (re.getStartTime().equals(startTime)) {
datas.add(re);
i++;
} else {
datas.add(new AbtestReport());
}
}
count++;
startTime = endTime;
m_calendar.add(Calendar.HOUR, 1);
endTime = m_calendar.getTime();
}
AbtestReport report = mergeReport(datas);
Chart chart = new Chart();
if (goal.length() == 0) {
for (Goal _goal : report.getGoals()) {
goal = _goal.getName();
if (goal.length() > 0) {
break;
}
}
}
String datasets = buildDateSets(datas, goal, report.getVariations().keySet(), model);
Gson gson = m_gsonBuilderManager.getGsonBuilder().create();
String label = gson.toJson(labels, new TypeToken<List<String>>() {
}.getType());
chart.setType("hour");
chart.setLabels(label);
chart.setDatasets(datasets);
chart.setGoal(goal);
report.setChart(chart);
report.setRunId(query.getRunId());
report.setStartTime(query.getStartTime());
report.setEndTime(query.getEndTime());
return report;
}
private AbtestReport buildQuery(int runId, Date startTime, Date endTime, String period) {
AbtestReport query = new AbtestReport();
Date now = new Date();
Date newStartTime = null;
Date newEndTime = null;
query.setRunId(runId);
if (startTime == null && endTime == null) {
m_calendar.setTime(now);
if (period.equals("day")) {
m_calendar.add(Calendar.DAY_OF_MONTH, -7);
} else {
m_calendar.add(Calendar.HOUR_OF_DAY, -24);
}
newStartTime = m_calendar.getTime();
newEndTime = now;
} else if (endTime == null) {
m_calendar.setTime(startTime);
if (period.equals("day")) {
m_calendar.add(Calendar.DAY_OF_MONTH, 7);
} else {
m_calendar.add(Calendar.HOUR_OF_DAY, 24);
}
newStartTime = startTime;
newEndTime = m_calendar.getTime();
} else if (startTime == null) {
m_calendar.setTime(endTime);
if (period.equals("day")) {
m_calendar.add(Calendar.DAY_OF_MONTH, -7);
} else {
m_calendar.add(Calendar.HOUR_OF_DAY, -24);
}
newStartTime = m_calendar.getTime();
newEndTime = endTime;
} else {
newStartTime = startTime;
newEndTime = endTime;
}
query.setStartTime(resetTime(period, newStartTime));
query.setEndTime(resetTime(period, newEndTime));
return query;
}
public AbtestReport buildReport(AbtestReport query, String goal, String period, Model model) {
if (period.equals("day")) {
return buildDailyReport(query, goal, model);
} else {
return buildHourlyReport(query, goal, model);
}
}
public Map<String, MetricItemConfig> getMetricItemConfig() {
return m_configManager.getMetricConfig().getMetricItemConfigs();
}
@Override
public void handle(Context ctx, Model model, Payload payload) {
int runId = payload.getId();
try {
AbtestRun run = m_abtestRunDao.findByPK(runId, AbtestRunEntity.READSET_FULL);
Abtest abtest = m_abtestDao.findByPK(run.getCaseId(), AbtestEntity.READSET_FULL);
AbtestItem item = new AbtestItem(abtest, run);
Date startTime = payload.getStartDate();
Date endTime = payload.getEndDate();
String goal = payload.getSelectMetricType();
String period = payload.getPeriod();
if (period == null || (!period.equals("hour") && !period.equals("day"))) {
period = "hour";
}
if (goal == null) {
goal = "";
}
AbtestReport query = buildQuery(runId, startTime, endTime, period);
AbtestReport report = buildReport(query, goal, period, model);
Collections.sort(report.getGoals(), new Comparator<Goal>() {
@Override
public int compare(Goal o1, Goal o2) {
Map<String, MetricItemConfig> metricItemConfig = getMetricItemConfig();
MetricItemConfig item1 = metricItemConfig.get(o1.getName());
MetricItemConfig item2 = metricItemConfig.get(o2.getName());
if (item1.getViewOrder() > item2.getViewOrder()) {
return 1;
} else {
return -1;
}
}
});
model.setAbtest(item);
model.setReport(report);
model.setMetricConfigItem(getMetricItemConfig());
payload.setStartDate2(query.getStartTime());
payload.setEndDate2(query.getEndTime());
} catch (Exception e) {
Cat.logError(e);
e.printStackTrace();
}
}
@Override
public void initialize() throws InitializationException {
try {
ContainerLoader.getDefaultContainer().lookup(ABTestReportBuilder.class);
} catch (ComponentLookupException e) {
Cat.logError(e);
}
}
private AbtestReport mergeReport(List<AbtestReport> reports) {
AbtestReport result = new AbtestReport();
AbtestReportVisitor visitor = new AbtestReportVisitor(result);
for (AbtestReport report : reports) {
if (report.getStartTime() != null) {
visitor.visitAbtestReport(report);
result.setRunId(report.getRunId());
if (result.getStartTime() == null || result.getEndTime() == null) {
result.setStartTime(report.getStartTime());
result.setEndTime(report.getEndTime());
}
if (result.getStartTime().after(report.getStartTime())) {
result.setStartTime(report.getStartTime());
}
if (result.getEndTime().before(report.getEndTime())) {
result.setEndTime(report.getEndTime());
}
}
}
return result;
}
private List<AbtestReport> queryReport(int runId, Date startTime, Date endTime) {
List<AbtestReport> results = new ArrayList<AbtestReport>();
try {
List<com.dianping.cat.home.dal.abtest.AbtestReport> reports = m_abtestReportDao.findByRunIdDuration(runId,
startTime, endTime, AbtestReportEntity.READSET_FULL);
for (com.dianping.cat.home.dal.abtest.AbtestReport report : reports) {
String content = report.getContent();
AbtestReport result = DefaultSaxParser.parse(content);
results.add(result);
}
} catch (Exception e) {
Cat.logError(e);
}
return results;
}
private Date resetTime(String period, Date time) {
m_calendar.setTime(time);
m_calendar.set(Calendar.MINUTE, 0);
m_calendar.set(Calendar.SECOND, 0);
m_calendar.set(Calendar.MILLISECOND, 0);
if (period.equals("day")) {
m_calendar.set(Calendar.HOUR_OF_DAY, 0);
}
return m_calendar.getTime();
}
class AbtestReportVisitor extends BaseVisitor {
private AbtestReport m_report;
private String m_variation = "";
private Set<String> m_variationSet;
private Map<String, MetricItemConfig> m_metricItemConfig;
public AbtestReportVisitor(AbtestReport report) {
m_report = report;
m_variationSet = new HashSet<String>();
m_variationSet.add("Control");
m_variationSet.add("A");
m_variationSet.add("B");
m_variationSet.add("C");
m_metricItemConfig = getMetricItemConfig();
}
public AbtestReport getReport() {
return m_report;
}
@Override
public void visitAbtestReport(AbtestReport abtestReport) {
for (Goal goal : abtestReport.getGoals()) {
String name = goal.getName();
MetricItemConfig tmp = m_metricItemConfig.get(name);
if (tmp.getViewOrder() > 0) {
m_report.findOrCreateGoal(name);
}
}
for (Variation variation : abtestReport.getVariations().values()) {
if (m_variationSet.contains(variation.getName())) {
visitVariation(variation);
}
}
}
@Override
public void visitGoal(Goal goal) {
String name = goal.getName();
if (m_variation != null && m_variation.length() > 0) {
Variation variation = m_report.findOrCreateVariation(m_variation);
Goal result = variation.findOrCreateGoal(name);
result.setType(goal.getType());
result.setCount(result.getCount() + goal.getCount());
result.setSum(result.getSum() + goal.getSum());
// avg?
}
}
@Override
public void visitVariation(Variation variation) {
m_variation = variation.getName();
if (m_variation != null && m_variation.length() > 0) {
m_report.findOrCreateVariation(m_variation);
for (Goal goal : variation.getGoals().values()) {
visitGoal(goal);
}
}
}
}
enum DataSetColor {
CONTROL(new DataSets("rgba(70, 136, 71,0.2)", "rgba(70, 136, 71,1)", "rgba(70, 136, 71, 1)", "#468847", null)),
A(new DataSets("rgba(58, 135, 173, 0.3)", "rgba(58, 135, 173, 1)", "rgba(58, 135, 173, 1)", "#3a87ad", null)),
B(new DataSets("rgba(185, 74, 72, 0.2)", "rgba(185, 74, 72, 1)", "rgba(185, 74, 72, 1)", "#b94a48", null)),
C(new DataSets("rgba(248, 148, 6,0.2)", "rgba(248, 148, 6,1)", "rgba(248, 148, 6, 1)", "#f89406", null));
public static DataSetColor getDataSetColor(String variation) {
if (variation.equalsIgnoreCase("control")) {
return CONTROL;
} else if (variation.equalsIgnoreCase("A")) {
return A;
} else if (variation.equalsIgnoreCase("B")) {
return B;
} else if (variation.equalsIgnoreCase("C")) {
return C;
} else {
return CONTROL;
}
}
private DataSets m_dataSets;
private DataSetColor(DataSets dataSets) {
m_dataSets = dataSets;
}
public DataSets getDataSets() {
return m_dataSets;
}
}
@SuppressWarnings("unused")
public static class DataSets {
private String m_fillColor;
private String m_strokeColor;
private String m_pointColor;
private String m_pointStrokeColor;
private List<Number> m_data;
public DataSets() {
}
public DataSets(String fillColor, String strokeColor, String pointColor, String pointStrokeColor,
List<Number> data) {
super();
m_fillColor = fillColor;
m_strokeColor = strokeColor;
m_pointColor = pointColor;
m_pointStrokeColor = pointStrokeColor;
m_data = data;
}
public String getPointStrokeColor() {
return m_pointStrokeColor;
}
public void setData(List<Number> data) {
m_data = data;
}
public String toJson() {
Gson gson = m_gsonBuilderManager.getGsonBuilder().create();
return gson.toJson(this, DataSets.class);
}
}
static class DataSetsBuilder {
public static DataSets buildDataSets(DataSetColor color, List<Number> number) {
DataSets dataSets = color.getDataSets();
dataSets.setData(number);
return dataSets;
}
}
}
package com.dianping.cat.system.page.abtest;
public interface SubHandler {
public void handle(Context ctx, Model model, Payload payload);
}
package com.dianping.cat.system.page.abtest.advisor;
public class ABTestAdvice {
private double m_ctrOfVariationA = 0.00;
private double m_ctrOfVariationB = 0.00;
private double m_difference = 0.00;
private int m_sizePerGroup = 0;
private int m_totalParticipants = 0;
private double m_confidenceInterval = 0.95;
private int m_days = 0;
public double getConfidenceInterval() {
return m_confidenceInterval;
}
public double getCtrOfVariationA() {
return m_ctrOfVariationA;
}
public double getCtrOfVariationB() {
return m_ctrOfVariationB;
}
public int getDays() {
return m_days;
}
public double getDifference() {
return m_difference;
}
public int getSizePerGroup() {
return m_sizePerGroup;
}
public int getTotalParticipants() {
return m_totalParticipants;
}
public void setConfidenceInterval(double confidenceInterval) {
m_confidenceInterval = confidenceInterval;
}
public void setCtrOfVariationA(double ctrOfVariationA) {
m_ctrOfVariationA = ctrOfVariationA;
}
public void setCtrOfVariationB(double ctrOfVariationB) {
m_ctrOfVariationB = ctrOfVariationB;
}
public void setDays(int days) {
m_days = days;
}
public void setDifference(double difference) {
m_difference = difference;
}
public void setSizePerGroup(int sizePerGroup) {
m_sizePerGroup = sizePerGroup;
}
public void setTotalParticipants(int totalParticipants) {
m_totalParticipants = totalParticipants;
}
}
\ No newline at end of file
package com.dianping.cat.system.page.abtest.advisor;
import java.util.List;
public interface ABTestAdvisor {
public List<ABTestAdvice> offer(double actualCTR, double expectedCTR);
public void setConfidenceInterval(double interval);
public void setCurrentPv(int pv);
public void setDifference(double difference);
}
package com.dianping.cat.system.page.abtest.advisor;
public class ABTestEvaluator {
public float getConfidence(float zscore) {
if (zscore < -3.89) {
return 0;
} else if (zscore > 3.89) {
return 1;
}
float ret = 0;
float temp = -3.89f;
while (temp <= zscore) {
ret += 0.0001f * fx(temp);
temp += 0.0001f;
}
return ret;
}
public double getConversionRate(double total, double real) {
return real / total;
}
private float fx(float zscore) {
float ret = 0;
double a = 1.0 / Math.sqrt(Math.PI * 2);
a = a * Math.pow(Math.E, -0.5 * Math.pow(zscore, 2));
ret = (float) a;
return ret;
}
/*
* 95% confidence interval
*/
public double getSampleSize(double crActual, double crExpected) {
double zscore = 1.65;
double diff = crActual - crExpected;
return zscore * zscore * (crActual + crExpected - crActual * crActual - crExpected * crExpected) / (diff * diff);
}
public double getStandardError(double conversionRate, double size) {
return Math.sqrt(conversionRate * (1 - conversionRate) / size);
}
public double getZsore(double cr1, double cr2, double se1, double se2) {
return Math.abs((cr1 - cr2) / Math.sqrt(se1 * se1 + se2 * se2));
}
}
package com.dianping.cat.system.page.abtest.conditions;
import java.util.List;
public interface ScriptProvider {
public List<String> actions();
}
此差异已折叠。
.rickshaw_graph .detail{pointer-events:none;position:absolute;top:0;z-index:2;background:rgba(0,0,0,.1);bottom:0;width:1px;transition:opacity .25s linear;-moz-transition:opacity .25s linear;-o-transition:opacity .25s linear;-webkit-transition:opacity .25s linear}.rickshaw_graph .detail.inactive{opacity:0}.rickshaw_graph .detail .item.active{opacity:1}.rickshaw_graph .detail .x_label{font-family:Arial,sans-serif;border-radius:3px;padding:6px;opacity:.5;border:1px solid #e0e0e0;font-size:12px;position:absolute;background:#fff;white-space:nowrap}.rickshaw_graph .detail .item{position:absolute;z-index:2;border-radius:3px;padding:.25em;font-size:12px;font-family:Arial,sans-serif;opacity:0;background:rgba(0,0,0,.4);color:#fff;border:1px solid rgba(0,0,0,.4);margin-left:1em;margin-top:-1em;white-space:nowrap}.rickshaw_graph .detail .item.active{opacity:1;background:rgba(0,0,0,.8)}.rickshaw_graph .detail .item:before{content:"\25c2";position:absolute;left:-.5em;color:rgba(0,0,0,.7);width:0}.rickshaw_graph .detail .dot{width:4px;height:4px;margin-left:-4px;margin-top:-3px;border-radius:5px;position:absolute;box-shadow:0 0 2px rgba(0,0,0,.6);background:#fff;border-width:2px;border-style:solid;display:none;background-clip:padding-box}.rickshaw_graph .detail .dot.active{display:block}.rickshaw_graph{position:relative}.rickshaw_graph svg{display:block;overflow:hidden}.rickshaw_graph .x_tick{position:absolute;top:0;bottom:0;width:0;border-left:1px dotted rgba(0,0,0,.2);pointer-events:none}.rickshaw_graph .x_tick .title{position:absolute;font-size:12px;font-family:Arial,sans-serif;opacity:.5;white-space:nowrap;margin-left:3px;bottom:1px}.rickshaw_annotation_timeline{height:1px;border-top:1px solid #e0e0e0;margin-top:10px;position:relative}.rickshaw_annotation_timeline .annotation{position:absolute;height:6px;width:6px;margin-left:-2px;top:-3px;border-radius:5px;background-color:rgba(0,0,0,.25)}.rickshaw_graph .annotation_line{position:absolute;top:0;bottom:-6px;width:0;border-left:2px solid rgba(0,0,0,.3);display:none}.rickshaw_graph .annotation_line.active{display:block}.rickshaw_graph .annotation_range{background:rgba(0,0,0,.1);display:none;position:absolute;top:0;bottom:-6px}.rickshaw_graph .annotation_range.active{display:block}.rickshaw_graph .annotation_range.active.offscreen{display:none}.rickshaw_annotation_timeline .annotation .content{background:#fff;color:#000;opacity:.9;padding:5px;box-shadow:0 0 2px rgba(0,0,0,.8);border-radius:3px;position:relative;z-index:20;font-size:12px;padding:6px 8px 8px;top:18px;left:-11px;width:160px;display:none;cursor:pointer}.rickshaw_annotation_timeline .annotation .content:before{content:"\25b2";position:absolute;top:-11px;color:#fff;text-shadow:0 -1px 1px rgba(0,0,0,.8)}.rickshaw_annotation_timeline .annotation.active,.rickshaw_annotation_timeline .annotation:hover{background-color:rgba(0,0,0,.8);cursor:none}.rickshaw_annotation_timeline .annotation .content:hover{z-index:50}.rickshaw_annotation_timeline .annotation.active .content{display:block}.rickshaw_annotation_timeline .annotation:hover .content{display:block;z-index:50}.rickshaw_graph .y_axis,.rickshaw_graph .x_axis_d3{fill:none}.rickshaw_graph .y_ticks .tick,.rickshaw_graph .x_ticks_d3 .tick{stroke:rgba(0,0,0,.16);stroke-width:2px;shape-rendering:crisp-edges;pointer-events:none}.rickshaw_graph .y_grid .tick,.rickshaw_graph .x_grid_d3 .tick{z-index:-1;stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:1 1}.rickshaw_graph .y_grid path,.rickshaw_graph .x_grid_d3 path{fill:none;stroke:none}.rickshaw_graph .y_ticks path,.rickshaw_graph .x_ticks_d3 path{fill:none;stroke:gray}.rickshaw_graph .y_ticks text,.rickshaw_graph .x_ticks_d3 text{opacity:.5;font-size:12px;pointer-events:none}.rickshaw_graph .x_tick.glow .title,.rickshaw_graph .y_ticks.glow text{fill:#000;color:#000;text-shadow:-1px 1px 0 rgba(255,255,255,.1),1px -1px 0 rgba(255,255,255,.1),1px 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1),0 -1px 0 rgba(255,255,255,.1),1px 0 0 rgba(255,255,255,.1),-1px 0 0 rgba(255,255,255,.1),-1px -1px 0 rgba(255,255,255,.1)}.rickshaw_graph .x_tick.inverse .title,.rickshaw_graph .y_ticks.inverse text{fill:#fff;color:#fff;text-shadow:-1px 1px 0 rgba(0,0,0,.8),1px -1px 0 rgba(0,0,0,.8),1px 1px 0 rgba(0,0,0,.8),0 1px 0 rgba(0,0,0,.8),0 -1px 0 rgba(0,0,0,.8),1px 0 0 rgba(0,0,0,.8),-1px 0 0 rgba(0,0,0,.8),-1px -1px 0 rgba(0,0,0,.8)}.rickshaw_legend{font-family:Arial;font-size:12px;color:#fff;background:#404040;display:inline-block;padding:12px 5px;border-radius:2px;position:relative}.rickshaw_legend:hover{z-index:10}.rickshaw_legend .swatch{width:10px;height:10px;border:1px solid rgba(0,0,0,.2)}.rickshaw_legend .line{clear:both;line-height:140%;padding-right:15px}.rickshaw_legend .line .swatch{display:inline-block;margin-right:3px;border-radius:2px}.rickshaw_legend .label{margin:0;white-space:nowrap;display:inline;font-size:inherit;background-color:transparent;color:inherit;font-weight:400;line-height:normal;padding:0;text-shadow:none}.rickshaw_legend .action:hover{opacity:.6}.rickshaw_legend .action{margin-right:.2em;font-size:10px;opacity:.2;cursor:pointer;font-size:14px}.rickshaw_legend .line.disabled{opacity:.4}.rickshaw_legend ul{list-style-type:none;margin:0;padding:0;margin:2px;cursor:pointer}.rickshaw_legend li{padding:0 0 0 2px;min-width:80px;white-space:nowrap}.rickshaw_legend li:hover{background:rgba(255,255,255,.08);border-radius:3px}.rickshaw_legend li:active{background:rgba(255,255,255,.2);border-radius:3px}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
<jsp:useBean id="ctx" type="com.dianping.cat.system.page.abtest.Context" scope="request" />${ctx.responseJson}
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册