You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by dr...@apache.org on 2015/01/22 01:56:33 UTC

[09/50] [abbrv] directory-kerberos git commit: Many changes with newname

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-config/src/main/java/org/apache/kerby/config/XmlConfigLoader.java
----------------------------------------------------------------------
diff --git a/lib/kerby-config/src/main/java/org/apache/kerby/config/XmlConfigLoader.java b/lib/kerby-config/src/main/java/org/apache/kerby/config/XmlConfigLoader.java
new file mode 100644
index 0000000..2208abc
--- /dev/null
+++ b/lib/kerby-config/src/main/java/org/apache/kerby/config/XmlConfigLoader.java
@@ -0,0 +1,159 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.config;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.*;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class XmlConfigLoader extends ConfigLoader {
+    private static final Logger logger = LoggerFactory.getLogger(Config.class);
+
+    @Override
+    protected void loadConfig(ConfigImpl config, Resource resource) throws Exception {
+        Element doc = loadResourceDocument(resource);
+        loadConfig((ConfigImpl) config, doc);
+    }
+
+    private Element loadResourceDocument(Resource resource) throws Exception {
+        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
+
+        docBuilderFactory.setIgnoringComments(true);
+        docBuilderFactory.setNamespaceAware(true);
+        try {
+            docBuilderFactory.setXIncludeAware(true);
+        } catch (UnsupportedOperationException e) {
+            logger.error("Failed to set setXIncludeAware(true) for parser", e);
+        }
+        DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
+        InputStream is = (InputStream) resource.getResource();
+        Document doc = null;
+        try {
+            doc = builder.parse(is);
+        } finally {
+            is.close();
+        }
+
+        Element root = doc.getDocumentElement();
+        validateConfig(root);
+
+        return root;
+    }
+
+    private boolean validateConfig(Element root) {
+        boolean valid = false;
+
+        if ("config".equals(root.getTagName())) {
+            valid = true;
+        } else {
+            logger.error("bad conf element: top-level element not <configuration>");
+        }
+
+        return valid;
+    }
+
+    private void loadConfig(ConfigImpl conifg, Element element) {
+        String name;
+        ConfigObject value;
+
+        NodeList props = element.getChildNodes();
+        for (int i = 0; i < props.getLength(); i++) {
+            Node subNode = props.item(i);
+            if (!(subNode instanceof Element)) {
+                continue;
+            }
+
+            Element prop = (Element)subNode;
+            name = getElementName(prop);
+            if (name == null) {
+                continue;
+            }
+
+            value = null;
+            String tagName = prop.getTagName();
+            if ("property".equals(tagName) && prop.hasChildNodes()) {
+                value = loadProperty(prop);
+            } else if ("config".equals(tagName) && prop.hasChildNodes()) {
+                ConfigImpl cfg = new ConfigImpl(name);
+                loadConfig(cfg, prop);
+                value = new ConfigObject(cfg);
+            }
+
+            if (name != null) {
+                conifg.set(name, value);
+            }
+        }
+    }
+
+    private static ConfigObject loadProperty(Element ele) {
+        String value = null;
+        if (ele.getFirstChild() instanceof Text) {
+            value = ((Text)ele.getFirstChild()).getData();
+            return new ConfigObject(value);
+        }
+
+        ConfigObject result = null;
+        NodeList nodes = ele.getChildNodes();
+        List<String> values = new ArrayList<String>(nodes.getLength());
+        for (int i = 0; i < nodes.getLength(); i++) {
+            value = null;
+            Node valueNode = nodes.item(i);
+            if (!(valueNode instanceof Element))
+                continue;
+
+            Element valueEle = (Element)valueNode;
+            if ("value".equals(valueEle.getTagName()) && valueEle.hasChildNodes()) {
+                value = ((Text)valueEle.getFirstChild()).getData();
+            }
+
+            if (value != null) {
+                values.add(value);
+            }
+        }
+        return new ConfigObject(values);
+    }
+
+    private static String getElementName(Element ele) {
+        String name, value;
+        Node node;
+        Attr attr;
+
+        NamedNodeMap nnm = ele.getAttributes();
+        for (int i = 0; i < nnm.getLength(); ++i) {
+            node = nnm.item(i);
+            if (!(node instanceof Attr))
+                continue;
+            attr = (Attr) node;
+            name = attr.getName();
+            value = attr.getValue();
+
+            if ("name".equals(name)) {
+                return value;
+            }
+        }
+        return null;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-config/src/test/java/org/apache/kerby/config/ConfTest.java
----------------------------------------------------------------------
diff --git a/lib/kerby-config/src/test/java/org/apache/kerby/config/ConfTest.java b/lib/kerby-config/src/test/java/org/apache/kerby/config/ConfTest.java
new file mode 100644
index 0000000..9a7ffdb
--- /dev/null
+++ b/lib/kerby-config/src/test/java/org/apache/kerby/config/ConfTest.java
@@ -0,0 +1,133 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *
+ */
+package org.apache.kerby.config;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * The test is base on the Conf level.
+ * We hope users use the Conf object only, and don't need to care about its internal implementation.
+ */
+public class ConfTest {
+
+    @Test
+    public void testMapConfig() {
+        String strProp = "hello";
+        Integer intProp = 123456;
+        Boolean boolProp = true;
+        Map<String, String> mapConfig = new HashMap<String, String>();
+        mapConfig.put("strProp", strProp);
+        mapConfig.put("intProp", String.valueOf(intProp));
+        mapConfig.put("boolProp", String.valueOf(boolProp));
+
+        Conf conf = new Conf();
+        conf.addMapConfig(mapConfig);
+        Assert.assertEquals(conf.getString("strProp"), strProp);
+        Assert.assertEquals(conf.getInt("intProp"), intProp);
+        Assert.assertEquals(conf.getBoolean("boolProp"), boolProp);
+    }
+
+    @Test
+    public void testPropertiesConfig() {
+        String strProp = "hello";
+        Integer intProp = 123456;
+        Boolean boolProp = true;
+        Properties properties = new Properties();
+        properties.setProperty("strProp", strProp);
+        properties.setProperty("intProp", String.valueOf(intProp));
+        properties.setProperty("boolProp", String.valueOf(boolProp));
+
+        Conf conf = new Conf();
+        conf.addPropertiesConfig(properties);
+        Assert.assertEquals(conf.getString("strProp"), strProp);
+        Assert.assertEquals(conf.getInt("intProp"), intProp);
+        Assert.assertEquals(conf.getBoolean("boolProp"), boolProp);
+    }
+
+    /**
+     * Test for whether can get right value form the conf which contains many config resources.
+     */
+    @Test
+    public void testMixedConfig() {
+        String mapStrProp = "hello map";
+        Integer intProp = 123456;
+        Map<String, String> mapConfig = new HashMap<String, String>();
+        mapConfig.put("mapStrProp", mapStrProp);
+        mapConfig.put("intProp", String.valueOf(intProp));
+
+        String propertiesStrProp = "hello properties";
+        Boolean boolProp = true;
+        Properties properties = new Properties();
+        properties.setProperty("propertiesStrProp", propertiesStrProp);
+        properties.setProperty("boolProp", String.valueOf(boolProp));
+
+        Conf conf = new Conf();
+        conf.addMapConfig(mapConfig);
+        conf.addPropertiesConfig(properties);
+        Assert.assertEquals(conf.getConfig("mapConfig"), null);
+        Assert.assertEquals(conf.getString("mapStrProp"), mapStrProp);
+        Assert.assertEquals(conf.getString("propertiesStrProp"), propertiesStrProp);
+        Assert.assertEquals(conf.getInt("intProp"), intProp);
+        Assert.assertEquals(conf.getBoolean("boolProp"), boolProp);
+    }
+
+    static enum TestConfKey implements ConfigKey {
+        ADDRESS("127.0.0.1"),
+        PORT(8015),
+        ENABLE(false);
+
+        private Object defaultValue;
+
+        private TestConfKey(Object defaultValue) {
+            this.defaultValue = defaultValue;
+        }
+
+        @Override
+        public String getPropertyKey() {
+            return name().toLowerCase();
+        }
+
+        @Override
+        public Object getDefaultValue() {
+            return this.defaultValue;
+        }
+    }
+
+    @Test
+    public void testConfKey() {
+        Conf conf = new Conf();
+        Assert.assertEquals(conf.getString(TestConfKey.ADDRESS),
+                TestConfKey.ADDRESS.getDefaultValue());
+        Map<String, String> mapConfig = new HashMap<String, String>();
+        String myAddress = "www.google.com";
+        mapConfig.put(TestConfKey.ADDRESS.getPropertyKey(), myAddress);
+        conf.addMapConfig(mapConfig);
+        Assert.assertEquals(conf.getString(TestConfKey.ADDRESS), myAddress);
+        Assert.assertEquals(conf.getInt(TestConfKey.PORT),
+                TestConfKey.PORT.getDefaultValue());
+        Assert.assertEquals(conf.getBoolean(TestConfKey.ENABLE),
+                TestConfKey.ENABLE.getDefaultValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-config/src/test/java/org/apache/kerby/config/ConfigImplTest.java
----------------------------------------------------------------------
diff --git a/lib/kerby-config/src/test/java/org/apache/kerby/config/ConfigImplTest.java b/lib/kerby-config/src/test/java/org/apache/kerby/config/ConfigImplTest.java
new file mode 100644
index 0000000..1834a9f
--- /dev/null
+++ b/lib/kerby-config/src/test/java/org/apache/kerby/config/ConfigImplTest.java
@@ -0,0 +1,62 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.config;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * The test is on ConfigImpl level.
+ * ConfigImpl is the internal implementation of Conf, only visual by developers.
+ */
+public class ConfigImplTest {
+
+    /**
+     * Test for section config support.
+     */
+    @Test
+    public void testSectionConfig() {
+        ConfigImpl rootConfig = new ConfigImpl(null);
+        rootConfig.set("globalConfig", "true");
+
+        ConfigImpl sectionA = new ConfigImpl("libdefaults");
+        rootConfig.set("libdefaults", sectionA);
+        sectionA.set("default_realm", "EXAMPLE.COM");
+        sectionA.set("forwardable", "true");
+        sectionA.set("dns_lookup_realm", "false");
+
+        ConfigImpl sectionB = new ConfigImpl("logging");
+        rootConfig.set("logging", sectionB);
+        sectionB.set("kdc", "FILE:/var/log/krb5kdc.log");
+
+        Assert.assertEquals(rootConfig.getString("globalConfig"), "true");
+        Assert.assertEquals(rootConfig.getString("default_realm"), null);
+
+        Config subA = rootConfig.getConfig("libdefaults");
+        Assert.assertEquals(subA.getString("default_realm"), "EXAMPLE.COM");
+        Assert.assertEquals(subA.getString("globalConfig"), null);
+        Assert.assertEquals(subA.getString("kdc"), null);
+
+        Config subB = rootConfig.getConfig("logging");
+        Assert.assertEquals(subB.getString("kdc"), "FILE:/var/log/krb5kdc.log");
+        Assert.assertEquals(subB.getString("globalConfig"), null);
+        Assert.assertEquals(subB.getBoolean("forwardable"), null);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-config/src/test/java/org/apache/kerby/config/IniConfigTest.java
----------------------------------------------------------------------
diff --git a/lib/kerby-config/src/test/java/org/apache/kerby/config/IniConfigTest.java b/lib/kerby-config/src/test/java/org/apache/kerby/config/IniConfigTest.java
new file mode 100644
index 0000000..f71e5a1
--- /dev/null
+++ b/lib/kerby-config/src/test/java/org/apache/kerby/config/IniConfigTest.java
@@ -0,0 +1,76 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.config;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class IniConfigTest {
+
+    private final static String TEST_DIR = new File(System.getProperty(
+            "test.build.data", "/tmp")).getAbsolutePath();
+    private final static File TEST_FILE = new File(TEST_DIR, "test-ini-config");
+
+    /**
+     * Build a INI format configuration file.
+     */
+    private void buildFile() throws IOException {
+        PrintWriter out = new PrintWriter(new FileWriter(TEST_FILE));
+        out.println("#note = notenote");
+        out.println("default = FILE:/var/log/krb5libs.log");
+        out.println("kdc = FILE:/var/log/krb5kdc.log");
+        out.println("admin_server = FILE:/var/log/kadmind.log");
+        out.println("[libdefaults]");
+        out.println("default_realm = EXAMPLE.COM");
+        out.println("dns_lookup_realm = false");
+        out.println("dns_lookup_kdc = false");
+        out.println("ticket_lifetime = 24h");
+        out.println("renew_lifetime = 7d");
+        out.println("forwardable = true");
+        out.println("[lib1]");
+        out.println("default_realm = EXAMPLE.COM1");
+        out.println("dns_lookup_realm = true");
+        out.close();
+    }
+
+    @Test
+    public void testIniConfig() throws IOException {
+        buildFile();
+
+        Conf conf = new Conf();
+        conf.addIniConfig(TEST_FILE);
+
+        Assert.assertEquals(conf.getString("default"), "FILE:/var/log/krb5libs.log");
+        Assert.assertEquals(conf.getString("#note"), null);//Comments should be ignored when loading.
+
+        Config config = conf.getConfig("libdefaults");
+        Assert.assertFalse(config.getBoolean("dns_lookup_realm"));
+        Assert.assertTrue(config.getBoolean("forwardable"));
+
+        Config config1 = conf.getConfig("lib1");
+        Assert.assertTrue(config1.getBoolean("dns_lookup_realm"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/README
----------------------------------------------------------------------
diff --git a/lib/kerby-event/README b/lib/kerby-event/README
new file mode 100644
index 0000000..cb3b88a
--- /dev/null
+++ b/lib/kerby-event/README
@@ -0,0 +1 @@
+An event driven application framework with mixed (TCP, UDP) x (connector, acceptor) supported.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/pom.xml
----------------------------------------------------------------------
diff --git a/lib/kerby-event/pom.xml b/lib/kerby-event/pom.xml
new file mode 100644
index 0000000..af1e11a
--- /dev/null
+++ b/lib/kerby-event/pom.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License. See accompanying LICENSE file.
+-->
+<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">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>lib</artifactId>
+    <groupId>org.apache.kerby</groupId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>kerby-event</artifactId>
+  <name>Kerby Event</name>
+  <description>Kerby Event and Transport facilities for both client and server</description>
+
+</project>

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/AbstractEventHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/AbstractEventHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/AbstractEventHandler.java
new file mode 100644
index 0000000..59a0a82
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/AbstractEventHandler.java
@@ -0,0 +1,55 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+public abstract class AbstractEventHandler implements EventHandler {
+
+    private Dispatcher dispatcher;
+
+    public AbstractEventHandler() {
+
+    }
+
+    protected void dispatch(Event event) {
+        dispatcher.dispatch(event);
+    }
+
+    @Override
+    public Dispatcher getDispatcher() {
+        return dispatcher;
+    }
+
+    @Override
+    public void setDispatcher(Dispatcher dispatcher) {
+        this.dispatcher = dispatcher;
+    }
+
+    @Override
+    public void handle(Event event) {
+        try {
+            doHandle(event);
+        } catch (Exception e) {
+            throw new RuntimeException(event.toString(), e);
+        }
+    }
+
+    protected abstract void doHandle(Event event) throws Exception;
+}
+

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/AbstractInternalEventHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/AbstractInternalEventHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/AbstractInternalEventHandler.java
new file mode 100644
index 0000000..bfed126
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/AbstractInternalEventHandler.java
@@ -0,0 +1,66 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public abstract class AbstractInternalEventHandler extends AbstractEventHandler
+        implements InternalEventHandler {
+
+    private int id = -1;
+    protected EventHandler handler;
+
+    private static AtomicInteger idGen = new AtomicInteger(1);
+
+    public AbstractInternalEventHandler() {
+        super();
+
+        this.id = idGen.getAndIncrement();
+
+        init();
+    }
+
+    public AbstractInternalEventHandler(EventHandler handler) {
+        this();
+
+        this.handler = handler;
+    }
+
+    protected void setEventHandler(EventHandler handler) {
+        this.handler = handler;
+    }
+
+    @Override
+    public int id() {
+        return id;
+    }
+
+    public abstract void init();
+
+    protected void process(Event event) {
+        handler.handle(event);
+    }
+
+    @Override
+    public EventType[] getInterestedEvents() {
+        return handler.getInterestedEvents();
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/BufferedEventHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/BufferedEventHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/BufferedEventHandler.java
new file mode 100644
index 0000000..39fca9f
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/BufferedEventHandler.java
@@ -0,0 +1,53 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+/**
+ * An EventHandler wrapper buffering events and processing them later
+ */
+public abstract class BufferedEventHandler extends AbstractInternalEventHandler {
+
+    protected BlockingQueue<Event> eventQueue;
+
+    public BufferedEventHandler(EventHandler handler) {
+        super(handler);
+    }
+
+    public BufferedEventHandler() {
+        super();
+    }
+
+    @Override
+    public void init() {
+        this.eventQueue = new ArrayBlockingQueue<Event>(2);
+    }
+
+    @Override
+    protected void doHandle(Event event) throws Exception {
+        try {
+            eventQueue.put(event);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/Dispatcher.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/Dispatcher.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/Dispatcher.java
new file mode 100644
index 0000000..f5a9f53
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/Dispatcher.java
@@ -0,0 +1,29 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+public interface Dispatcher {
+
+    public void dispatch(Event event);
+
+    public void register(EventHandler handler);
+
+    public void register(InternalEventHandler internalHandler);
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/Event.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/Event.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/Event.java
new file mode 100644
index 0000000..332ee0d
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/Event.java
@@ -0,0 +1,43 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+public class Event {
+
+    private EventType eventType;
+    private Object eventData;
+
+    public Event(EventType eventType) {
+        this.eventType = eventType;
+    }
+
+    public Event(EventType eventType, Object eventData) {
+        this.eventType = eventType;
+        this.eventData = eventData;
+    }
+
+    public EventType getEventType() {
+        return eventType;
+    }
+
+    public Object getEventData() {
+        return eventData;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/EventHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/EventHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/EventHandler.java
new file mode 100644
index 0000000..b9ef871
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/EventHandler.java
@@ -0,0 +1,31 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+public interface EventHandler {
+
+    public void handle(Event event);
+
+    public EventType[] getInterestedEvents();
+
+    public Dispatcher getDispatcher();
+
+    public void setDispatcher(Dispatcher dispatcher);
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/EventHub.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/EventHub.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/EventHub.java
new file mode 100644
index 0000000..931455a
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/EventHub.java
@@ -0,0 +1,192 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class EventHub implements Dispatcher {
+
+    private enum BuiltInEventType implements EventType {
+        STOP,
+        ALL
+    }
+
+    private boolean started = false;
+
+    private Map<Integer, InternalEventHandler> handlers =
+            new ConcurrentHashMap<Integer, InternalEventHandler>();
+
+    private Map<EventType, Set<Integer>> eventHandlersMap =
+        new ConcurrentHashMap<EventType, Set<Integer>>();
+
+    private InternalEventHandler builtInHandler;
+
+    class BuiltInEventHandler extends AbstractEventHandler {
+        public BuiltInEventHandler() {
+            super();
+        }
+
+        @Override
+        protected void doHandle(Event event) {
+
+        }
+
+        @Override
+        public EventType[] getInterestedEvents() {
+            return BuiltInEventType.values();
+        }
+    }
+
+    public EventHub() {
+        init();
+    }
+
+    private void init() {
+        EventHandler eh = new BuiltInEventHandler();
+        builtInHandler = new ExecutedEventHandler(eh);
+        register(builtInHandler);
+    }
+
+    @Override
+    public void dispatch(Event event) {
+        process(event);
+    }
+
+    @Override
+    public void register(EventHandler handler) {
+        handler.setDispatcher(this);
+        InternalEventHandler ieh = new ExecutedEventHandler(handler);
+        register(ieh);
+    }
+
+    @Override
+    public void register(InternalEventHandler handler) {
+        handler.setDispatcher(this);
+        handler.init();
+        handlers.put(handler.id(), handler);
+
+        if (started) {
+            handler.start();
+        }
+
+        EventType[] interestedEvents = handler.getInterestedEvents();
+        Set<Integer> tmpHandlers;
+        for (EventType eventType : interestedEvents) {
+            if (eventHandlersMap.containsKey(eventType)) {
+                tmpHandlers = eventHandlersMap.get(eventType);
+            } else {
+                tmpHandlers = new HashSet<Integer>();
+                eventHandlersMap.put(eventType, tmpHandlers);
+            }
+            tmpHandlers.add(handler.id());
+        }
+    }
+
+    public EventWaiter waitEvent(final EventType event) {
+        return waitEvent(new EventType[] { event } );
+    }
+
+    public EventWaiter waitEvent(final EventType... events) {
+        EventHandler handler = new AbstractEventHandler() {
+            @Override
+            protected void doHandle(Event event) throws Exception {
+                // no op;
+            }
+
+            @Override
+            public EventType[] getInterestedEvents() {
+                return events;
+            }
+        };
+
+        handler.setDispatcher(this);
+        final WaitEventHandler waitEventHandler = new WaitEventHandler(handler);
+        register(waitEventHandler);
+        EventWaiter waiter = new EventWaiter() {
+            @Override
+            public Event waitEvent(EventType event) {
+                return waitEventHandler.waitEvent(event);
+            }
+
+            @Override
+            public Event waitEvent() {
+                return waitEventHandler.waitEvent();
+            }
+
+            @Override
+            public Event waitEvent(EventType event, long timeout,
+                                   TimeUnit timeUnit) throws TimeoutException {
+                return waitEventHandler.waitEvent(event, timeout, timeUnit);
+            }
+
+            @Override
+            public Event waitEvent(long timeout, TimeUnit timeUnit) throws TimeoutException {
+                return waitEventHandler.waitEvent(timeout, timeUnit);
+            }
+        };
+
+        return waiter;
+    }
+
+    private void process(Event event) {
+        EventType eventType = event.getEventType();
+        InternalEventHandler handler;
+        Set<Integer> handlerIds;
+
+        if (eventHandlersMap.containsKey(eventType)) {
+            handlerIds = eventHandlersMap.get(eventType);
+            for (Integer hid : handlerIds) {
+                handler = handlers.get(hid);
+                handler.handle(event);
+            }
+        }
+
+        if (eventHandlersMap.containsKey(BuiltInEventType.ALL)) {
+            handlerIds = eventHandlersMap.get(BuiltInEventType.ALL);
+            for (Integer hid : handlerIds) {
+                handler = handlers.get(hid);
+                handler.handle(event);
+            }
+        }
+    }
+
+    public void start() {
+        if (!started) {
+            for (InternalEventHandler handler : handlers.values()) {
+                handler.start();
+            }
+            started = true;
+        }
+    }
+
+    public void stop() {
+        if (started) {
+            for (InternalEventHandler handler : handlers.values()) {
+                handler.stop();
+            }
+            started = false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/EventType.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/EventType.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/EventType.java
new file mode 100644
index 0000000..6a4a453
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/EventType.java
@@ -0,0 +1,24 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+public interface EventType {
+    // no op
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/EventWaiter.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/EventWaiter.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/EventWaiter.java
new file mode 100644
index 0000000..5e6d7b1
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/EventWaiter.java
@@ -0,0 +1,35 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public interface EventWaiter {
+
+    public abstract Event waitEvent(EventType event);
+
+    public abstract Event waitEvent();
+
+    public abstract Event waitEvent(EventType event, long timeout, TimeUnit timeUnit) throws TimeoutException;
+
+    public abstract Event waitEvent(long timeout, TimeUnit timeUnit) throws TimeoutException;
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/ExecutedEventHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/ExecutedEventHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/ExecutedEventHandler.java
new file mode 100644
index 0000000..d094711
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/ExecutedEventHandler.java
@@ -0,0 +1,76 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * An EventHandler wrapper processing events using an ExecutorService
+ */
+public class ExecutedEventHandler extends AbstractInternalEventHandler {
+
+    private ExecutorService executorService;
+
+    public ExecutedEventHandler(EventHandler handler) {
+        super(handler);
+    }
+
+    @Override
+    protected void doHandle(final Event event) throws Exception {
+        if (executorService.isTerminated()) {
+            return;
+        }
+
+        executorService.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    process(event);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void start() {
+        executorService = Executors.newFixedThreadPool(2);
+    }
+
+    @Override
+    public void stop() {
+        if (executorService.isShutdown()) {
+            return;
+        }
+        executorService.shutdownNow();
+    }
+
+    @Override
+    public boolean isStopped() {
+        return executorService.isShutdown();
+    }
+
+    @Override
+    public void init() {
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/InternalEventHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/InternalEventHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/InternalEventHandler.java
new file mode 100644
index 0000000..6adff3c
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/InternalEventHandler.java
@@ -0,0 +1,34 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+public interface InternalEventHandler extends EventHandler {
+
+    public int id();
+
+    public void init();
+
+    public void start();
+
+    public void stop();
+
+    public boolean isStopped();
+}
+

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/LongRunningEventHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/LongRunningEventHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/LongRunningEventHandler.java
new file mode 100644
index 0000000..10c1f0b
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/LongRunningEventHandler.java
@@ -0,0 +1,77 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public abstract class LongRunningEventHandler extends BufferedEventHandler {
+
+    private ExecutorService executorService;
+
+    public LongRunningEventHandler(EventHandler handler) {
+        super(handler);
+    }
+
+    public LongRunningEventHandler() {
+        super();
+    }
+
+    protected abstract void loopOnce();
+
+    @Override
+    public void start() {
+        executorService = Executors.newFixedThreadPool(1);
+        executorService.execute(new Runnable() {
+            @Override
+            public void run() {
+                while (true) {
+
+                    processEvents();
+
+                    loopOnce();
+                }
+            }
+        });
+    }
+
+    @Override
+    public void stop() {
+        if (executorService.isShutdown()) {
+            return;
+        }
+        executorService.shutdownNow();
+    }
+
+    @Override
+    public boolean isStopped() {
+        return executorService.isShutdown();
+    }
+
+    protected void processEvents() {
+        while (! eventQueue.isEmpty()) {
+            try {
+                process(eventQueue.take());
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/event/WaitEventHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/event/WaitEventHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/event/WaitEventHandler.java
new file mode 100644
index 0000000..9edc230
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/event/WaitEventHandler.java
@@ -0,0 +1,128 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.event;
+
+import java.util.concurrent.*;
+
+public class WaitEventHandler extends BufferedEventHandler {
+
+    private ExecutorService executorService;
+
+    public WaitEventHandler(EventHandler handler) {
+        super(handler);
+    }
+
+    public Event waitEvent() {
+        return waitEvent(null);
+    }
+
+    public Event waitEvent(final EventType eventType) {
+        Future<Event> future = doWaitEvent(eventType);
+
+        try {
+            return future.get();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } catch (ExecutionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Event waitEvent(final EventType eventType,
+                           long timeout, TimeUnit timeUnit) throws TimeoutException {
+        Future<Event> future = doWaitEvent(eventType);
+
+        try {
+            return future.get(timeout, timeUnit);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } catch (ExecutionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Event waitEvent(long timeout, TimeUnit timeUnit) throws TimeoutException {
+        Future<Event> future = doWaitEvent(null);
+
+        try {
+            return future.get(timeout, timeUnit);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } catch (ExecutionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private Future<Event> doWaitEvent(final EventType eventType) {
+        Future<Event> future = executorService.submit(new Callable<Event>() {
+            @Override
+            public Event call() throws Exception {
+                if (eventType != null) {
+                    return checkEvent(eventType);
+                } else {
+                    return checkEvent();
+                }
+            }
+        });
+
+        return future;
+    }
+
+    private Event checkEvent() throws Exception {
+        return eventQueue.take();
+    }
+
+    private Event checkEvent(EventType eventType) throws Exception {
+        Event event = null;
+
+        while (true) {
+            if (eventQueue.size() == 1) {
+                if (eventQueue.peek().getEventType() == eventType) {
+                    return eventQueue.take();
+                }
+            } else {
+                event = eventQueue.take();
+                if (event.getEventType() == eventType) {
+                    return event;
+                } else {
+                    eventQueue.put(event); // put back since not wanted
+                }
+            }
+        }
+    }
+
+    @Override
+    public void start() {
+        executorService = Executors.newFixedThreadPool(2);
+    }
+
+    @Override
+    public void stop() {
+        if (executorService.isShutdown()) {
+            return;
+        }
+        executorService.shutdown();
+    }
+
+    @Override
+    public boolean isStopped() {
+        return executorService.isShutdown();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/Acceptor.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/Acceptor.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/Acceptor.java
new file mode 100644
index 0000000..8fa25d7
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/Acceptor.java
@@ -0,0 +1,36 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport;
+
+import java.net.InetSocketAddress;
+
+public abstract class Acceptor extends TransportSelector {
+
+    public Acceptor(TransportHandler transportHandler) {
+        super(transportHandler);
+    }
+
+    public void listen(String address, short listenPort) {
+        InetSocketAddress socketAddress = new InetSocketAddress(address, listenPort);
+        doListen(socketAddress);
+    }
+
+    protected abstract void doListen(InetSocketAddress socketAddress);
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/Connector.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/Connector.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/Connector.java
new file mode 100644
index 0000000..ece171f
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/Connector.java
@@ -0,0 +1,36 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport;
+
+import java.net.InetSocketAddress;
+
+public abstract class Connector extends TransportSelector {
+
+    public Connector(TransportHandler transportHandler) {
+        super(transportHandler);
+    }
+
+    public void connect(String serverAddress, short serverPort) {
+        InetSocketAddress sa = new InetSocketAddress(serverAddress, serverPort);
+        doConnect(sa);
+    }
+
+    protected abstract void doConnect(InetSocketAddress sa);
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/MessageHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/MessageHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/MessageHandler.java
new file mode 100644
index 0000000..d6ad01e
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/MessageHandler.java
@@ -0,0 +1,42 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport;
+
+import org.apache.kerby.event.AbstractEventHandler;
+import org.apache.kerby.event.Event;
+import org.apache.kerby.event.EventType;
+import org.apache.kerby.transport.event.MessageEvent;
+import org.apache.kerby.transport.event.TransportEventType;
+
+public abstract class MessageHandler extends AbstractEventHandler {
+
+    @Override
+    protected void doHandle(Event event) throws Exception {
+        handleMessage((MessageEvent) event);
+    }
+
+    protected abstract void handleMessage(MessageEvent event) throws Exception;
+
+    @Override
+    public EventType[] getInterestedEvents() {
+        return new EventType[] { TransportEventType.INBOUND_MESSAGE };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/Network.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/Network.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/Network.java
new file mode 100644
index 0000000..75f934d
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/Network.java
@@ -0,0 +1,298 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport;
+
+import org.apache.kerby.event.AbstractEventHandler;
+import org.apache.kerby.event.Event;
+import org.apache.kerby.event.EventType;
+import org.apache.kerby.event.LongRunningEventHandler;
+import org.apache.kerby.transport.event.AddressEvent;
+import org.apache.kerby.transport.event.TransportEvent;
+import org.apache.haox.transport.tcp.*;
+import org.apache.kerby.transport.tcp.*;
+import org.apache.kerby.transport.udp.UdpAddressEvent;
+import org.apache.kerby.transport.udp.UdpEventType;
+import org.apache.kerby.transport.udp.UdpTransport;
+import org.apache.kerby.transport.udp.UdpTransportHandler;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.nio.channels.*;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A combined and mixed network facility handling UDP and TCP in both connect and accept sides
+ */
+public class Network extends LongRunningEventHandler {
+
+    private Selector selector;
+    private StreamingDecoder streamingDecoder;
+    private UdpTransportHandler udpTransportHandler;
+    private TcpTransportHandler tcpTransportHandler;
+
+    class MyEventHandler extends AbstractEventHandler {
+        @Override
+        protected void doHandle(Event event) throws Exception {
+            if (event.getEventType() == UdpEventType.ADDRESS_CONNECT) {
+                doUdpConnect((AddressEvent) event);
+            } else if (event.getEventType() ==  UdpEventType.ADDRESS_BIND) {
+                doUdpBind((AddressEvent) event);
+            } else if (event.getEventType() ==  TcpEventType.ADDRESS_CONNECT) {
+                doTcpConnect((AddressEvent) event);
+            } else if (event.getEventType() ==  TcpEventType.ADDRESS_BIND) {
+                doTcpBind((AddressEvent) event);
+            }
+        }
+
+        @Override
+        public EventType[] getInterestedEvents() {
+            return new EventType[]{
+                    UdpEventType.ADDRESS_CONNECT,
+                    UdpEventType.ADDRESS_BIND,
+                    TcpEventType.ADDRESS_CONNECT,
+                    TcpEventType.ADDRESS_BIND
+            };
+        }
+    }
+
+    public Network() {
+        setEventHandler(new MyEventHandler());
+    }
+
+    @Override
+    public void init() {
+        super.init();
+
+        try {
+            selector = Selector.open();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * TCP transport only, for decoding tcp streaming into messages
+     * @param streamingDecoder
+     */
+    public void setStreamingDecoder(StreamingDecoder streamingDecoder) {
+        this.streamingDecoder = streamingDecoder;
+    }
+
+    /**
+     * TCP only. Connect on the given server address. Can be called multiple times
+     * for multiple servers
+     * @param serverAddress
+     * @param serverPort
+     */
+    public void tcpConnect(String serverAddress, short serverPort) {
+        InetSocketAddress sa = new InetSocketAddress(serverAddress, serverPort);
+        checkTcpTransportHandler();
+        doTcpConnect(sa);
+    }
+
+    /**
+     * UDP only. Connect on the given server address. Can be called multiple times
+     * for multiple servers
+     * @param serverAddress
+     * @param serverPort
+     */
+    public void udpConnect(String serverAddress, short serverPort) {
+        InetSocketAddress sa = new InetSocketAddress(serverAddress, serverPort);
+        checkUdpTransportHandler();
+        doUdpConnect(sa);
+    }
+
+    /**
+     * TCP only. Listen and accept connections on the address. Can be called multiple
+     * times for multiple server addresses.
+     * @param serverAddress
+     * @param serverPort
+     */
+    public void tcpListen(String serverAddress, short serverPort) {
+        InetSocketAddress sa = new InetSocketAddress(serverAddress, serverPort);
+        checkTcpTransportHandler();
+        doTcpListen(sa);
+    }
+
+    /**
+     * UDP only. Listen and accept connections on the address. Can be called multiple
+     * times for multiple server addresses.
+     * @param serverAddress
+     * @param serverPort
+     */
+    public void udpListen(String serverAddress, short serverPort) {
+        InetSocketAddress sa = new InetSocketAddress(serverAddress, serverPort);
+        checkUdpTransportHandler();
+        doUdpListen(sa);
+    }
+
+    @Override
+    protected void loopOnce() {
+        try {
+            selectOnce();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected void selectOnce() throws IOException {
+        if (selector.isOpen() && selector.select(2) > 0 && selector.isOpen()) {
+            Set<SelectionKey> selectionKeys = selector.selectedKeys();
+            Iterator<SelectionKey> iterator = selectionKeys.iterator();
+            while (iterator.hasNext()) {
+                SelectionKey selectionKey = iterator.next();
+                dealKey(selectionKey);
+                iterator.remove();
+            }
+            selectionKeys.clear();
+        }
+    }
+
+    private void checkTcpTransportHandler() {
+        if (tcpTransportHandler == null) {
+            if (streamingDecoder == null) {
+                throw new IllegalArgumentException("No streaming decoder set yet");
+            }
+            tcpTransportHandler = new TcpTransportHandler(streamingDecoder);
+            getDispatcher().register(tcpTransportHandler);
+        }
+    }
+
+    private void checkUdpTransportHandler() {
+        if (udpTransportHandler == null) {
+            udpTransportHandler = new UdpTransportHandler();
+            getDispatcher().register(udpTransportHandler);
+        }
+    }
+
+    private void dealKey(SelectionKey selectionKey) throws IOException {
+        if (selectionKey.isConnectable()) {
+            doTcpConnect(selectionKey);
+        } else if (selectionKey.isAcceptable()) {
+            doTcpAccept(selectionKey);
+        } else {
+            helpHandleSelectionKey(selectionKey);
+        }
+    }
+
+    private void helpHandleSelectionKey(SelectionKey selectionKey) throws IOException {
+        SelectableChannel channel = selectionKey.channel();
+        if (channel instanceof DatagramChannel) {
+            udpTransportHandler.helpHandleSelectionKey(selectionKey);
+        } else {
+            tcpTransportHandler.helpHandleSelectionKey(selectionKey);
+        }
+    }
+
+    private void doUdpConnect(InetSocketAddress sa) {
+        AddressEvent event = UdpAddressEvent.createAddressConnectEvent(sa);
+        dispatch(event);
+    }
+
+    private void doUdpConnect(AddressEvent event) throws IOException {
+        InetSocketAddress address = event.getAddress();
+        DatagramChannel channel = DatagramChannel.open();
+        channel.configureBlocking(false);
+        channel.connect(address);
+
+        channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
+
+        UdpTransport transport = new UdpTransport(channel, address);
+        onNewTransport(transport);
+    }
+
+    protected void doUdpListen(InetSocketAddress socketAddress) {
+        AddressEvent event = UdpAddressEvent.createAddressBindEvent(socketAddress);
+        dispatch(event);
+    }
+
+    private void doUdpBind(AddressEvent event) throws IOException {
+        DatagramChannel serverChannel = DatagramChannel.open();
+        serverChannel.configureBlocking(false);
+        serverChannel.bind(event.getAddress());
+        serverChannel.register(selector, SelectionKey.OP_READ);
+    }
+
+    protected void doTcpConnect(InetSocketAddress sa) {
+        AddressEvent event = TcpAddressEvent.createAddressConnectEvent(sa);
+        dispatch(event);
+    }
+
+    private void doTcpConnect(AddressEvent event) throws IOException {
+        SocketChannel channel = SocketChannel.open();
+        channel.configureBlocking(false);
+        channel.connect(event.getAddress());
+        channel.register(selector,
+                SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE);
+    }
+
+    private void doTcpConnect(SelectionKey key) throws IOException {
+        SocketChannel channel = (SocketChannel) key.channel();
+        if (channel.isConnectionPending()) {
+            channel.finishConnect();
+        }
+
+        Transport transport = new TcpTransport(channel, tcpTransportHandler.getStreamingDecoder());
+        channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE, transport);
+        onNewTransport(transport);
+    }
+
+    protected void doTcpListen(InetSocketAddress socketAddress) {
+        AddressEvent event = TcpAddressEvent.createAddressBindEvent(socketAddress);
+        dispatch(event);
+    }
+
+    protected void doTcpAccept(SelectionKey key) throws IOException {
+        ServerSocketChannel server = (ServerSocketChannel) key.channel();
+        SocketChannel channel;
+
+        try {
+            while ((channel = server.accept()) != null) {
+                channel.configureBlocking(false);
+                channel.socket().setTcpNoDelay(true);
+                channel.socket().setKeepAlive(true);
+
+                Transport transport = new TcpTransport(channel,
+                    tcpTransportHandler.getStreamingDecoder());
+
+                channel.register(selector,
+                    SelectionKey.OP_READ | SelectionKey.OP_WRITE, transport);
+                onNewTransport(transport);
+            }
+        } catch (ClosedByInterruptException e) {
+            // No op as normal
+        }
+    }
+
+    protected void doTcpBind(AddressEvent event) throws IOException {
+        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
+        serverSocketChannel.configureBlocking(false);
+        ServerSocket serverSocket = serverSocketChannel.socket();
+        serverSocket.bind(event.getAddress());
+        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT, serverSocketChannel);
+    }
+
+    private void onNewTransport(Transport transport) {
+        transport.setDispatcher(getDispatcher());
+        dispatch(TransportEvent.createNewTransportEvent(transport));
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/Transport.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/Transport.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/Transport.java
new file mode 100644
index 0000000..152e30a
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/Transport.java
@@ -0,0 +1,84 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport;
+
+import org.apache.kerby.event.Dispatcher;
+import org.apache.kerby.transport.buffer.TransBuffer;
+import org.apache.kerby.transport.event.TransportEvent;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+
+public abstract class Transport {
+    private InetSocketAddress remoteAddress;
+    protected Dispatcher dispatcher;
+    private Object attachment;
+
+    protected TransBuffer sendBuffer;
+
+    private int readableCount = 0;
+    private int writableCount = 0;
+
+    public Transport(InetSocketAddress remoteAddress) {
+        this.remoteAddress = remoteAddress;
+        this.sendBuffer = new TransBuffer();
+    }
+
+    public void setDispatcher(Dispatcher dispatcher) {
+        this.dispatcher = dispatcher;
+    }
+
+    public InetSocketAddress getRemoteAddress() {
+        return remoteAddress;
+    }
+
+    public void sendMessage(ByteBuffer message) {
+        if (message != null) {
+            sendBuffer.write(message);
+            dispatcher.dispatch(TransportEvent.createWritableTransportEvent(this));
+        }
+    }
+
+    public void onWriteable() throws IOException {
+        this.writableCount ++;
+
+        if (! sendBuffer.isEmpty()) {
+            ByteBuffer message = sendBuffer.read();
+            if (message != null) {
+                sendOutMessage(message);
+            }
+        }
+    }
+
+    public void onReadable() throws IOException {
+        this.readableCount++;
+    }
+
+    protected abstract void sendOutMessage(ByteBuffer message) throws IOException;
+
+    public void setAttachment(Object attachment) {
+        this.attachment = attachment;
+    }
+
+    public Object getAttachment() {
+        return attachment;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/TransportHandler.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/TransportHandler.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/TransportHandler.java
new file mode 100644
index 0000000..e745e38
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/TransportHandler.java
@@ -0,0 +1,34 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport;
+
+import org.apache.kerby.event.AbstractEventHandler;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+
+/**
+ * Handling readable and writable events
+ */
+public abstract class TransportHandler extends AbstractEventHandler {
+
+    public abstract void helpHandleSelectionKey(SelectionKey selectionKey) throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/TransportSelector.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/TransportSelector.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/TransportSelector.java
new file mode 100644
index 0000000..a4016a0
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/TransportSelector.java
@@ -0,0 +1,100 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport;
+
+import org.apache.kerby.event.Dispatcher;
+import org.apache.kerby.event.LongRunningEventHandler;
+import org.apache.kerby.transport.event.TransportEvent;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.util.Iterator;
+import java.util.Set;
+
+public abstract class TransportSelector extends LongRunningEventHandler {
+
+    protected Selector selector;
+    protected TransportHandler transportHandler;
+
+    public TransportSelector(TransportHandler transportHandler) {
+        super();
+        this.transportHandler = transportHandler;
+    }
+
+    @Override
+    public void setDispatcher(Dispatcher dispatcher) {
+        super.setDispatcher(dispatcher);
+        dispatcher.register(transportHandler);
+    }
+
+    @Override
+    public void init() {
+        super.init();
+
+        try {
+            selector = Selector.open();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    protected void loopOnce() {
+        try {
+            selectOnce();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected void selectOnce() throws IOException {
+        if (selector.isOpen() && selector.select(10) > 0 && selector.isOpen()) {
+            Set<SelectionKey> selectionKeys = selector.selectedKeys();
+            Iterator<SelectionKey> iterator = selectionKeys.iterator();
+            while (iterator.hasNext()) {
+                SelectionKey selectionKey = iterator.next();
+                dealKey(selectionKey);
+                iterator.remove();
+            }
+            selectionKeys.clear();
+        }
+    }
+
+    protected void dealKey(SelectionKey selectionKey) throws IOException {
+        transportHandler.helpHandleSelectionKey(selectionKey);
+    }
+
+    protected void onNewTransport(Transport transport) {
+        transport.setDispatcher(getDispatcher());
+        dispatch(TransportEvent.createNewTransportEvent(transport));
+    }
+
+    @Override
+    public void stop() {
+        super.stop();
+
+        try {
+            selector.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/BufferPool.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/BufferPool.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/BufferPool.java
new file mode 100644
index 0000000..7737c13
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/BufferPool.java
@@ -0,0 +1,33 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport.buffer;
+
+import java.nio.ByteBuffer;
+
+public class BufferPool {
+
+    public static ByteBuffer allocate(int len) {
+        return ByteBuffer.allocate(len);
+    }
+
+    public static void release(ByteBuffer buffer) {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/BufferUtil.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/BufferUtil.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/BufferUtil.java
new file mode 100644
index 0000000..f67ab09
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/BufferUtil.java
@@ -0,0 +1,42 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport.buffer;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+public class BufferUtil {
+
+    /**
+     * Read len bytes from src buffer
+     */
+    public static ByteBuffer read(ByteBuffer src, int len) {
+        if (len > src.remaining())
+            throw new BufferOverflowException();
+
+        ByteBuffer result = ByteBuffer.allocate(len);
+        int n = src.remaining();
+        for (int i = 0; i < n; i++) {
+            result.put(src.get());
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/7d9261af/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/RecvBuffer.java
----------------------------------------------------------------------
diff --git a/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/RecvBuffer.java b/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/RecvBuffer.java
new file mode 100644
index 0000000..2c190a3
--- /dev/null
+++ b/lib/kerby-event/src/main/java/org/apache/kerby/transport/buffer/RecvBuffer.java
@@ -0,0 +1,155 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.transport.buffer;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+public class RecvBuffer {
+
+    private LinkedList<ByteBuffer> bufferQueue;
+
+    public RecvBuffer() {
+        bufferQueue = new LinkedList<ByteBuffer>();
+    }
+
+    public synchronized void write(ByteBuffer buffer) {
+        bufferQueue.addLast(buffer);
+    }
+
+    /**
+     * Put buffer as the first into the buffer queue
+     */
+    public synchronized void writeFirst(ByteBuffer buffer) {
+        bufferQueue.addFirst(buffer);
+    }
+
+    /**
+     * Read and return the first buffer if available
+     */
+    public synchronized ByteBuffer readFirst() {
+        if (! bufferQueue.isEmpty()) {
+            return bufferQueue.removeFirst();
+        }
+        return null;
+    }
+
+    /**
+     * Read most available bytes into the dst buffer
+     */
+    public synchronized ByteBuffer readMostBytes() {
+        int len = remaining();
+        return readBytes(len);
+    }
+
+    /**
+     * Read len bytes into the dst buffer if available
+     */
+    public synchronized ByteBuffer readBytes(int len) {
+        if (remaining() < len) { // no enough data that's available
+            throw new BufferOverflowException();
+        }
+
+        ByteBuffer result = null;
+
+        ByteBuffer takenBuffer;
+        if (bufferQueue.size() == 1) {
+            takenBuffer = bufferQueue.removeFirst();
+
+            if (takenBuffer.remaining() == len) {
+                return takenBuffer;
+            }
+
+            result = BufferPool.allocate(len);
+            for (int i = 0; i < len; i++) {
+                result.put(takenBuffer.get());
+            }
+            // Has left bytes so put it back for future reading
+            if (takenBuffer.remaining() > 0) {
+                bufferQueue.addFirst(takenBuffer);
+            }
+        } else {
+            result = BufferPool.allocate(len);
+
+            Iterator<ByteBuffer> iter = bufferQueue.iterator();
+            int alreadyGot = 0, toGet;
+            while (iter.hasNext()) {
+                takenBuffer = iter.next();
+                iter.remove();
+
+                toGet = takenBuffer.remaining() < len - alreadyGot ?
+                    takenBuffer.remaining() : len -alreadyGot;
+                byte[] toGetBytes = new byte[toGet];
+                takenBuffer.get(toGetBytes);
+                result.put(toGetBytes);
+
+                if (takenBuffer.remaining() > 0) {
+                    bufferQueue.addFirst(takenBuffer);
+                }
+
+                alreadyGot += toGet;
+                if (alreadyGot == len) {
+                    break;
+                }
+            }
+        }
+        result.flip();
+
+        return result;
+    }
+
+    public boolean isEmpty() {
+        return bufferQueue.isEmpty();
+    }
+
+    /**
+     * Return count of remaining and left bytes that's available
+     */
+    public int remaining() {
+        if (bufferQueue.isEmpty()) {
+            return 0;
+        } else if (bufferQueue.size() == 1) {
+            return bufferQueue.getFirst().remaining();
+        }
+
+        int result = 0;
+        Iterator<ByteBuffer> iter = bufferQueue.iterator();
+        while (iter.hasNext()) {
+            result += iter.next().remaining();
+        }
+        return result;
+    }
+
+    public synchronized void clear() {
+        if (bufferQueue.isEmpty()) {
+            return;
+        } else if (bufferQueue.size() == 1) {
+            BufferPool.release(bufferQueue.getFirst());
+        }
+
+        Iterator<ByteBuffer> iter = bufferQueue.iterator();
+        while (iter.hasNext()) {
+            BufferPool.release(iter.next());
+        }
+        bufferQueue.clear();
+    }
+}