diff --git a/README.md b/README.md
index 1c01e59a..cbfb551c 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,20 @@
# ezyfox-server
EzyFox Server
-#Synopsis
+# Synopsis
-#Code Example
+# Code Example
-#Motivation
+# Motivation
-#API Reference
+# API Reference
-#Tests
+# Tests
mvn test
-#Contributors
+# Contributors
-#License
+# License
- Apache License, Version 2.0
diff --git a/build.sh b/build.sh
new file mode 100755
index 00000000..bfe70853
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,33 @@
+mvn clean install
+mvn clean install -f ezyfox-server-util
+mvn clean install -f ezyfox-server-io
+mvn clean install -f ezyfox-server-concurrent
+mvn clean install -f ezyfox-server-security
+mvn clean install -f ezyfox-server-common
+mvn clean install -f ezyfox-server-binding
+mvn clean install -f ezyfox-server-bean
+mvn clean install -f ezyfox-server-mapping
+mvn clean install -f ezyfox-server-codec
+mvn clean install -f ezyfox-server-core
+mvn clean install -f ezyfox-server-databridge
+mvn clean install -f ezyfox-server-webapi
+mvn clean install -f ezyfox-server-httpserver
+mvn clean install -f ezyfox-server-boot
+mvn clean install -f ezyfox-server-netty
+mvn clean install -f ezyfox-server-nio
+mvn clean install -f ezyfox-server-jackson
+mvn clean install -f ezyfox-server-msgpack
+mvn clean install -f ezyfox-server-sfs2x
+mvn clean install -f ezyfox-server-nettycodec
+mvn clean install -f ezyfox-server-niocodec
+mvn clean install -f ezyfox-server-database
+mvn clean install -f ezyfox-server-mongodb
+mvn clean install -f ezyfox-server-morphia
+mvn clean install -f ezyfox-server-hazelcast
+mvn clean install -f ezyfox-server-hazelcast-mongodb
+mvn clean install -f ezyfox-server-hazelcast-morphia
+mvn clean install -f ezyfox-server-hazelcast-bean
+mvn clean install -f ezyfox-server-monitor
+mvn clean install -f ezyfox-server-admintools
+mvn clean install -f ezyfox-server-nettyrunner
+mvn clean install -f ezyfox-server-niorunner
\ No newline at end of file
diff --git a/ezyfox-server-admintools/.tern-project b/ezyfox-server-admintools/.tern-project
new file mode 100644
index 00000000..f030bd16
--- /dev/null
+++ b/ezyfox-server-admintools/.tern-project
@@ -0,0 +1,17 @@
+{
+ "plugins": {
+ "guess-types": {
+
+ },
+ "outline": {
+
+ },
+ "angular": {
+
+ }
+ },
+ "libs": [
+ "ecma5",
+ "browser"
+ ]
+}
\ No newline at end of file
diff --git a/ezyfox-server-admintools/pom.xml b/ezyfox-server-admintools/pom.xml
new file mode 100644
index 00000000..26a1a16b
--- /dev/null
+++ b/ezyfox-server-admintools/pom.xml
@@ -0,0 +1,114 @@
+
+
+ 4.0.0
+
+ com.tvd12
+ ezyfox-server
+ 0.0.2
+
+ ezyfox-server-admintools
+ 1.0.0
+ war
+
+ ezyfox-server-admintools
+ http://maven.apache.org
+
+
+ 1.0.0
+ 1.0.0
+ 4.3.8.RELEASE
+ 2.5.10.1
+ 5.2.10.Final
+ 2.1.1
+ 6.0.6
+
+
+
+
+ com.tvd12
+ ezyfox-server-mongodb
+ ${ezy.mongodb.version}
+
+
+ com.tvd12
+ ezyfox-server-hazelcast
+ ${ezy.hazelcast.version}
+
+
+ org.springframework
+ spring-context
+ ${spring.version}
+
+
+ org.springframework
+ spring-context-support
+ ${spring.version}
+
+
+ org.springframework
+ spring-orm
+ ${spring.version}
+ jar
+ compile
+
+
+
+ org.apache.struts
+ struts2-core
+ ${struts.version}
+
+
+ org.apache.struts
+ struts2-spring-plugin
+ ${struts.version}
+
+
+
+ org.hibernate
+ hibernate-core
+ ${hibernate.version}
+
+
+
+ org.apache.commons
+ commons-dbcp2
+ ${commons.dbcp2.version}
+
+
+
+ mysql
+ mysql-connector-java
+ ${mysqlconnector.version}
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+ provided
+
+
+ javax.servlet.jsp.jstl
+ jstl-api
+ 1.2
+ provided
+
+
+
+
+ src/main/java
+
+
+ maven-war-plugin
+ 2.4
+
+ src/main/webapp
+ false
+
+
+
+
+
+
diff --git a/ezyfox-server-admintools/sql/create_product_table.sql b/ezyfox-server-admintools/sql/create_product_table.sql
new file mode 100644
index 00000000..72048fc0
--- /dev/null
+++ b/ezyfox-server-admintools/sql/create_product_table.sql
@@ -0,0 +1,9 @@
+USE `test`;
+
+CREATE TABLE `product` (
+ `product_id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` varchar(128) NOT NULL,
+ `description` varchar(512) NOT NULL,
+ `price` float NOT NULL,
+ PRIMARY KEY (`product_id`)
+)
\ No newline at end of file
diff --git a/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/action/HomeAction.java b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/action/HomeAction.java
new file mode 100644
index 00000000..cef74543
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/action/HomeAction.java
@@ -0,0 +1,26 @@
+package com.tvd12.ezyfoxserver.adt.action;
+
+import com.opensymphony.xwork2.ActionSupport;
+import com.tvd12.ezyfoxserver.hazelcast.service.EzyMaxIdService;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HomeAction extends ActionSupport {
+ private static final long serialVersionUID = -5885995144592628588L;
+
+ private String random = "random";
+
+ @Getter(AccessLevel.NONE)
+ private transient EzyMaxIdService maxIdService;
+
+ @Override
+ public String execute() throws Exception {
+ setRandom(String.valueOf(maxIdService.incrementAndGet("count")));
+ return SUCCESS;
+ }
+
+}
diff --git a/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/action/ListProductAction.java b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/action/ListProductAction.java
new file mode 100644
index 00000000..68c2052a
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/action/ListProductAction.java
@@ -0,0 +1,24 @@
+package com.tvd12.ezyfoxserver.adt.action;
+
+import java.util.List;
+
+import com.opensymphony.xwork2.ActionSupport;
+import com.tvd12.ezyfoxserver.adt.dao.ProductDAO;
+import com.tvd12.ezyfoxserver.adt.model.Product;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ListProductAction extends ActionSupport {
+ private static final long serialVersionUID = 8858337894805627088L;
+
+ private ProductDAO productDAO;
+ private List products;
+
+ public String execute() {
+ products = productDAO.list();
+ return SUCCESS;
+ }
+}
diff --git a/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/dao/ProductDAO.java b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/dao/ProductDAO.java
new file mode 100644
index 00000000..30af0a31
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/dao/ProductDAO.java
@@ -0,0 +1,15 @@
+package com.tvd12.ezyfoxserver.adt.dao;
+
+/**
+ * Copyright CodeJava.net To Present
+ * All rights reserved.
+ */
+import java.util.List;
+
+import com.tvd12.ezyfoxserver.adt.model.Product;
+
+public interface ProductDAO {
+
+ List list();
+
+}
diff --git a/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/dao/impl/ProductDAOImpl.java b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/dao/impl/ProductDAOImpl.java
new file mode 100644
index 00000000..64162d62
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/dao/impl/ProductDAOImpl.java
@@ -0,0 +1,47 @@
+package com.tvd12.ezyfoxserver.adt.dao.impl;
+
+/**
+ * Copyright CodeJava.net To Present
+ * All rights reserved.
+ */
+import java.util.List;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.transaction.Transactional;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+
+import com.tvd12.ezyfoxserver.adt.dao.ProductDAO;
+import com.tvd12.ezyfoxserver.adt.model.Product;
+
+public class ProductDAOImpl implements ProductDAO {
+
+ private SessionFactory sessionFactory;
+
+ public ProductDAOImpl(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+
+ @Transactional
+ @Override
+ public List list() {
+ CriteriaQuery query =
+ createQuery().distinct(true);
+ query.from(Product.class);
+ return getCurrentSession().createQuery(query).list();
+ }
+
+ private Session getCurrentSession() {
+ return sessionFactory.getCurrentSession();
+ }
+
+ private CriteriaBuilder getCriteriaBuilder() {
+ return getCurrentSession().getCriteriaBuilder();
+ }
+
+ private CriteriaQuery createQuery() {
+ return getCriteriaBuilder().createQuery(Product.class);
+ }
+}
diff --git a/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/model/Product.java b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/model/Product.java
new file mode 100644
index 00000000..2a089344
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/java/com/tvd12/ezyfoxserver/adt/model/Product.java
@@ -0,0 +1,17 @@
+package com.tvd12.ezyfoxserver.adt.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Copyright CodeJava.net To Present
+ * All rights reserved.
+ */
+@Getter
+@Setter
+public class Product {
+ private long id;
+ private String name;
+ private String description;
+ private float price;
+}
diff --git a/ezyfox-server-admintools/src/main/resources/hibernate.cfg.xml b/ezyfox-server-admintools/src/main/resources/hibernate.cfg.xml
new file mode 100644
index 00000000..9fd8cbc0
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/resources/hibernate.cfg.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ org.hibernate.dialect.MySQLDialect
+ true
+
+
+
\ No newline at end of file
diff --git a/ezyfox-server-admintools/src/main/resources/hibernate/mapping/product.hbm.xml b/ezyfox-server-admintools/src/main/resources/hibernate/mapping/product.hbm.xml
new file mode 100644
index 00000000..247cbd5c
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/resources/hibernate/mapping/product.hbm.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ezyfox-server-admintools/src/main/resources/struts.xml b/ezyfox-server-admintools/src/main/resources/struts.xml
new file mode 100644
index 00000000..37eb0333
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/resources/struts.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+ /WEB-INF/views/jsp/home.jsp
+
+
+
+ /WEB-INF/views/ftl/home.ftl
+
+
+
+ /WEB-INF/views/vm/home.vm
+
+
+
+ /WEB-INF/views/jsp/list_product.jsp
+
+
+
\ No newline at end of file
diff --git a/ezyfox-server-admintools/src/main/webapp/META-INF/MANIFEST.MF b/ezyfox-server-admintools/src/main/webapp/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..5e949512
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/webapp/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
diff --git a/ezyfox-server-admintools/src/main/webapp/WEB-INF/spring/app-context.xml b/ezyfox-server-admintools/src/main/webapp/WEB-INF/spring/app-context.xml
new file mode 100644
index 00000000..0f7a55c2
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/webapp/WEB-INF/spring/app-context.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ localhost
+ 27017
+ root
+ 123456
+ test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/ftl/home.ftl b/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/ftl/home.ftl
new file mode 100644
index 00000000..dc8908f2
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/ftl/home.ftl
@@ -0,0 +1,14 @@
+
+
+
+
+ Home
+
+
+
+
+
${random}
+
+
+
\ No newline at end of file
diff --git a/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/jsp/home.jsp b/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/jsp/home.jsp
new file mode 100644
index 00000000..5a6f396f
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/jsp/home.jsp
@@ -0,0 +1,16 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8"
+ pageEncoding="UTF-8"%>
+<%@ taglib prefix="s" uri="/struts-tags" %>
+
+
+
+
+Home
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/jsp/list_product.jsp b/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/jsp/list_product.jsp
new file mode 100644
index 00000000..a7c284d5
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/jsp/list_product.jsp
@@ -0,0 +1,31 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8"
+ pageEncoding="UTF-8"%>
+<%@ taglib prefix="s" uri="/struts-tags" %>
+
+
+
+
+Product List
+
+
+
+
+
+ No |
+ Product Name |
+ Description |
+ Price |
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/vm/home.vm b/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/vm/home.vm
new file mode 100644
index 00000000..99d40d75
--- /dev/null
+++ b/ezyfox-server-admintools/src/main/webapp/WEB-INF/views/vm/home.vm
@@ -0,0 +1,6 @@
+
+Home
+
+ ${random}
+
+
+
+
+ ezyfox server admintools
+
+
+ contextConfigLocation
+ /WEB-INF/spring/app-context.xml
+
+
+
+ org.springframework.web.context.ContextLoaderListener
+
+
+
+ DispatcherFilter
+ org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter
+
+
+
+ DispatcherFilter
+ /*
+
+
\ No newline at end of file
diff --git a/ezyfox-server-admintools/src/test/resources/AllTests.tng.xml b/ezyfox-server-admintools/src/test/resources/AllTests.tng.xml
new file mode 100644
index 00000000..3f571ed5
--- /dev/null
+++ b/ezyfox-server-admintools/src/test/resources/AllTests.tng.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ezyfox-server-bean/assembly.xml b/ezyfox-server-bean/assembly.xml
new file mode 100644
index 00000000..9ccc91ef
--- /dev/null
+++ b/ezyfox-server-bean/assembly.xml
@@ -0,0 +1,16 @@
+
+
+ bin
+ false
+
+ zip
+
+
+
+
+ true
+ lib
+
+
+
+
\ No newline at end of file
diff --git a/ezyfox-server-bean/pom.xml b/ezyfox-server-bean/pom.xml
new file mode 100644
index 00000000..34107c42
--- /dev/null
+++ b/ezyfox-server-bean/pom.xml
@@ -0,0 +1,24 @@
+
+ 4.0.0
+
+ com.tvd12
+ ezyfox-server
+ 0.0.2
+
+ ezyfox-server-bean
+ 1.0.0
+ ezyfox-server-bean
+
+
+ 1.0.0
+
+
+
+
+ com.tvd12
+ ezyfox-server-common
+ ${ezy.common.version}
+
+
+
\ No newline at end of file
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanConfig.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanConfig.java
new file mode 100644
index 00000000..6c6ba45e
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanConfig.java
@@ -0,0 +1,7 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzyBeanConfig {
+
+ void config();
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanContext.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanContext.java
new file mode 100644
index 00000000..cea2480e
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanContext.java
@@ -0,0 +1,22 @@
+package com.tvd12.ezyfoxserver.bean;
+
+import java.util.Properties;
+
+import com.tvd12.ezyfoxserver.bean.impl.EzySimpleBeanContext;
+
+public interface EzyBeanContext extends
+ EzyBeanFetcher,
+ EzySingletonFetcher,
+ EzyPrototypeFetcher,
+ EzyPropertyFetcher {
+
+ Properties getProperties();
+ EzySingletonFactory getSingletonFactory();
+ EzyPrototypeFactory getPrototypeFactory();
+ EzyBeanNameTranslator getBeanNameTranslator();
+
+ static EzyBeanContextBuilder builder() {
+ return EzySimpleBeanContext.builder();
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanContextAware.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanContextAware.java
new file mode 100644
index 00000000..45d967cb
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanContextAware.java
@@ -0,0 +1,7 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzyBeanContextAware {
+
+ void setContext(EzyBeanContext context);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanContextBuilder.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanContextBuilder.java
new file mode 100644
index 00000000..0c4e8ae7
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanContextBuilder.java
@@ -0,0 +1,41 @@
+package com.tvd12.ezyfoxserver.bean;
+
+import java.util.Map;
+
+import com.tvd12.ezyfoxserver.builder.EzyBuilder;
+import com.tvd12.ezyfoxserver.properties.EzyPropertiesReader;
+
+@SuppressWarnings("rawtypes")
+public interface EzyBeanContextBuilder extends EzyBuilder {
+
+ EzyBeanContextBuilder scan(String packageName);
+
+ EzyBeanContextBuilder scan(String... packageNames);
+
+ EzyBeanContextBuilder scan(Iterable packageNames);
+
+ EzyBeanContextBuilder addSingleton(String name, Object singleton);
+
+ EzyBeanContextBuilder addSingletonClass(Class clazz);
+
+ EzyBeanContextBuilder addSingletonClasses(Class... classes);
+
+ EzyBeanContextBuilder addSingletonClasses(Iterable classes);
+
+ EzyBeanContextBuilder addPrototypeClass(Class clazz);
+
+ EzyBeanContextBuilder addPrototypeClasses(Class... classes);
+
+ EzyBeanContextBuilder addPrototypeClasses(Iterable classes);
+
+ EzyBeanContextBuilder addPrototypeSupplier(String objectName, EzyPrototypeSupplier supplier);
+
+ EzyBeanContextBuilder errorHandler(EzyErrorHandler handler);
+
+ EzyBeanContextBuilder addProperties(Map properties);
+
+ EzyBeanContextBuilder addProperty(String key, Object value);
+
+ EzyBeanContextBuilder propertiesReader(EzyPropertiesReader propertiesReader);
+
+}
\ No newline at end of file
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanFetcher.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanFetcher.java
new file mode 100644
index 00000000..b12cdfda
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanFetcher.java
@@ -0,0 +1,9 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzyBeanFetcher {
+
+ Object getBean(Class> type);
+
+ Object getBean(String name, Class> type);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanNameTranslator.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanNameTranslator.java
new file mode 100644
index 00000000..fb707f8e
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanNameTranslator.java
@@ -0,0 +1,9 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzyBeanNameTranslator {
+
+ String translate(String name, Class> type);
+
+ void map(String freename, Class> type, String realname);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanNameTranslatorAware.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanNameTranslatorAware.java
new file mode 100644
index 00000000..d0a9926e
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyBeanNameTranslatorAware.java
@@ -0,0 +1,7 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzyBeanNameTranslatorAware {
+
+ void setBeanNameTranslator(EzyBeanNameTranslator translator);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyErrorHandler.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyErrorHandler.java
new file mode 100644
index 00000000..eecf4037
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyErrorHandler.java
@@ -0,0 +1,7 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzyErrorHandler {
+
+ void handle(Throwable error);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPropertyFetcher.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPropertyFetcher.java
new file mode 100644
index 00000000..e2120ee3
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPropertyFetcher.java
@@ -0,0 +1,9 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzyPropertyFetcher {
+
+ boolean containsProperty(Object key);
+
+ T getProperty(Object key, Class outType);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeFactory.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeFactory.java
new file mode 100644
index 00000000..2fbaa48f
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeFactory.java
@@ -0,0 +1,25 @@
+package com.tvd12.ezyfoxserver.bean;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("rawtypes")
+public interface EzyPrototypeFactory {
+
+ EzyPrototypeSupplier getSupplier(String objectName, Class objectType);
+
+ EzyPrototypeSupplier getSupplier(Map properties);
+
+ List getSuppliers(Map properties);
+
+ List getSuppliers(Class annoClass);
+
+ Map getProperties(EzyPrototypeSupplier supplier);
+
+ void addSupplier(EzyPrototypeSupplier supplier);
+
+ void addSupplier(String objectName, EzyPrototypeSupplier supplier);
+
+ void addSupplier(String objectName, EzyPrototypeSupplier supplier, Map properties);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeFactoryAware.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeFactoryAware.java
new file mode 100644
index 00000000..51125e8f
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeFactoryAware.java
@@ -0,0 +1,7 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzyPrototypeFactoryAware {
+
+ void setPrototypeFactory(EzyPrototypeFactory factory);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeFetcher.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeFetcher.java
new file mode 100644
index 00000000..fffe00f2
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeFetcher.java
@@ -0,0 +1,19 @@
+package com.tvd12.ezyfoxserver.bean;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("rawtypes")
+public interface EzyPrototypeFetcher {
+
+ T getPrototype(String name, Class type);
+
+ T getPrototype(Map properties);
+
+ List getPrototypes(Map properties);
+
+ EzyPrototypeSupplier getPrototypeSupplier(Map properties);
+
+ List getPrototypeSuppliers(Map properties);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeSupplier.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeSupplier.java
new file mode 100644
index 00000000..bf5156c7
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzyPrototypeSupplier.java
@@ -0,0 +1,9 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzyPrototypeSupplier {
+
+ Class> getObjectType();
+
+ Object supply(EzyBeanContext context);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzySingletonFactory.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzySingletonFactory.java
new file mode 100644
index 00000000..7e1a3963
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzySingletonFactory.java
@@ -0,0 +1,25 @@
+package com.tvd12.ezyfoxserver.bean;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("rawtypes")
+public interface EzySingletonFactory {
+
+ Object getSingleton(String name, Class type);
+
+ Object getSingleton(Map properties);
+
+ List getSingletons(Map properties);
+
+ List getSingletons(Class annoClass);
+
+ Map getProperties(Object singleton);
+
+ Object addSingleton(Object singleton);
+
+ Object addSingleton(String name, Object singleton);
+
+ Object addSingleton(String name, Object singleton, Map properties);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzySingletonFactoryAware.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzySingletonFactoryAware.java
new file mode 100644
index 00000000..3dee927f
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzySingletonFactoryAware.java
@@ -0,0 +1,7 @@
+package com.tvd12.ezyfoxserver.bean;
+
+public interface EzySingletonFactoryAware {
+
+ void setSingletonFactory(EzySingletonFactory factory);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzySingletonFetcher.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzySingletonFetcher.java
new file mode 100644
index 00000000..f5211ba9
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/EzySingletonFetcher.java
@@ -0,0 +1,15 @@
+package com.tvd12.ezyfoxserver.bean;
+
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings("rawtypes")
+public interface EzySingletonFetcher {
+
+ T getSingleton(String name, Class type);
+
+ T getSingleton(Map properties);
+
+ List getSingletons(Map properties);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyAutoBind.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyAutoBind.java
new file mode 100644
index 00000000..1fdb561c
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyAutoBind.java
@@ -0,0 +1,20 @@
+package com.tvd12.ezyfoxserver.bean.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({
+ ElementType.FIELD,
+ ElementType.METHOD,
+ ElementType.CONSTRUCTOR
+})
+public @interface EzyAutoBind {
+
+ String[] value() default {};
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyConfiguration.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyConfiguration.java
new file mode 100644
index 00000000..96d80384
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyConfiguration.java
@@ -0,0 +1,19 @@
+package com.tvd12.ezyfoxserver.bean.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tavandung12
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE })
+public @interface EzyConfiguration {
+
+ int priority() default 0;
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyConfigurationBefore.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyConfigurationBefore.java
new file mode 100644
index 00000000..16e1daf5
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyConfigurationBefore.java
@@ -0,0 +1,19 @@
+package com.tvd12.ezyfoxserver.bean.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @author tavandung12
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE })
+public @interface EzyConfigurationBefore {
+
+ int priority() default 0;
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyPackagesScan.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyPackagesScan.java
new file mode 100644
index 00000000..a21381cc
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyPackagesScan.java
@@ -0,0 +1,25 @@
+package com.tvd12.ezyfoxserver.bean.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a class configure which packages bean context need to load
+ *
+ * @author tavandung12
+ *
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE })
+public @interface EzyPackagesScan {
+
+ /**
+ * packages to load
+ *
+ * @return array of package names
+ */
+ public String[] value();
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyPostInit.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyPostInit.java
new file mode 100644
index 00000000..99e6b087
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyPostInit.java
@@ -0,0 +1,18 @@
+package com.tvd12.ezyfoxserver.bean.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({
+ ElementType.METHOD
+})
+public @interface EzyPostInit {
+
+ String[] value() default "";
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyPrototype.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyPrototype.java
new file mode 100644
index 00000000..8ac9954a
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzyPrototype.java
@@ -0,0 +1,23 @@
+package com.tvd12.ezyfoxserver.bean.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.tvd12.ezyfoxserver.annotation.EzyKeyValue;
+
+/**
+ *
+ * @author tavandung12
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
+public @interface EzyPrototype {
+
+ String value() default "";
+
+ EzyKeyValue[] properties() default {};
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzySingleton.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzySingleton.java
new file mode 100644
index 00000000..addda015
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/annotation/EzySingleton.java
@@ -0,0 +1,23 @@
+package com.tvd12.ezyfoxserver.bean.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.tvd12.ezyfoxserver.annotation.EzyKeyValue;
+
+/**
+ *
+ * @author tavandung12
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
+public @interface EzySingleton {
+
+ String value() default "";
+
+ EzyKeyValue[] properties() default {};
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/exception/EzyNewSingletonException.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/exception/EzyNewSingletonException.java
new file mode 100644
index 00000000..30dceebd
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/exception/EzyNewSingletonException.java
@@ -0,0 +1,31 @@
+package com.tvd12.ezyfoxserver.bean.exception;
+
+import com.tvd12.ezyfoxserver.bean.impl.EzyBeanKey;
+
+import lombok.Getter;
+
+@Getter
+public class EzyNewSingletonException extends IllegalStateException {
+ private static final long serialVersionUID = -1494071992523176740L;
+
+ private final String errorBeanName;
+ private final Class> errorClass;
+ private final Class> singletonClass;
+
+ public EzyNewSingletonException(
+ Class> singletonClass, Class> errorClass, String errorBeanName) {
+ super(
+ "can't load singleton of class " +
+ singletonClass.getSimpleName() +
+ ", can't set (" + errorBeanName + ", " + errorClass.getSimpleName() + ")"
+ );
+ this.errorClass = errorClass;
+ this.singletonClass = singletonClass;
+ this.errorBeanName = errorBeanName;
+ }
+
+ public final EzyBeanKey getErrorKey() {
+ return EzyBeanKey.of(getErrorBeanName(), getErrorClass());
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/exception/EzySingletonException.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/exception/EzySingletonException.java
new file mode 100644
index 00000000..2ad7c2f7
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/exception/EzySingletonException.java
@@ -0,0 +1,23 @@
+package com.tvd12.ezyfoxserver.bean.exception;
+
+import java.util.Set;
+
+import com.tvd12.ezyfoxserver.bean.impl.EzyBeanKey;
+
+public class EzySingletonException extends IllegalStateException {
+ private static final long serialVersionUID = 814337130118800149L;
+
+ public EzySingletonException(String msg) {
+ super(msg);
+ }
+
+ public static EzySingletonException
+ implementationNotFound(EzyBeanKey key, Set> uncompleted) {
+ StringBuilder message = new StringBuilder("bean ")
+ .append(key)
+ .append(" implementation not found, uncompleted classes: ")
+ .append(uncompleted);
+ return new EzySingletonException(message.toString());
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyBeanKey.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyBeanKey.java
new file mode 100644
index 00000000..e7ce9dc6
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyBeanKey.java
@@ -0,0 +1,46 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.io.Serializable;
+
+import com.tvd12.ezyfoxserver.util.EzyEquals;
+import com.tvd12.ezyfoxserver.util.EzyHashCodes;
+
+import lombok.Getter;
+
+@Getter
+public class EzyBeanKey implements Serializable {
+ private static final long serialVersionUID = -2376464316946102262L;
+
+ protected String name;
+ protected Class> type;
+
+ public EzyBeanKey(String name, Class> type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public static EzyBeanKey of(String name, Class> type) {
+ return new EzyBeanKey(name, type);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return new EzyEquals()
+ .function(o -> o.name)
+ .function(o -> o.type)
+ .isEquals(this, obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return new EzyHashCodes()
+ .append(name, type)
+ .toHashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "(" + name + "," + type.getSimpleName() + ")";
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyBeanNameParser.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyBeanNameParser.java
new file mode 100644
index 00000000..a8abcd81
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyBeanNameParser.java
@@ -0,0 +1,74 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.tvd12.ezyfoxserver.bean.annotation.EzyPrototype;
+import com.tvd12.ezyfoxserver.bean.annotation.EzySingleton;
+import com.tvd12.ezyfoxserver.reflect.EzyClasses;
+import com.tvd12.ezyfoxserver.reflect.EzyField;
+import com.tvd12.ezyfoxserver.reflect.EzyMethod;
+
+public final class EzyBeanNameParser {
+
+ private EzyBeanNameParser() {
+ }
+
+ public static String getBeanName(Class> clazz) {
+ if(clazz.isAnnotationPresent(EzySingleton.class))
+ return getSingletonName(clazz);
+ if(clazz.isAnnotationPresent(EzyPrototype.class))
+ return getPrototypeName(clazz);
+ return EzyClasses.getVariableName(clazz);
+ }
+
+ // ============== parse singleton ==================
+ public static String getSingletonName(EzyField field) {
+ return getSingletonName(field.getAnnotation(EzySingleton.class), field.getName());
+ }
+
+ public static String getSingletonName(EzyMethod method) {
+ return getSingletonName(method.getAnnotation(EzySingleton.class), method.getFieldName());
+ }
+
+ public static String getSingletonName(Class> clazz) {
+ return getSingletonName(clazz, clazz.getAnnotation(EzySingleton.class));
+ }
+
+ public static String getSingletonName(Class> clazz, EzySingleton annotation) {
+ return getSingletonName(annotation, EzyClasses.getVariableName(clazz, "Impl"));
+ }
+
+ public static String getSingletonName(EzySingleton annotation, String defaultName) {
+ if(annotation == null)
+ return defaultName;
+ if(StringUtils.isEmpty(annotation.value()))
+ return defaultName;
+ return annotation.value();
+ }
+
+ // ============ parse prototype ==========
+ public static String getPrototypeName(EzyField field) {
+ return getPrototypeName(field.getAnnotation(EzyPrototype.class), field.getName());
+ }
+
+ public static String getPrototypeName(EzyMethod method) {
+ return getPrototypeName(method.getAnnotation(EzyPrototype.class), method.getFieldName());
+ }
+
+ public static String getPrototypeName(Class> clazz) {
+ return getPrototypeName(clazz, clazz.getAnnotation(EzyPrototype.class));
+ }
+
+ public static String getPrototypeName(Class> clazz, EzyPrototype annotation) {
+ return getPrototypeName(annotation, EzyClasses.getVariableName(clazz, "Impl"));
+ }
+
+ public static String getPrototypeName(EzyPrototype annotation, String defaultName) {
+ if(annotation == null)
+ return defaultName;
+ if(StringUtils.isEmpty(annotation.value()))
+ return defaultName;
+ return annotation.value();
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByConstructorPrototypeSupplierLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByConstructorPrototypeSupplierLoader.java
new file mode 100644
index 00000000..10c7d2a7
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByConstructorPrototypeSupplierLoader.java
@@ -0,0 +1,28 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.lang.reflect.Constructor;
+
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+
+public class EzyByConstructorPrototypeSupplierLoader
+ extends EzySimplePrototypeSupplierLoader
+ implements EzyPrototypeSupplierLoader {
+
+ protected final Constructor> constructor;
+
+ public EzyByConstructorPrototypeSupplierLoader(EzyClass clazz) {
+ super(clazz);
+ this.constructor = getConstructor(clazz);
+ }
+
+ @Override
+ protected String[] getConstructorArgumentNames() {
+ return getConstructorArgumentNames(constructor);
+ }
+
+ @Override
+ protected Class>[] getConstructorParameterTypes() {
+ return constructor.getParameterTypes();
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByConstructorSingletonLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByConstructorSingletonLoader.java
new file mode 100644
index 00000000..c5890537
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByConstructorSingletonLoader.java
@@ -0,0 +1,38 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.lang.reflect.Constructor;
+
+import com.tvd12.ezyfoxserver.bean.EzyBeanContext;
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+
+@SuppressWarnings("rawtypes")
+public class EzyByConstructorSingletonLoader
+ extends EzySimpleSingletonLoader
+ implements EzySingletonLoader {
+
+ protected final Constructor> constructor;
+
+ protected EzyByConstructorSingletonLoader(EzyClass clazz) {
+ super(clazz);
+ this.constructor = getConstructor(clazz);
+ }
+
+ @Override
+ protected String[] getConstructorArgumentNames() {
+ return getConstructorArgumentNames(constructor);
+ }
+
+ @Override
+ protected Class>[] getConstructorParameterTypes() {
+ return constructor.getParameterTypes();
+ }
+
+ @Override
+ protected Object newSingletonByConstructor(
+ EzyBeanContext context, Class[] parameterTypes) throws Exception {
+ if(parameterTypes.length == 0)
+ return clazz.newInstance();
+ return constructor.newInstance(getArguments(parameterTypes, context));
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByFieldPrototypeSupplierLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByFieldPrototypeSupplierLoader.java
new file mode 100644
index 00000000..fd36e785
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByFieldPrototypeSupplierLoader.java
@@ -0,0 +1,63 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.List;
+import java.util.Map;
+
+import com.tvd12.ezyfoxserver.asm.EzyFunction.EzyBody;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyPrototype;
+import com.tvd12.ezyfoxserver.asm.EzyInstruction;
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+import com.tvd12.ezyfoxserver.reflect.EzyClasses;
+import com.tvd12.ezyfoxserver.reflect.EzyField;
+
+public class EzyByFieldPrototypeSupplierLoader
+ extends EzySimplePrototypeSupplierLoader
+ implements EzyPrototypeSupplierLoader {
+
+ protected final EzyField field;
+ protected final Object configurator;
+
+ public EzyByFieldPrototypeSupplierLoader(EzyField field, Object configurator) {
+ super(new EzyClass(field.getType()));
+ this.field = field;
+ this.configurator = configurator;
+ }
+
+ @Override
+ protected String getPrototypeName() {
+ return EzyBeanNameParser.getPrototypeName(
+ field.getAnnotation(EzyPrototype.class), field.getName());
+ }
+
+ @Override
+ protected Class>[] getConstructorParameterTypes() {
+ return new Class[0];
+ }
+
+ @Override
+ protected String[] getConstructorArgumentNames() {
+ return new String[0];
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected Map getAnnotationProperties() {
+ return EzyKeyValueParser.getPrototypeProperties(
+ field.getAnnotation(EzyPrototype.class));
+ }
+
+ @Override
+ protected EzyInstruction newConstructInstruction(EzyBody body, List cparams) {
+ Class> configClass = configurator.getClass();
+ EzyInstruction prepare = newVariableInstruction(
+ configClass, "configurator", EzyClasses.getVariableName(configClass));
+ body.append(prepare);
+ EzyInstruction instruction = new EzyInstruction("\t", "\n")
+ .variable(clazz.getClazz(), "object")
+ .equal()
+ .append("configurator.")
+ .append(field.getName());
+ return instruction;
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByFieldSingletonLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByFieldSingletonLoader.java
new file mode 100644
index 00000000..6526a0e1
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByFieldSingletonLoader.java
@@ -0,0 +1,61 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.Map;
+
+import com.tvd12.ezyfoxserver.bean.EzyBeanContext;
+import com.tvd12.ezyfoxserver.bean.annotation.EzySingleton;
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+import com.tvd12.ezyfoxserver.reflect.EzyField;
+import com.tvd12.ezyfoxserver.reflect.EzyMethod;
+
+@SuppressWarnings("rawtypes")
+public class EzyByFieldSingletonLoader
+ extends EzySimpleSingletonLoader
+ implements EzySingletonLoader {
+
+ protected final EzyField field;
+
+ public EzyByFieldSingletonLoader(
+ EzyField field, Object configurator, Map, EzyMethod> methodsByType) {
+ super(new EzyClass(field.getType()), configurator, methodsByType);
+ this.field = field;
+ }
+
+ @Override
+ protected Map getAnnotationProperties() {
+ return EzyKeyValueParser.getSingletonProperties(
+ field.getAnnotation(EzySingleton.class));
+ }
+
+ @Override
+ protected String getSingletonName() {
+ return EzyBeanNameParser.getSingletonName(
+ field.getAnnotation(EzySingleton.class), field.getName());
+ }
+
+ @Override
+ protected Class>[] getConstructorParameterTypes() {
+ return new Class[0];
+ }
+
+ @Override
+ protected Object newSingletonByConstructor(
+ EzyBeanContext context, Class[] parameterTypes) throws Exception {
+ return field.get(configurator);
+ }
+
+ @Override
+ protected String[] getConstructorArgumentNames() {
+ return new String[0];
+ }
+
+ @Override
+ protected Class[] getConstructorParameterTypes(Class clazz) {
+ return new Class[0];
+ }
+
+ @Override
+ protected void detectCircularDependency(Class[] parameterTypes, StringBuilder log) {
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByMethodPrototypeSupplierLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByMethodPrototypeSupplierLoader.java
new file mode 100644
index 00000000..00bb3e4e
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByMethodPrototypeSupplierLoader.java
@@ -0,0 +1,63 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.tvd12.ezyfoxserver.asm.EzyFunction.EzyBody;
+import com.tvd12.ezyfoxserver.asm.EzyInstruction;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyPrototype;
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+import com.tvd12.ezyfoxserver.reflect.EzyClasses;
+import com.tvd12.ezyfoxserver.reflect.EzyMethod;
+
+public class EzyByMethodPrototypeSupplierLoader
+ extends EzySimplePrototypeSupplierLoader
+ implements EzyPrototypeSupplierLoader {
+
+ protected final EzyMethod method;
+ protected final Object configurator;
+
+ public EzyByMethodPrototypeSupplierLoader(EzyMethod method, Object configurator) {
+ super(new EzyClass(method.getReturnType()));
+ this.method = method;
+ this.configurator = configurator;
+ }
+
+ @Override
+ protected String getPrototypeName() {
+ return EzyBeanNameParser.getPrototypeName(
+ method.getAnnotation(EzyPrototype.class), method.getFieldName());
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected Map getAnnotationProperties() {
+ return EzyKeyValueParser.getPrototypeProperties(
+ method.getAnnotation(EzyPrototype.class));
+ }
+
+ @Override
+ protected Class>[] getConstructorParameterTypes() {
+ return method.getParameterTypes();
+ }
+
+ @Override
+ protected EzyInstruction newConstructInstruction(EzyBody body, List cparams) {
+ Class> configClass = configurator.getClass();
+ EzyInstruction prepare = newVariableInstruction(
+ configClass, "configurator", EzyClasses.getVariableName(configClass));
+ body.append(prepare);
+ EzyInstruction instruction = new EzyInstruction("\t", "\n")
+ .variable(clazz.getClazz(), "object")
+ .equal()
+ .append("configurator.")
+ .append(method.getName())
+ .bracketopen()
+ .append(StringUtils.join(cparams, ", "))
+ .bracketclose();
+ return instruction;
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByMethodSingletonLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByMethodSingletonLoader.java
new file mode 100644
index 00000000..345de22b
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyByMethodSingletonLoader.java
@@ -0,0 +1,56 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.Map;
+
+import com.tvd12.ezyfoxserver.bean.EzyBeanContext;
+import com.tvd12.ezyfoxserver.bean.annotation.EzySingleton;
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+import com.tvd12.ezyfoxserver.reflect.EzyMethod;
+
+@SuppressWarnings("rawtypes")
+public class EzyByMethodSingletonLoader
+ extends EzySimpleSingletonLoader
+ implements EzySingletonLoader {
+
+ protected final EzyMethod method;
+
+ public EzyByMethodSingletonLoader(
+ EzyMethod method,
+ Object configurator,
+ Map, EzyMethod> methodsByType) {
+ super(new EzyClass(method.getReturnType()), configurator, methodsByType);
+ this.method = method;
+ }
+
+ @Override
+ protected Map getAnnotationProperties() {
+ return EzyKeyValueParser.getSingletonProperties(
+ method.getAnnotation(EzySingleton.class));
+ }
+
+ @Override
+ protected String getSingletonName() {
+ return EzyBeanNameParser.getSingletonName(
+ method.getAnnotation(EzySingleton.class), method.getFieldName());
+ }
+
+ @Override
+ protected Class>[] getConstructorParameterTypes() {
+ return method.getParameterTypes();
+ }
+
+ @Override
+ protected Object newSingletonByConstructor(
+ EzyBeanContext context, Class[] parameterTypes) throws Exception {
+ if(parameterTypes.length == 0)
+ return method.invoke(configurator);
+ return method.invoke(configurator, getArguments(parameterTypes, context));
+ }
+
+ @Override
+ protected Class[] getConstructorParameterTypes(Class clazz) {
+ EzyMethod method = methodsByType.get(clazz);
+ return method != null ? method.getParameterTypes() : new Class[0];
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyConfigurationBeforeClassSorter.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyConfigurationBeforeClassSorter.java
new file mode 100644
index 00000000..fc33aa7d
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyConfigurationBeforeClassSorter.java
@@ -0,0 +1,33 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+
+import com.tvd12.ezyfoxserver.bean.annotation.EzyConfigurationBefore;
+
+@SuppressWarnings("rawtypes")
+public class EzyConfigurationBeforeClassSorter {
+
+ private EzyConfigurationBeforeClassSorter() {
+ }
+
+ public static List sort(Collection classes) {
+ List list = new ArrayList<>(classes);
+ list.sort(newComparator());
+ return list;
+ }
+
+ private static Comparator newComparator() {
+ return (c1, c2) -> getPriority(c1) - getPriority(c2);
+ }
+
+ private static int getPriority(Class> clazz) {
+ return getPriority(clazz.getAnnotation(EzyConfigurationBefore.class));
+ }
+
+ private static int getPriority(EzyConfigurationBefore annotation) {
+ return annotation.priority();
+ }
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyConfigurationClassSorter.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyConfigurationClassSorter.java
new file mode 100644
index 00000000..b1e1ffdb
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyConfigurationClassSorter.java
@@ -0,0 +1,33 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+
+import com.tvd12.ezyfoxserver.bean.annotation.EzyConfiguration;
+
+@SuppressWarnings("rawtypes")
+public class EzyConfigurationClassSorter {
+
+ private EzyConfigurationClassSorter() {
+ }
+
+ public static List sort(Collection classes) {
+ List list = new ArrayList<>(classes);
+ list.sort(newComparator());
+ return list;
+ }
+
+ private static Comparator newComparator() {
+ return (c1, c2) -> getPriority(c1) - getPriority(c2);
+ }
+
+ private static int getPriority(Class> clazz) {
+ return getPriority(clazz.getAnnotation(EzyConfiguration.class));
+ }
+
+ private static int getPriority(EzyConfiguration annotation) {
+ return annotation.priority();
+ }
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyConfigurationLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyConfigurationLoader.java
new file mode 100644
index 00000000..fb2ad807
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyConfigurationLoader.java
@@ -0,0 +1,12 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import com.tvd12.ezyfoxserver.bean.EzyBeanContext;
+
+public interface EzyConfigurationLoader {
+
+ EzyConfigurationLoader clazz(Class> clazz);
+
+ EzyConfigurationLoader context(EzyBeanContext context);
+
+ void load();
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyKeyValueParser.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyKeyValueParser.java
new file mode 100644
index 00000000..db0c48ca
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyKeyValueParser.java
@@ -0,0 +1,34 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.Map;
+
+import com.tvd12.ezyfoxserver.annotation.EzyKeyValue;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyPrototype;
+import com.tvd12.ezyfoxserver.bean.annotation.EzySingleton;
+import com.tvd12.ezyfoxserver.util.EzyKeyValueAnnotations;
+
+@SuppressWarnings({ "rawtypes" })
+public final class EzyKeyValueParser {
+
+ private EzyKeyValueParser() {
+ }
+
+ public static Map getSingletonProperties(Class> clazz) {
+ return getSingletonProperties(clazz.getAnnotation(EzySingleton.class));
+ }
+
+ public static Map getSingletonProperties(EzySingleton annotation) {
+ EzyKeyValue[] keyValues = annotation != null ? annotation.properties() : new EzyKeyValue[0];
+ return EzyKeyValueAnnotations.getProperties(keyValues);
+ }
+
+ public static Map getPrototypeProperties(Class> clazz) {
+ return getPrototypeProperties(clazz.getAnnotation(EzyPrototype.class));
+ }
+
+ public static Map getPrototypeProperties(EzyPrototype annotation) {
+ EzyKeyValue[] keyValues = annotation != null ? annotation.properties() : new EzyKeyValue[0];
+ return EzyKeyValueAnnotations.getProperties(keyValues);
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyPrototypeSupplierLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyPrototypeSupplierLoader.java
new file mode 100644
index 00000000..26783e97
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzyPrototypeSupplierLoader.java
@@ -0,0 +1,10 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeFactory;
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeSupplier;
+
+public interface EzyPrototypeSupplierLoader {
+
+ EzyPrototypeSupplier load(EzyPrototypeFactory factory);
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleBeanContext.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleBeanContext.java
new file mode 100644
index 00000000..8af776b1
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleBeanContext.java
@@ -0,0 +1,484 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import static com.tvd12.ezyfoxserver.bean.impl.EzyBeanNameParser.getPrototypeName;
+import static com.tvd12.ezyfoxserver.bean.impl.EzyBeanNameParser.getSingletonName;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+import com.tvd12.ezyfoxserver.bean.EzyBeanContext;
+import com.tvd12.ezyfoxserver.bean.EzyBeanContextBuilder;
+import com.tvd12.ezyfoxserver.bean.EzyBeanNameTranslator;
+import com.tvd12.ezyfoxserver.bean.EzyErrorHandler;
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeFactory;
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeSupplier;
+import com.tvd12.ezyfoxserver.bean.EzySingletonFactory;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyConfiguration;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyConfigurationBefore;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyPackagesScan;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyPrototype;
+import com.tvd12.ezyfoxserver.bean.annotation.EzySingleton;
+import com.tvd12.ezyfoxserver.bean.exception.EzyNewSingletonException;
+import com.tvd12.ezyfoxserver.bean.exception.EzySingletonException;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyArrayListSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyCollectionSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyConcurrentHashMapSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyCopyOnWriteArrayListSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyCopyOnWriteArraySetSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyHashMapSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyHashSetSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyLinkedListSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyListSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyMapSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyQueueSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzySetSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyStackSupplier;
+import com.tvd12.ezyfoxserver.bean.supplier.EzyTreeMapSupplier;
+import com.tvd12.ezyfoxserver.properties.EzyPropertiesReader;
+import com.tvd12.ezyfoxserver.properties.EzySimplePropertiesReader;
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+import com.tvd12.ezyfoxserver.reflect.EzyPackages;
+import com.tvd12.ezyfoxserver.util.EzyHashMapSet;
+import com.tvd12.ezyfoxserver.util.EzyLoggable;
+import com.tvd12.ezyfoxserver.util.EzyMapSet;
+
+import lombok.Getter;
+
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public class EzySimpleBeanContext
+ extends EzyLoggable
+ implements EzyBeanContext {
+
+ @Getter
+ protected Properties properties;
+ @Getter
+ protected EzySingletonFactory singletonFactory;
+ @Getter
+ protected EzyPrototypeFactory prototypeFactory;
+ @Getter
+ protected EzyBeanNameTranslator beanNameTranslator;
+
+ protected EzyPropertiesReader propertiesReader;
+
+ @Override
+ public Object getBean(String name, Class type) {
+ Object object = getSingleton(name, type);
+ if(object != null)
+ return object;
+ return getPrototype(name, type);
+ }
+
+ @Override
+ public Object getBean(Class> type) {
+ return getBean(EzyBeanNameParser.getBeanName(type), type);
+ }
+
+ @Override
+ public T getSingleton(String name, Class type) {
+ return (T) singletonFactory.getSingleton(name, type);
+ }
+
+ @Override
+ public T getSingleton(Map properties) {
+ return (T) singletonFactory.getSingleton(properties);
+ }
+
+ @Override
+ public List getSingletons(Map properties) {
+ return singletonFactory.getSingletons(properties);
+ }
+
+ @Override
+ public T getPrototype(String name, Class type) {
+ EzyPrototypeSupplier supplier = prototypeFactory.getSupplier(name, type);
+ if(supplier == null)
+ throw new IllegalArgumentException("has no bean with name = " + name + ", and type " + type);
+ return (T) supplier.supply(this);
+ }
+
+ @Override
+ public T getPrototype(Map properties) {
+ EzyPrototypeSupplier supplier = getPrototypeSupplier(properties);
+ return supplier != null ? (T)supplier.supply(this) : null;
+ }
+
+ @Override
+ public List getPrototypes(Map properties) {
+ List list = new ArrayList<>();
+ List suppliers = getPrototypeSuppliers(properties);
+ for(EzyPrototypeSupplier supplier : suppliers)
+ list.add(supplier.supply(this));
+ return list;
+ }
+
+ @Override
+ public EzyPrototypeSupplier getPrototypeSupplier(Map properties) {
+ return prototypeFactory.getSupplier(properties);
+ }
+
+ @Override
+ public List getPrototypeSuppliers(Map properties) {
+ return prototypeFactory.getSuppliers(properties);
+ }
+
+ @Override
+ public boolean containsProperty(Object key) {
+ return properties.containsKey(key);
+ }
+
+ @Override
+ public T getProperty(Object key, Class outType) {
+ return propertiesReader.get(properties, key, outType);
+ }
+
+ public static EzyBeanContextBuilder builder() {
+ return new Builder();
+ }
+
+ public static class Builder extends EzyLoggable implements EzyBeanContextBuilder {
+ protected Properties properties;
+ protected Set singletonClasses;
+ protected Set prototypeClasses;
+ protected Set packagesScanClasses;
+ protected Set configurationClasses;
+ protected Set configurationBeforeClasses;
+ protected EzyPropertiesReader propertiesReader;
+ protected EzySingletonFactory singletonFactory;
+ protected EzyPrototypeFactory prototypeFactory;
+ protected EzyBeanNameTranslator beanNameTranslator;
+
+ protected EzyErrorHandler errorHandler;
+ protected EzyMapSet> unloadedSingletons;
+
+ public Builder() {
+ this.properties = new Properties();
+ this.singletonClasses = new HashSet<>();
+ this.prototypeClasses = new HashSet<>();
+ this.packagesScanClasses = new HashSet<>();
+ this.configurationClasses = new HashSet<>();
+ this.configurationBeforeClasses = new HashSet<>();
+ this.errorHandler = new EzySimpleErrorHandler();
+ this.unloadedSingletons = new EzyHashMapSet<>();
+ this.beanNameTranslator = new EzySimpleBeanNameTranslator();
+ this.singletonFactory = newBeanFactory(new EzySimpleSingletonFactory());
+ this.prototypeFactory = newBeanFactory(new EzySimplePrototypeFactory());
+ }
+
+ protected T newBeanFactory(T factory) {
+ factory.setBeanNameTranslator(beanNameTranslator);
+ return factory;
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#scan(java.lang.String)
+ */
+ @Override
+ public EzyBeanContextBuilder scan(String packageName) {
+ singletonClasses.addAll(getAnnotatedClasses(packageName, EzySingleton.class));
+ prototypeClasses.addAll(getAnnotatedClasses(packageName, EzyPrototype.class));
+ packagesScanClasses.addAll(getAnnotatedClasses(packageName, EzyPackagesScan.class));
+ configurationClasses.addAll(getAnnotatedClasses(packageName, EzyConfiguration.class));
+ configurationBeforeClasses.addAll(getAnnotatedClasses(packageName, EzyConfigurationBefore.class));
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#scan(java.lang.String)
+ */
+ @Override
+ public EzyBeanContextBuilder scan(String... packageNames) {
+ return scan(Sets.newHashSet(packageNames));
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#scan(java.lang.Iterable)
+ */
+ @Override
+ public EzyBeanContextBuilder scan(Iterable packageNames) {
+ packageNames.forEach(this::scan);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#addSingleton(java.lang.String, java.lang.Object)
+ */
+ @Override
+ public EzyBeanContextBuilder addSingleton(String name, Object singleton) {
+ singletonFactory.addSingleton(name, singleton);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#addPrototypeSupplier(java.lang.String, com.tvd12.ezyfoxserver.bean.EzyPrototypeSupplier)
+ */
+ @Override
+ public EzyBeanContextBuilder addPrototypeSupplier(String objectName, EzyPrototypeSupplier supplier) {
+ prototypeFactory.addSupplier(objectName, supplier);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#addSingletonClass(java.lang.Class)
+ */
+ @Override
+ public EzyBeanContextBuilder addSingletonClass(Class clazz) {
+ this.singletonClasses.add(clazz);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#addSingletonClasses(java.lang.Class)
+ */
+ @Override
+ public EzyBeanContextBuilder addSingletonClasses(Class... classes) {
+ return addSingletonClasses(Sets.newHashSet(classes));
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#addSingletonClasses(java.lang.Iterable)
+ */
+ @Override
+ public EzyBeanContextBuilder addSingletonClasses(Iterable classes) {
+ classes.forEach(this::addSingletonClass);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#addPrototypeClass(java.lang.Class)
+ */
+ @Override
+ public EzyBeanContextBuilder addPrototypeClass(Class clazz) {
+ this.prototypeClasses.add(clazz);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#addPrototypeClasses(java.lang.Class)
+ */
+ @Override
+ public EzyBeanContextBuilder addPrototypeClasses(Class... classes) {
+ return addPrototypeClasses(Sets.newHashSet(classes));
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#addPrototypeClasses(java.lang.Iterable)
+ */
+ @Override
+ public EzyBeanContextBuilder addPrototypeClasses(Iterable classes) {
+ classes.forEach(this::addPrototypeClass);
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.EzyBeanContextBuilder#errorHandler(com.tvd12.ezyfoxserver.bean.EzyErrorHandler)
+ */
+ @Override
+ public EzyBeanContextBuilder errorHandler(EzyErrorHandler handler) {
+ this.errorHandler = handler;
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.EzyBeanContextBuilder#addProperties(java.util.Map)
+ */
+ @Override
+ public EzyBeanContextBuilder addProperties(Map properties) {
+ this.properties.putAll(properties);
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.EzyBeanContextBuilder#addProperty(java.lang.String, java.lang.Object)
+ */
+ public EzyBeanContextBuilder addProperty(String key, Object value) {
+ this.properties.put(key, value);
+ return this;
+ }
+
+ @Override
+ public EzyBeanContextBuilder propertiesReader(EzyPropertiesReader propertiesReader) {
+ this.propertiesReader = propertiesReader;
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.tvd12.ezyfoxserver.bean.impl.EzyBeanContextBuilder#build()
+ */
+ @Override
+ public EzySimpleBeanContext build() {
+ EzySimpleBeanContext context = new EzySimpleBeanContext();
+ context.properties = properties;
+ context.prototypeFactory = prototypeFactory;
+ context.singletonFactory = singletonFactory;
+ context.beanNameTranslator = beanNameTranslator;
+ context.propertiesReader = getPropertiesReader();
+ addSingleton("beanContext", context);
+ addSingleton("singletonFactory", singletonFactory);
+ addSingleton("prototypeFactory", prototypeFactory);
+ addSingleton("beanNameTranslator", beanNameTranslator);
+ scanPackagesScanClasses();
+ prototypeClasses.removeAll(singletonClasses);
+ loadConfigurationBeforeClasses(context);
+ addScannedSingletonsToFactory(context);
+ addDefaultPrototypeSuppliers();
+ addScannedPrototypeSuppliersToFactory();
+ tryLoadUncompletedSingletonsAgain(context, false);
+ loadConfigurationClasses(context);
+ tryLoadUncompletedSingletonsAgain(context, true);
+ return context;
+ }
+
+ private Set> getAnnotatedClasses(String packageName, Class extends Annotation> annClass) {
+ return EzyPackages.getAnnotatedClasses(packageName, annClass);
+ }
+
+ private void addScannedSingletonsToFactory(EzyBeanContext context) {
+ for(Class type : singletonClasses)
+ createAndLoadSingleton(context, type);
+ }
+
+ private void addScannedPrototypeSuppliersToFactory() {
+ for(Class type : prototypeClasses)
+ createAndLoadPrototypeSupplier(type);
+ }
+
+ private Object createAndLoadSingleton(EzyBeanContext context, Class type) {
+ return createAndLoadSingleton(context, type, false);
+ }
+
+ private Object createAndLoadSingleton(EzyBeanContext context, Class type, boolean reload) {
+ String beanName = getSingletonName(type);
+ Object current = singletonFactory.getSingleton(beanName, type);
+ if(current != null && !reload) return current;
+ try {
+ return new EzyByConstructorSingletonLoader(new EzyClass(type)).load(context);
+ }
+ catch(EzyNewSingletonException e) {
+ unloadedSingletons.addItems(e.getErrorKey(), e.getSingletonClass());
+ return null;
+ }
+ }
+
+ private void createAndLoadPrototypeSupplier(Class type) {
+ String beanName = getPrototypeName(type);
+ Object current = prototypeFactory.getSupplier(beanName, type);
+ if(current == null)
+ new EzyByConstructorPrototypeSupplierLoader(new EzyClass(type)).load(prototypeFactory);
+ }
+
+ private void scanPackagesScanClasses() {
+ packagesScanClasses.forEach(this::scanPackagesScanClass);
+ }
+
+ private void scanPackagesScanClass(Class> clazz) {
+ scan(clazz.getAnnotation(EzyPackagesScan.class).value());
+ }
+
+ private void loadConfigurationBeforeClasses(EzyBeanContext context) {
+ List classes = EzyConfigurationBeforeClassSorter.sort(configurationBeforeClasses);
+ for(Class clazz : classes)
+ loadConfigurationClass(clazz, context);
+ }
+
+ private void loadConfigurationClasses(EzyBeanContext context) {
+ List classes = EzyConfigurationClassSorter.sort(configurationClasses);
+ for(Class clazz : classes)
+ loadConfigurationClass(clazz, context);
+ }
+
+ private void loadConfigurationClass(Class> clazz, EzyBeanContext context) {
+ new EzySimpleConfigurationLoader().context(context).clazz(clazz).load();
+ }
+
+ private void tryLoadUncompletedSingletonsAgain(EzyBeanContext context, boolean finish) {
+ Set keySet = new HashSet<>(unloadedSingletons.keySet());
+ for(EzyBeanKey key : keySet) {
+ Set> uncompleted = unloadedSingletons.get(key);
+ getLogger().debug("unload bean: {}, uncompleted: {}", key, uncompleted);
+ getLogger().debug("try load bean {} again", key);
+ loadUncompletedSingletons(context, key, uncompleted, finish);
+ }
+ if(finish) {
+ while(!unloadedSingletons.isEmpty())
+ tryLoadUncompletedSingletonsAgain(context, finish);
+ }
+ }
+
+ private void loadUncompletedSingletons(
+ EzyBeanContext context, EzyBeanKey key, Set> uncompleted, boolean finish) {
+ Object singleton = getSingletonOfErrorBeanKey0(context, key, finish);
+ if(singleton == null) return;
+ getLogger().debug("found singleton {} with key {}", singleton, key);
+ for(Class> clazz : uncompleted) {
+ createAndLoadSingleton(context, clazz, true);
+ }
+ }
+
+ private Object getSingletonOfErrorBeanKey0(EzyBeanContext context, EzyBeanKey key, boolean finish) {
+ Object singleton = null;
+ try {
+ singleton = getSingletonOfErrorBeanKey(context, key);
+ }
+ catch(EzySingletonException e) {
+ if(finish) {
+ errorHandler.handle(e);
+ unloadedSingletons.remove(key);
+ }
+ }
+ if(finish && singleton != null) {
+ unloadedSingletons.remove(key);
+ }
+ return singleton;
+ }
+
+ private Object getSingletonOfErrorBeanKey(EzyBeanContext context, EzyBeanKey key) {
+ Object singleton = singletonFactory.getSingleton(key.getName(), key.getType());
+ if(singleton != null) return singleton;
+ return loadSingletonOfBeanKey(context, key);
+ }
+
+ private Object loadSingletonOfBeanKey(EzyBeanContext context, EzyBeanKey key) {
+ for(EzyBeanKey i : unloadedSingletons.keySet()) {
+ Set> classes = unloadedSingletons.get(i);
+ for(Class> implClass : classes) {
+ if(key.getType().isAssignableFrom(implClass)) {
+ return createAndLoadSingleton(context, implClass, true);
+ }
+ }
+ }
+ throw EzySingletonException.implementationNotFound(key, unloadedSingletons.get(key));
+ }
+
+ private EzyPropertiesReader getPropertiesReader() {
+ return propertiesReader != null ? propertiesReader : new EzySimplePropertiesReader();
+ }
+
+ private void addDefaultPrototypeSuppliers() {
+ prototypeFactory.addSupplier(new EzyArrayListSupplier());
+ prototypeFactory.addSupplier(new EzyCollectionSupplier());
+ prototypeFactory.addSupplier(new EzyConcurrentHashMapSupplier());
+ prototypeFactory.addSupplier(new EzyCopyOnWriteArrayListSupplier());
+ prototypeFactory.addSupplier(new EzyCopyOnWriteArraySetSupplier());
+ prototypeFactory.addSupplier(new EzyHashMapSupplier());
+ prototypeFactory.addSupplier(new EzyHashSetSupplier());
+ prototypeFactory.addSupplier(new EzyLinkedListSupplier());
+ prototypeFactory.addSupplier(new EzyListSupplier());
+ prototypeFactory.addSupplier(new EzyMapSupplier());
+ prototypeFactory.addSupplier(new EzyQueueSupplier());
+ prototypeFactory.addSupplier(new EzySetSupplier());
+ prototypeFactory.addSupplier(new EzyStackSupplier());
+ prototypeFactory.addSupplier(new EzyTreeMapSupplier());
+ }
+
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleBeanFactory.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleBeanFactory.java
new file mode 100644
index 00000000..e327dea4
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleBeanFactory.java
@@ -0,0 +1,28 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import com.tvd12.ezyfoxserver.bean.EzyBeanNameTranslator;
+import com.tvd12.ezyfoxserver.reflect.EzyClasses;
+import com.tvd12.ezyfoxserver.util.EzyLoggable;
+
+import lombok.Setter;
+
+public class EzySimpleBeanFactory extends EzyLoggable {
+
+ @Setter
+ protected EzyBeanNameTranslator beanNameTranslator;
+
+ protected final String translateBeanName(String name, Class> type) {
+ if(beanNameTranslator == null)
+ return name;
+ return beanNameTranslator.translate(name, type);
+ }
+
+ protected final void mapBeanName(String freename, Class> type, String realname) {
+ if(beanNameTranslator != null)
+ beanNameTranslator.map(freename, type, realname);
+ }
+
+ protected final String getDefaultBeanName(Class> type) {
+ return EzyClasses.getVariableName(type);
+ }
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleBeanNameTranslator.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleBeanNameTranslator.java
new file mode 100644
index 00000000..a130f748
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleBeanNameTranslator.java
@@ -0,0 +1,23 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.tvd12.ezyfoxserver.bean.EzyBeanNameTranslator;
+import static com.tvd12.ezyfoxserver.bean.impl.EzyBeanKey.*;
+
+public class EzySimpleBeanNameTranslator implements EzyBeanNameTranslator {
+
+ protected final Map map = new ConcurrentHashMap<>();
+
+ @Override
+ public String translate(String name, Class> type) {
+ EzyBeanKey key = of(name, type);
+ return map.containsKey(key) ? map.get(key) : name;
+ }
+
+ @Override
+ public void map(String freename, Class> type, String realname) {
+ map.put(of(freename, type), realname);
+ }
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleConfigurationLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleConfigurationLoader.java
new file mode 100644
index 00000000..88d34668
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleConfigurationLoader.java
@@ -0,0 +1,175 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.lang.annotation.Annotation;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import com.tvd12.ezyfoxserver.bean.EzyBeanConfig;
+import com.tvd12.ezyfoxserver.bean.EzyBeanContext;
+import com.tvd12.ezyfoxserver.bean.EzyBeanNameTranslator;
+import com.tvd12.ezyfoxserver.bean.EzyBeanNameTranslatorAware;
+import com.tvd12.ezyfoxserver.bean.EzyBeanContextAware;
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeFactory;
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeFactoryAware;
+import com.tvd12.ezyfoxserver.bean.EzySingletonFactory;
+import com.tvd12.ezyfoxserver.bean.EzySingletonFactoryAware;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyPrototype;
+import com.tvd12.ezyfoxserver.bean.annotation.EzySingleton;
+import com.tvd12.ezyfoxserver.io.EzyMaps;
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+import com.tvd12.ezyfoxserver.reflect.EzyField;
+import com.tvd12.ezyfoxserver.reflect.EzyMethod;
+import com.tvd12.ezyfoxserver.util.EzyLoggable;
+import com.tvd12.ezyfoxserver.util.EzyPropertiesAware;
+
+import static com.tvd12.ezyfoxserver.bean.impl.EzyBeanNameParser.*;
+
+public class EzySimpleConfigurationLoader
+ extends EzyLoggable
+ implements EzyConfigurationLoader {
+
+ protected EzyClass clazz;
+ protected Properties properties;
+ protected EzyBeanContext context;
+ protected EzyPrototypeFactory prototypeFactory;
+ protected EzySingletonFactory singletonFactory;
+ protected EzyBeanNameTranslator beanNameTranslator;
+ protected Map, EzyMethod> singletonMethods;
+
+ @Override
+ public EzyConfigurationLoader clazz(Class> configClass) {
+ this.clazz = new EzyClass(configClass);
+ this.singletonMethods = mapSingletonTypeMethods();
+ return this;
+ }
+
+ @Override
+ public EzyConfigurationLoader context(EzyBeanContext context) {
+ this.context = context;
+ this.properties = context.getProperties();
+ this.singletonFactory = context.getSingletonFactory();
+ this.prototypeFactory = context.getPrototypeFactory();
+ this.beanNameTranslator = context.getBeanNameTranslator();
+ return this;
+ }
+
+ @Override
+ public void load() {
+ Object configurator = newConfigurator();
+ addSingletonByFields(configurator);
+ addSingletonByMethods(configurator);
+ addPrototypeByFields(configurator);
+ addPrototypeByMethods(configurator);
+ }
+
+ private Object newConfigurator() {
+ Object object = new EzyByConstructorSingletonLoader(clazz)
+ .load(context);
+ if(object instanceof EzyBeanContextAware)
+ ((EzyBeanContextAware)object).setContext(context);
+ if(object instanceof EzyPropertiesAware)
+ ((EzyPropertiesAware)object).setProperties(properties);
+ if(object instanceof EzySingletonFactoryAware)
+ ((EzySingletonFactoryAware)object).setSingletonFactory(singletonFactory);
+ if(object instanceof EzyPrototypeFactoryAware)
+ ((EzyPrototypeFactoryAware)object).setPrototypeFactory(prototypeFactory);
+ if(object instanceof EzyBeanNameTranslatorAware)
+ ((EzyBeanNameTranslatorAware)object).setBeanNameTranslator(beanNameTranslator);
+ if(object instanceof EzyBeanConfig)
+ ((EzyBeanConfig)object).config();
+ return object;
+ }
+
+ private void addSingletonByFields(Object configurator) {
+ getSingletonFields().forEach(f -> addSingletonByField(f, configurator));
+ }
+
+ private void addSingletonByField(EzyField field, Object configurator) {
+ String beanName = getSingletonName(field);
+ Object current = singletonFactory.getSingleton(beanName, field.getType());
+ if(current == null)
+ new EzyByFieldSingletonLoader(
+ field, configurator, singletonMethods).load(context);
+ }
+
+ private void addSingletonByMethods(Object configurator) {
+ Set> types = new HashSet<>(singletonMethods.keySet());
+ for(Class> type : types) {
+ EzyMethod method = singletonMethods.remove(type);
+ if(method != null) {
+ getLogger().debug("add singleton of {} with method {}", type, method);
+ addSingletonByMethod(method, configurator);
+ }
+ }
+ }
+
+ private void addSingletonByMethod(EzyMethod method, Object configurator) {
+ String beanName = getSingletonName(method);
+ Object current = singletonFactory.getSingleton(beanName, method.getReturnType());
+ if(current == null) {
+ new EzyByMethodSingletonLoader(
+ method, configurator, singletonMethods).load(context);
+ }
+ }
+
+ //============ prototype =================
+ private void addPrototypeByFields(Object configurator) {
+ getPrototypeFields().forEach(f -> addPrototypeByField(f, configurator));
+ }
+
+ private void addPrototypeByField(EzyField field, Object configurator) {
+ String beanName = getPrototypeName(field);
+ Object current = prototypeFactory.getSupplier(beanName, field.getType());
+ if(current == null)
+ new EzyByFieldPrototypeSupplierLoader(field, configurator).load(prototypeFactory);
+ }
+
+ private void addPrototypeByMethods(Object configurator) {
+ Map, EzyMethod> methods = mapPrototypeTypeMethods();
+ Set> types = new HashSet<>(methods.keySet());
+ for(Class> type : types)
+ addPrototypeByMethod(methods.remove(type), configurator, methods);
+ }
+
+ private void addPrototypeByMethod(EzyMethod method,
+ Object configurator, Map, EzyMethod> methods) {
+ String beanName = getPrototypeName(method);
+ Object current = prototypeFactory.getSupplier(beanName, method.getReturnType());
+ if(current == null) {
+ new EzyByMethodPrototypeSupplierLoader(method, configurator).load(prototypeFactory);
+ }
+ }
+
+ //============ get components ==========
+
+ private List getSingletonFields() {
+ return getBeanFields(EzySingleton.class);
+ }
+
+ private Map, EzyMethod> mapSingletonTypeMethods() {
+ return mapBeanTypeMethods(EzySingleton.class);
+ }
+
+ private List getPrototypeFields() {
+ return getBeanFields(EzyPrototype.class);
+ }
+
+ private Map, EzyMethod> mapPrototypeTypeMethods() {
+ return mapBeanTypeMethods(EzyPrototype.class);
+ }
+
+ private List getBeanFields(Class extends Annotation> annClass) {
+ return clazz.getPublicFields(f -> f.isAnnotated(annClass));
+ }
+
+ private Map, EzyMethod> mapBeanTypeMethods(Class extends Annotation> annClass) {
+ List methods = clazz.getPublicMethods(m ->
+ m.isAnnotated(annClass) &&
+ m.getReturnType() != void.class
+ );
+ return EzyMaps.newHashMap(methods, m -> m.getReturnType());
+ }
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleErrorHandler.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleErrorHandler.java
new file mode 100644
index 00000000..3b7668c6
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleErrorHandler.java
@@ -0,0 +1,15 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import com.tvd12.ezyfoxserver.bean.EzyErrorHandler;
+import com.tvd12.ezyfoxserver.util.EzyLoggable;
+
+public class EzySimpleErrorHandler
+ extends EzyLoggable
+ implements EzyErrorHandler {
+
+ @Override
+ public void handle(Throwable error) {
+ getLogger().warn("error", error);
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleObjectBuilder.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleObjectBuilder.java
new file mode 100644
index 00000000..22e54adc
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleObjectBuilder.java
@@ -0,0 +1,166 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
+
+import com.tvd12.ezyfoxserver.annotation.EzyProperty;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyAutoBind;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyPostInit;
+import com.tvd12.ezyfoxserver.io.EzyLists;
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+import com.tvd12.ezyfoxserver.reflect.EzyClasses;
+import com.tvd12.ezyfoxserver.reflect.EzyField;
+import com.tvd12.ezyfoxserver.reflect.EzyMethod;
+import com.tvd12.ezyfoxserver.reflect.EzyReflectElement;
+import com.tvd12.ezyfoxserver.reflect.EzySetterMethod;
+import com.tvd12.ezyfoxserver.util.EzyLoggable;
+import com.tvd12.ezyfoxserver.util.EzyPropertyAnnotations;
+
+@SuppressWarnings("rawtypes")
+public abstract class EzySimpleObjectBuilder extends EzyLoggable {
+
+ protected final EzyClass clazz;
+ protected final AtomicInteger variableCount;
+ protected final List bindingFields;
+ protected final List bindingMethods;
+ protected final List propertyFields;
+ protected final List propertyMethods;
+
+ public EzySimpleObjectBuilder(EzyClass clazz) {
+ this.clazz = clazz;
+ this.variableCount = new AtomicInteger(0);
+ this.bindingFields = getBindingFields(clazz);
+ this.bindingMethods = getBindingMethods(clazz);
+ this.propertyFields = getPropertyFields(clazz);
+ this.propertyMethods = getPropertyMethods(clazz);
+ }
+
+ protected Constructor getConstructor(EzyClass clazz) {
+ List constructors = clazz.getDeclaredConstructors();
+ for(Constructor con : constructors)
+ if(con.isAnnotationPresent(EzyAutoBind.class))
+ return con;
+ return clazz.getDeclaredConstructor();
+ }
+
+ protected abstract Class>[] getConstructorParameterTypes();
+
+ protected String[] getConstructorArgumentNames() {
+ return getArgumentNames(getConstructorParameterTypes());
+ }
+
+ protected final String[] getArgumentNames(Class>[] parameterTypes) {
+ String[] names = new String[parameterTypes.length];
+ for(int i = 0 ; i < parameterTypes.length ; i++)
+ names[i] = EzyClasses.getVariableName(parameterTypes[i]);
+ return names;
+ }
+
+ protected final String[] getConstructorArgumentNames(EzyAutoBind annotation) {
+ Class>[] parameterTypes = getConstructorParameterTypes();
+ String[] names = getArgumentNames(parameterTypes);
+ if(annotation == null) return names;
+ String[] fixNames = annotation.value();
+ for(int i = 0 ; i < fixNames.length ; i++)
+ if(i < names.length) names[i] = fixNames[i];
+ return names;
+ }
+
+ protected final String[] getConstructorArgumentNames(Constructor> constructor) {
+ return getConstructorArgumentNames(
+ constructor.getAnnotation(EzyAutoBind.class));
+ }
+
+ protected final List getBindingFields(EzyClass clazz) {
+ return getValidFields(clazz, EzyAutoBind.class);
+ }
+
+ protected final List getBindingMethods(EzyClass clazz) {
+ return getValidMethods(clazz, this::isBindingMethod);
+ }
+
+ protected final List getPropertyFields(EzyClass clazz) {
+ return getValidFields(clazz, EzyProperty.class);
+ }
+
+ protected final List getPropertyMethods(EzyClass clazz) {
+ return getValidMethods(clazz, this::isPropertyMethod);
+ }
+
+ protected final List getPostInitMethods() {
+ return clazz.getPublicMethods(m ->
+ m.isAnnotated(EzyPostInit.class) &&
+ m.getParameterCount() == 0
+ );
+ }
+
+ private boolean isBindingMethod(EzyMethod method) {
+ return isValidMethod(method, EzyAutoBind.class);
+ }
+
+ private boolean isPropertyMethod(EzyMethod method) {
+ return isValidMethod(method, EzyProperty.class);
+ }
+
+ private List getValidFields(
+ EzyClass clazz, Class extends Annotation> ann) {
+ return clazz.getFields(f -> f.isPublic() && f.isAnnotated(ann));
+ }
+
+ private List
+ getValidMethods(EzyClass clazz, Predicate predicate) {
+ List methods = clazz.getMethods();
+ List valid = EzyLists.filter(methods, predicate);
+ return EzyLists.newArrayList(valid, EzySetterMethod::new);
+ }
+
+ private boolean isValidMethod(EzyMethod method, Class extends Annotation> ann) {
+ if(!method.isPublic())
+ return false;
+ if(method.getParameterCount() != 1)
+ return false;
+ EzyField field = clazz.getField(method.getFieldName());
+ boolean answer =
+ field != null &&
+ !field.isPublic() &&
+ field.isAnnotated(ann);
+ return answer ? answer : method.isAnnotated(ann);
+ }
+
+ protected final boolean isAbstractClass(Class> clazz) {
+ return Modifier.isAbstract(clazz.getModifiers());
+ }
+
+ protected final String getBeanName(EzyReflectElement element) {
+ if(element instanceof EzyField)
+ return getBeanName((EzyField)element);
+ return getBeanName((EzyMethod)element);
+ }
+
+ private String getBeanName(EzyField field) {
+ EzyAutoBind annotation = field.getAnnotation(EzyAutoBind.class);
+ if(annotation == null)
+ return field.getName();
+ if(annotation.value().length > 0 && annotation.value()[0].length() > 0)
+ return annotation.value()[0];
+ return field.getName();
+ }
+
+ private final String getBeanName(EzyMethod method) {
+ EzyAutoBind annotation = method.getAnnotation(EzyAutoBind.class);
+ if(annotation != null && annotation.value().length > 0)
+ return annotation.value()[0];
+ String fieldName = method.getFieldName();
+ EzyField field = clazz.getField(fieldName);
+ return field != null ? getBeanName(field) : fieldName;
+ }
+
+ protected final String getPropertyName(EzyReflectElement element) {
+ return EzyPropertyAnnotations.getPropertyName(clazz, element);
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimplePrototypeFactory.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimplePrototypeFactory.java
new file mode 100644
index 00000000..bd85022b
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimplePrototypeFactory.java
@@ -0,0 +1,121 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.tvd12.ezyfoxserver.annotation.EzyKeyValue;
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeFactory;
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeSupplier;
+import com.tvd12.ezyfoxserver.bean.annotation.EzyPrototype;
+import com.tvd12.ezyfoxserver.io.EzyMaps;
+import static com.tvd12.ezyfoxserver.reflect.EzyClasses.*;
+import static com.tvd12.ezyfoxserver.bean.impl.EzyBeanKey.*;
+
+@SuppressWarnings({ "unchecked", "rawtypes" })
+public class EzySimplePrototypeFactory
+ extends EzySimpleBeanFactory
+ implements EzyPrototypeFactory {
+
+ protected final Map supplierByKey
+ = new ConcurrentHashMap<>();
+ protected final Map suppliersByProperties
+ = new ConcurrentHashMap<>();
+
+ @Override
+ public EzyPrototypeSupplier getSupplier(String objectName, Class objectType) {
+ String realname = translateBeanName(objectName, objectType);
+ return supplierByKey.get(of(realname, objectType));
+ }
+
+ @Override
+ public EzyPrototypeSupplier getSupplier(Map properties) {
+ for(Entry entry : suppliersByProperties.entrySet())
+ if(EzyMaps.containsAll(entry.getValue(), properties))
+ return entry.getKey();
+ return null;
+ }
+
+ @Override
+ public List getSuppliers(Map properties) {
+ List list = new ArrayList<>();
+ for(Entry entry : suppliersByProperties.entrySet())
+ if(EzyMaps.containsAll(entry.getValue(), properties))
+ list.add(entry.getKey());
+ return list;
+ }
+
+ @Override
+ public List getSuppliers(Class annoClass) {
+ List list = new ArrayList<>();
+ for(EzyBeanKey key : supplierByKey.keySet()) {
+ Class type = key.getType();
+ if(type.isAnnotationPresent(annoClass))
+ list.add(supplierByKey.get(type));
+ }
+ return list;
+ }
+
+ @Override
+ public Map getProperties(EzyPrototypeSupplier supplier) {
+ return suppliersByProperties.get(supplier);
+ }
+
+ @Override
+ public void addSupplier(EzyPrototypeSupplier supplier) {
+ Class type = supplier.getObjectType();
+ addSupplier(getBeanName(type), supplier);
+ }
+
+ @Override
+ public void addSupplier(String objectName, EzyPrototypeSupplier supplier) {
+ Class> type = supplier.getObjectType();
+ addSupplier(objectName, supplier, getProperties(type));
+ }
+
+ @Override
+ public void addSupplier(
+ String objectName, EzyPrototypeSupplier supplier, Map properties) {
+ Class> type = supplier.getObjectType();
+ EzyBeanKey key = of(objectName, type);
+
+ if(supplierByKey.containsKey(key))
+ return;
+
+ supplierByKey.put(key, supplier);
+ suppliersByProperties.put(supplier, properties);
+
+ String defname = getDefaultBeanName(type);
+ mapBeanName(defname, type, objectName);
+
+ Set subTypes = flatSuperAndInterfaceClasses(type, true);
+ for(Class> subType : subTypes)
+ checkAndAddSupplier(objectName, subType, supplier);
+ }
+
+ private void checkAndAddSupplier(
+ String objectName, Class> type, EzyPrototypeSupplier supplier) {
+ EzyBeanKey key = of(objectName, type);
+ if(supplierByKey.containsKey(key))
+ return;
+ supplierByKey.put(key, supplier);
+ }
+
+ private String getBeanName(Class> type) {
+ return EzyBeanNameParser.getPrototypeName(type);
+ }
+
+ private Map getProperties(Class> type) {
+ EzyPrototype ann = type.getAnnotation(EzyPrototype.class);
+ Map properties = new HashMap<>();
+ EzyKeyValue[] keyValues = ann != null ? ann.properties() : new EzyKeyValue[0];
+ Arrays.stream(keyValues).forEach(kv -> properties.put(kv.key(), kv.value()));
+ return properties;
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimplePrototypeSupplierLoader.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimplePrototypeSupplierLoader.java
new file mode 100644
index 00000000..62ae194f
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimplePrototypeSupplierLoader.java
@@ -0,0 +1,301 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.tvd12.ezyfoxserver.asm.EzyFunction;
+import com.tvd12.ezyfoxserver.asm.EzyInstruction;
+import com.tvd12.ezyfoxserver.bean.EzyBeanContext;
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeFactory;
+import com.tvd12.ezyfoxserver.bean.EzyPrototypeSupplier;
+import com.tvd12.ezyfoxserver.io.EzyStrings;
+import com.tvd12.ezyfoxserver.reflect.EzyClass;
+import com.tvd12.ezyfoxserver.reflect.EzyField;
+import com.tvd12.ezyfoxserver.reflect.EzyMethod;
+import com.tvd12.ezyfoxserver.reflect.EzySetterMethod;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtNewMethod;
+import lombok.Setter;
+
+@SuppressWarnings("rawtypes")
+public abstract class EzySimplePrototypeSupplierLoader
+ extends EzySimpleObjectBuilder
+ implements EzyPrototypeSupplierLoader {
+
+ @Setter
+ private static boolean debug;
+ private static final AtomicInteger COUNT = new AtomicInteger(0);
+
+ public EzySimplePrototypeSupplierLoader(EzyClass clazz) {
+ super(clazz);
+ }
+
+ @Override
+ public final EzyPrototypeSupplier load(EzyPrototypeFactory factory) {
+ try {
+ return process(factory);
+ }
+ catch(Exception e) {
+ throw new IllegalStateException("can not create prototype supplier of class " + clazz, e);
+ }
+ }
+
+ private Class> getPrototypeClass() {
+ return clazz.getClazz();
+ }
+
+ protected String getPrototypeName() {
+ return EzyBeanNameParser.getPrototypeName(getPrototypeClass());
+ }
+
+ protected Map getAnnotationProperties() {
+ return EzyKeyValueParser.getPrototypeProperties(getPrototypeClass());
+ }
+
+ private EzyPrototypeSupplier process(EzyPrototypeFactory factory) throws Exception {
+ ClassPool pool = ClassPool.getDefault();
+ String implClassName = getImplClassName();
+ CtClass implClass = pool.makeClass(implClassName);
+
+ EzyMethod supplyMethod = getSupplyMethod();
+ supplyMethod.setDisplayName("supply$impl");
+ String supplyImplMethodContent = makeSupplyImplMethodContent(supplyMethod);
+ supplyMethod.setDisplayName("supply");
+ String supplyMethodContent = makeSupplyMethodContent(supplyMethod);
+
+ EzyMethod getObjectTypeMethod = getGetObjectTypeMethod();
+ String getObjectTypeMethodContent = makeGetObjectTypeMethodContent(getObjectTypeMethod);
+
+ printMethodContent(supplyMethodContent);
+ printMethodContent(supplyImplMethodContent);
+ printMethodContent(getObjectTypeMethodContent);
+
+ implClass.setInterfaces(new CtClass[] { pool.makeClass(EzyPrototypeSupplier.class.getName()) });
+ implClass.addMethod(CtNewMethod.make(supplyImplMethodContent, implClass));
+ implClass.addMethod(CtNewMethod.make(supplyMethodContent, implClass));
+ implClass.addMethod(CtNewMethod.make(getObjectTypeMethodContent, implClass));
+ Class answerClass = implClass.toClass();
+ implClass.detach();
+ EzyPrototypeSupplier supplier = (EzyPrototypeSupplier)answerClass.newInstance();
+ factory.addSupplier(getPrototypeName(), supplier, getAnnotationProperties());
+ getLogger().debug("add prototype supplier of " + implClassName);
+ return supplier;
+ }
+
+ private String makeGetObjectTypeMethodContent(EzyMethod method) {
+ return new EzyFunction(method)
+ .body()
+ .append(new EzyInstruction("\t", "\n")
+ .answer()
+ .clazz(clazz.getClazz(), true))
+ .function()
+ .toString();
+ }
+
+ private String makeSupplyMethodContent(EzyMethod method) {
+ return new EzyFunction(method)
+ .body()
+ .append(new EzyInstruction("\t", "\n", false)
+ .append("try {"))
+ .append(new EzyInstruction("\t\t", "\n")
+ .append("return this.supply$impl(arg0)"))
+ .append(new EzyInstruction("\t", "\n", false)
+ .append("} catch(")
+ .clazz(Exception.class)
+ .append(" e) {"))
+ .append(new EzyInstruction("\t\t", "\n\t}\n")
+ .append("throw new ")
+ .clazz(IllegalStateException.class)
+ .bracketopen()
+ .string("can't create bean of " + clazz.getClazz().getTypeName())
+ .append(", e")
+ .bracketclose())
+ .function()
+ .toString();
+ }
+
+ private String makeSupplyImplMethodContent(EzyMethod method) {
+ EzyFunction.EzyBody methodBody = new EzyFunction(method)
+ .modifier("protected")
+ .body();
+ addConstructInstruction(methodBody);
+ addSetPropertiesInstructions(methodBody);
+ addBindingValueInstructions(methodBody);
+ addCallPostInitInstructions(methodBody);
+ addReturnInstruction(methodBody);
+ EzyFunction function = methodBody.function();
+ return function.toString();
+ }
+
+ private void addConstructInstruction(EzyFunction.EzyBody body) {
+ List cparams = addAndGetConstructorParamNames(body);
+ EzyInstruction instruction = newConstructInstruction(body, cparams);
+ body.append(instruction);
+ }
+
+ private List addAndGetConstructorParamNames(EzyFunction.EzyBody body) {
+ int index = 0;
+ List cparams = new ArrayList<>();
+ String[] argumentNames = getConstructorArgumentNames();
+ for(Class type : getConstructorParameterTypes()) {
+ String variableName = "cparam" + index;
+ String beanName = EzyStrings.getString(argumentNames, index ++, variableName);
+ cparams.add(variableName);
+ body.append(newVariableInstruction(type, variableName, beanName));
+ }
+ return cparams;
+ }
+
+ protected EzyInstruction newConstructInstruction(EzyFunction.EzyBody body, List cparams) {
+ EzyInstruction instruction = new EzyInstruction("\t", "\n")
+ .variable(clazz.getClazz(), "object")
+ .equal()
+ .append("new ")
+ .clazz(clazz.getClazz())
+ .bracketopen()
+ .append(StringUtils.join(cparams, ", "))
+ .bracketclose();
+ return instruction;
+ }
+
+ protected final EzyInstruction newVariableInstruction(Class varType, String varName, String beanName) {
+ return new EzyInstruction("\t", "\n")
+ .variable(varType, varName)
+ .equal()
+ .bracketopen()
+ .clazz(varType)
+ .bracketclose()
+ .append("arg0.getBean")
+ .bracketopen()
+ .string(beanName)
+ .comma()
+ .clazz(varType, true)
+ .bracketclose();
+ }
+
+ private void addReturnInstruction(EzyFunction.EzyBody body) {
+ EzyInstruction instruction = new EzyInstruction("\t", "\n")
+ .answer()
+ .append("object");
+ body.append(instruction);
+ }
+
+ private void addSetPropertiesInstructions(EzyFunction.EzyBody body) {
+ for(EzyField field : propertyFields)
+ addSetPropertyInstruction(body, field);
+ for(EzySetterMethod method : propertyMethods)
+ addSetPropertyInstruction(body, method);
+ }
+
+ private void addSetPropertyInstruction(EzyFunction.EzyBody body, EzyField field) {
+ Class propertyType = field.getType();
+ String propertyName = getPropertyName(field);
+ body.append(new EzyInstruction("\t", "\n", false)
+ .append("if(arg0.containsProperty(\"" + propertyName + "\"))"));
+ body.append(new EzyInstruction("\t\t", "\n")
+ .append("object.")
+ .append(field.getName())
+ .equal()
+ .brackets(propertyType)
+ .append("arg0.getProperty")
+ .bracketopen()
+ .string(propertyName)
+ .comma()
+ .clazz(propertyType, true)
+ .bracketclose());
+ }
+
+ private void addSetPropertyInstruction(EzyFunction.EzyBody body, EzySetterMethod method) {
+ Class propertyType = method.getType();
+ String propertyName = getPropertyName(method);
+ body.append(new EzyInstruction("\t", "\n", false)
+ .append("if(arg0.containsProperty(\"" + propertyName + "\"))"));
+ body.append(new EzyInstruction("\t\t", "\n")
+ .append("object.")
+ .append(method.getName())
+ .bracketopen()
+ .brackets(propertyType)
+ .append("arg0.getProperty")
+ .bracketopen()
+ .string(propertyName)
+ .comma()
+ .clazz(propertyType, true)
+ .bracketclose()
+ .bracketclose());
+ }
+
+ private void addBindingValueInstructions(EzyFunction.EzyBody body) {
+ for(EzyField field : bindingFields)
+ addBindingValueInstruction(body, field);
+ for(EzySetterMethod method : bindingMethods)
+ addBindingValueInstruction(body, method);
+ }
+
+ private void addBindingValueInstruction(
+ EzyFunction.EzyBody body, EzyField field) {
+ String variableName = field.getName() + variableCount.incrementAndGet();
+ Class propertyType = field.getType();
+ body.append(newVariableInstruction(propertyType, variableName, getBeanName(field)));
+ EzyInstruction instruction = new EzyInstruction("\t", "\n")
+ .append("object.")
+ .append(field.getName())
+ .equal()
+ .append(variableName);
+ body.append(instruction);
+ }
+
+ private void addBindingValueInstruction(
+ EzyFunction.EzyBody body, EzySetterMethod method) {
+ String variableName = method.getFieldName() + variableCount.incrementAndGet();
+ Class propertyType = method.getType();
+ body.append(newVariableInstruction(propertyType, variableName, getBeanName(method)));
+ EzyInstruction instruction = new EzyInstruction("\t", "\n")
+ .append("object.")
+ .append(method.getName())
+ .brackets(variableName);
+ body.append(instruction);
+ }
+
+ private void addCallPostInitInstructions(EzyFunction.EzyBody body) {
+ List methods = getPostInitMethods();
+ methods.forEach(m -> addCallPostInitInstruction(body, m));
+ }
+
+ private void addCallPostInitInstruction(EzyFunction.EzyBody body, EzyMethod method) {
+ EzyInstruction instruction = new EzyInstruction("\t", "\n")
+ .append("object.")
+ .append(method.getName())
+ .brackets("");
+ body.append(instruction);
+ }
+
+ private String getImplClassName() {
+ return clazz.getName() + "$EzyPrototypeSupplier$EzyAutoImpl$" + COUNT.incrementAndGet();
+ }
+
+ private EzyMethod getSupplyMethod() {
+ return EzyMethod.builder()
+ .clazz(EzyPrototypeSupplier.class)
+ .methodName("supply")
+ .parameterTypes(EzyBeanContext.class)
+ .build();
+ }
+
+ private EzyMethod getGetObjectTypeMethod() {
+ return EzyMethod.builder()
+ .clazz(EzyPrototypeSupplier.class)
+ .methodName("getObjectType")
+ .build();
+ }
+
+ private void printMethodContent(String methodContent) {
+ if(debug) getLogger().debug("reader: method content \n{}", methodContent);
+ }
+
+}
diff --git a/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleSingletonFactory.java b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleSingletonFactory.java
new file mode 100644
index 00000000..e03972f7
--- /dev/null
+++ b/ezyfox-server-bean/src/main/java/com/tvd12/ezyfoxserver/bean/impl/EzySimpleSingletonFactory.java
@@ -0,0 +1,112 @@
+package com.tvd12.ezyfoxserver.bean.impl;
+
+import static com.tvd12.ezyfoxserver.bean.impl.EzyBeanKey.of;
+import static com.tvd12.ezyfoxserver.reflect.EzyClasses.flatSuperAndInterfaceClasses;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.tvd12.ezyfoxserver.bean.EzySingletonFactory;
+import com.tvd12.ezyfoxserver.io.EzyMaps;
+
+@SuppressWarnings({ "unchecked", "rawtypes" })
+public class EzySimpleSingletonFactory
+ extends EzySimpleBeanFactory
+ implements EzySingletonFactory {
+
+ protected final Map objectsByKey
+ = new ConcurrentHashMap<>();
+ protected final Map