提交 f5527137 编写于 作者: F Frankie Wu

initial commit for ABTest

- API (draft)
- SPI (draft)
上级 e3054bc5
......@@ -13,6 +13,7 @@ import org.unidal.initialization.DefaultModuleContext;
import org.unidal.initialization.Module;
import org.unidal.initialization.ModuleContext;
import com.dianping.cat.abtest.ABTestManager;
import com.dianping.cat.configuration.ClientConfigManager;
import com.dianping.cat.configuration.ClientConfigReloader;
import com.dianping.cat.configuration.client.entity.ClientConfig;
......@@ -53,6 +54,8 @@ public class CatCoreModule extends AbstractModule {
Threads.forGroup("Cat").start(new ClientConfigReloader(clientConfigFile.getAbsolutePath(), config));
}
}
ABTestManager.initialize();
}
@Override
......
package com.dianping.cat.abtest;
public interface ABTest {
public ABTestId getTestId();
public boolean isDefaultGroup();
public boolean isGroupA();
public boolean isGroupB();
public boolean isGroupC();
public boolean isGroupD();
public boolean isGroupE();
public boolean isGroup(String name);
}
package com.dianping.cat.abtest;
public interface ABTestId {
public int getValue();
}
package com.dianping.cat.abtest;
import javax.servlet.http.HttpServletRequest;
import org.unidal.lookup.ContainerLoader;
import com.dianping.cat.abtest.internal.DefaultABTest;
import com.dianping.cat.abtest.spi.ABTestContextManager;
public final class ABTestManager {
private static ABTestContextManager s_contextManager;
public static ABTest getTest(ABTestId id) {
initialize();
return new DefaultABTest(id, s_contextManager);
}
public static void initialize() {
if (s_contextManager == null) {
synchronized (ABTestManager.class) {
if (s_contextManager == null) {
try {
// it could be time-consuming due to load entities from the repository, i.e. database.
s_contextManager = ContainerLoader.getDefaultContainer().lookup(ABTestContextManager.class);
} catch (Exception e) {
throw new RuntimeException("Error when initializing ABTestContextManager!", e);
}
}
}
}
}
public static void onRequestBegin(HttpServletRequest req) {
initialize();
s_contextManager.onRequestBegin(req);
}
public static void onRequestEnd() {
s_contextManager.onRequestEnd();
}
}
package com.dianping.cat.abtest.internal;
import com.dianping.cat.abtest.ABTest;
import com.dianping.cat.abtest.ABTestId;
import com.dianping.cat.abtest.spi.ABTestContext;
import com.dianping.cat.abtest.spi.ABTestContextManager;
public class DefaultABTest implements ABTest {
private ABTestContextManager m_contextManager;
private ABTestId m_id;
public DefaultABTest(ABTestId id, ABTestContextManager contextManager) {
m_contextManager = contextManager;
m_id = id;
}
@Override
public ABTestId getTestId() {
return m_id;
}
private String getGroupName() {
ABTestContext ctx = m_contextManager.getContext(m_id);
return ctx.getGroupName();
}
@Override
public boolean isDefaultGroup() {
return ABTestContext.DEFAULT_GROUP.equals(getGroupName());
}
@Override
public boolean isGroupA() {
return "A".equals(getGroupName());
}
@Override
public boolean isGroupB() {
return "B".equals(getGroupName());
}
@Override
public boolean isGroupC() {
return "C".equals(getGroupName());
}
@Override
public boolean isGroupD() {
return "D".equals(getGroupName());
}
@Override
public boolean isGroupE() {
return "E".equals(getGroupName());
}
@Override
public boolean isGroup(String name) {
return name.equals(getGroupName());
}
}
package com.dianping.cat.abtest.spi;
import javax.servlet.http.HttpServletRequest;
public interface ABTestContext {
public final String DEFAULT_GROUP = "default";
public ABTestEntity getEntity();
public String getGroupName();
public void setGroupName(String groupName);
public HttpServletRequest getHttpServletRequest();
}
package com.dianping.cat.abtest.spi;
import javax.servlet.http.HttpServletRequest;
import com.dianping.cat.abtest.ABTestId;
public interface ABTestContextManager {
public ABTestContext getContext(ABTestId testId);
public void onRequestBegin(HttpServletRequest req);
public void onRequestEnd();
}
package com.dianping.cat.abtest.spi;
public class ABTestEntity {
private int m_id;
private String m_name;
private String m_groupStrategy;
private String m_groupStrategyConfiguration;
private boolean m_active;
public String getGroupStrategy() {
return m_groupStrategy;
}
public String getGroupStrategyConfiguration() {
return m_groupStrategyConfiguration;
}
public int getId() {
return m_id;
}
public String getName() {
return m_name;
}
public boolean isActive() {
return m_active;
}
public void setActive(boolean active) {
m_active = active;
}
public void setGroupStrategy(String groupStrategy) {
m_groupStrategy = groupStrategy;
}
public void setGroupStrategyConfiguration(String groupStrategyConfiguration) {
m_groupStrategyConfiguration = groupStrategyConfiguration;
}
public void setId(int id) {
m_id = id;
}
public void setName(String name) {
m_name = name;
}
}
package com.dianping.cat.abtest.spi;
import com.dianping.cat.abtest.ABTestId;
public interface ABTestEntityManager {
public ABTestEntity getEntity(ABTestId id);
}
package com.dianping.cat.abtest.spi;
public interface ABTestGroupStrategy {
public void apply(ABTestContext ctx);
}
package com.dianping.cat.abtest.spi.internal;
import javax.servlet.http.HttpServletRequest;
import com.dianping.cat.abtest.spi.ABTestContext;
import com.dianping.cat.abtest.spi.ABTestEntity;
public class DefaultABTestContext implements ABTestContext {
private String m_groupName = DEFAULT_GROUP;
private HttpServletRequest m_req;
private ABTestEntity m_entity;
public DefaultABTestContext(ABTestEntity entity) {
m_entity = entity;
}
@Override
public String getGroupName() {
return m_groupName;
}
@Override
public void setGroupName(String groupName) {
m_groupName = groupName;
}
public void setup(HttpServletRequest req) {
m_req = req;
}
@Override
public HttpServletRequest getHttpServletRequest() {
return m_req;
}
@Override
public ABTestEntity getEntity() {
return m_entity;
}
}
package com.dianping.cat.abtest.spi.internal;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.unidal.lookup.annotation.Inject;
import com.dianping.cat.abtest.ABTestId;
import com.dianping.cat.abtest.spi.ABTestContext;
import com.dianping.cat.abtest.spi.ABTestContextManager;
import com.dianping.cat.abtest.spi.ABTestEntity;
import com.dianping.cat.abtest.spi.ABTestEntityManager;
public class DefaultABTestContextManager implements ABTestContextManager {
@Inject
private ABTestEntityManager m_entityManager;
private InheritableThreadLocal<Entry> m_threadLocal = new InheritableThreadLocal<Entry>() {
@Override
protected Entry initialValue() {
return new Entry();
}
};
@Override
public ABTestContext getContext(ABTestId testId) {
Entry entry = m_threadLocal.get();
Map<Integer, DefaultABTestContext> map = entry.getContextMap();
int id = testId.getValue();
DefaultABTestContext ctx = map.get(id);
if (ctx == null) {
ABTestEntity entity = m_entityManager.getEntity(testId);
ctx = new DefaultABTestContext(entity);
ctx.setup(entry.getHttpServletRequest());
map.put(id, ctx);
}
return ctx;
}
@Override
public void onRequestEnd() {
m_threadLocal.remove();
}
@Override
public void onRequestBegin(HttpServletRequest req) {
Entry entry = m_threadLocal.get();
entry.setHttpServletRequest(req);
Map<Integer, DefaultABTestContext> map = entry.getContextMap();
for (DefaultABTestContext ctx : map.values()) {
ctx.setup(req);
}
}
static class Entry {
private Map<Integer, DefaultABTestContext> m_map = new HashMap<Integer, DefaultABTestContext>(4);
private HttpServletRequest m_req;
public Map<Integer, DefaultABTestContext> getContextMap() {
return m_map;
}
public HttpServletRequest getHttpServletRequest() {
return m_req;
}
public void setHttpServletRequest(HttpServletRequest req) {
m_req = req;
}
}
}
package com.dianping.cat.abtest.spi.internal;
import java.util.HashMap;
import java.util.Map;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import com.dianping.cat.abtest.ABTestId;
import com.dianping.cat.abtest.spi.ABTestEntity;
import com.dianping.cat.abtest.spi.ABTestEntityManager;
public class DefaultABTestEntityManager implements ABTestEntityManager, Initializable {
private Map<Integer, ABTestEntity> m_entities = new HashMap<Integer, ABTestEntity>();
@Override
public ABTestEntity getEntity(ABTestId id) {
ABTestEntity entity = m_entities.get(id.getValue());
if (entity == null) {
entity = new ABTestEntity();
entity.setActive(false);
m_entities.put(id.getValue(), entity);
}
return entity;
}
@Override
public void initialize() throws InitializationException {
// TODO
}
}
package com.dianping.cat.build;
import java.util.ArrayList;
import java.util.List;
import org.unidal.lookup.configuration.AbstractResourceConfigurator;
import org.unidal.lookup.configuration.Component;
import com.dianping.cat.abtest.spi.ABTestContextManager;
import com.dianping.cat.abtest.spi.ABTestEntityManager;
import com.dianping.cat.abtest.spi.internal.DefaultABTestContextManager;
import com.dianping.cat.abtest.spi.internal.DefaultABTestEntityManager;
class ABTestComponentConfigurator extends AbstractResourceConfigurator {
@Override
public List<Component> defineComponents() {
List<Component> all = new ArrayList<Component>();
all.add(C(ABTestContextManager.class, DefaultABTestContextManager.class) //
.req(ABTestEntityManager.class));
all.add(C(ABTestEntityManager.class, DefaultABTestEntityManager.class));
return all;
}
}
......@@ -3,6 +3,10 @@ package com.dianping.cat.build;
import java.util.ArrayList;
import java.util.List;
import org.unidal.initialization.Module;
import org.unidal.lookup.configuration.AbstractResourceConfigurator;
import org.unidal.lookup.configuration.Component;
import com.dianping.cat.CatCoreModule;
import com.dianping.cat.configuration.ClientConfigManager;
import com.dianping.cat.configuration.ServerConfigManager;
......@@ -42,9 +46,6 @@ import com.dianping.cat.storage.dump.LocalMessageBucket;
import com.dianping.cat.storage.dump.LocalMessageBucketManager;
import com.dianping.cat.storage.dump.MessageBucket;
import com.dianping.cat.storage.dump.MessageBucketManager;
import org.unidal.initialization.Module;
import org.unidal.lookup.configuration.AbstractResourceConfigurator;
import org.unidal.lookup.configuration.Component;
public class ComponentsConfigurator extends AbstractResourceConfigurator {
@Override
......@@ -111,6 +112,7 @@ public class ComponentsConfigurator extends AbstractResourceConfigurator {
all.addAll(new CodecComponentConfigurator().defineComponents());
all.addAll(new StorageComponentConfigurator().defineComponents());
all.addAll(new ABTestComponentConfigurator().defineComponents());
return all;
}
......
......@@ -13,6 +13,7 @@ import javax.servlet.http.HttpServletRequest;
import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.abtest.ABTestManager;
import com.dianping.cat.message.Event;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.MessageProducer;
......@@ -24,13 +25,13 @@ 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 {
HttpServletRequest req = (HttpServletRequest) request;
String sessionToken = getSessionIdFromCookie(req);
// setup for thread local data
Cat.setup(sessionToken);
ABTestManager.onRequestBegin(req);
MessageProducer cat = Cat.getProducer();
Transaction t = cat.newTransaction(CatConstants.TYPE_URL, getOriginalUrl(request));
......@@ -66,6 +67,7 @@ public class CatFilter implements Filter {
} finally {
t.complete();
Cat.reset();
ABTestManager.onRequestEnd();
}
}
......
......@@ -302,5 +302,18 @@
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.abtest.spi.ABTestContextManager</role>
<implementation>com.dianping.cat.abtest.spi.internal.DefaultABTestContextManager</implementation>
<requirements>
<requirement>
<role>com.dianping.cat.abtest.spi.ABTestEntityManager</role>
</requirement>
</requirements>
</component>
<component>
<role>com.dianping.cat.abtest.spi.ABTestEntityManager</role>
<implementation>com.dianping.cat.abtest.spi.internal.DefaultABTestEntityManager</implementation>
</component>
</components>
</plexus>
package com.dianping.cat.abtest.sample;
import org.junit.Test;
import com.dianping.cat.abtest.ABTest;
import com.dianping.cat.abtest.ABTestId;
import com.dianping.cat.abtest.ABTestManager;
public class SampleTest {
public static ABTest abtest1 = ABTestManager.getTest(MyABTestId.CASE1);
public static ABTest abtest2 = ABTestManager.getTest(MyABTestId.CASE2);
@Test
public void usage() {
// some initialization for case 1
if (abtest1.isGroupA()) {
// Cat.logMetric(...);
} else if (abtest1.isGroupB()) {
// Cat.logMetric(...);
} else {
// Cat.logMetric(...);
}
// some cleanup for case 1
}
public static enum MyABTestId implements ABTestId {
CASE1(1001),
CASE2(1002);
private int m_id;
private MyABTestId(int id) {
m_id = id;
}
@Override
public int getValue() {
return m_id;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册