├── .gitignore
├── CHANGELOG.MD
├── README.md
├── TODO.md
├── crabs-common
├── pom.xml
└── src
│ └── main
│ └── java
│ └── org
│ └── codefamily
│ └── crabs
│ ├── Constants.java
│ ├── Product.java
│ ├── exception
│ ├── CrabsError.java
│ └── CrabsException.java
│ └── util
│ ├── ExtensionClassCollector.java
│ ├── ReadonlyList.java
│ ├── RegularExpressionHelper.java
│ ├── StringUtils.java
│ └── TimeCacheMap.java
├── crabs-core
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── org
│ │ └── codefamily
│ │ └── crabs
│ │ └── core
│ │ ├── DataType.java
│ │ ├── Document.java
│ │ ├── DocumentFactory.java
│ │ ├── Identifier.java
│ │ ├── IndexDefinition.java
│ │ ├── TypeDefinition.java
│ │ ├── client
│ │ ├── AdvancedClient.java
│ │ ├── IndexDefinitionManager.java
│ │ └── TypeDefinitionManager.java
│ │ └── exception
│ │ ├── FieldAlreadyExistsException.java
│ │ ├── FieldNotExistsException.java
│ │ ├── FormatPatternNotFoundException.java
│ │ ├── IndexAlreadyExistsException.java
│ │ ├── IndexNotExistsException.java
│ │ ├── PrimaryFieldAlreadyExistsException.java
│ │ ├── PrimaryFieldNotFoundException.java
│ │ ├── TypeAlreadyExistsException.java
│ │ ├── TypeNotExistsException.java
│ │ └── UnsupportedDataTypeException.java
│ └── test
│ └── java
│ └── org
│ └── codefamily
│ └── crabs
│ └── core
│ └── client
│ ├── IndexDefinitionManagerTest.java
│ └── TypeDefinitionManagerTest.java
├── crabs-jdbc
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── org
│ │ │ └── codefamily
│ │ │ └── crabs
│ │ │ └── jdbc
│ │ │ ├── BaseClasses.java
│ │ │ ├── Connection.java
│ │ │ ├── DataSource.java
│ │ │ ├── DataSourceFactory.java
│ │ │ ├── Driver.java
│ │ │ ├── PreparedStatement.java
│ │ │ ├── Protocol.java
│ │ │ ├── ResultSet.java
│ │ │ ├── Statement.java
│ │ │ ├── benchmark
│ │ │ └── Benchmark.java
│ │ │ ├── compiler
│ │ │ ├── FunctionFactory.java
│ │ │ ├── GrammarAnalyzer.java
│ │ │ ├── StatementCache.java
│ │ │ ├── StatementFactory.java
│ │ │ └── extension
│ │ │ │ ├── clause
│ │ │ │ ├── FromClauseGrammarAnalyzer.java
│ │ │ │ ├── GroupByClauseGrammarAnalyzer.java
│ │ │ │ ├── HavingClauseGrammarAnalyzer.java
│ │ │ │ ├── LimitClauseGrammarAnalyzer.java
│ │ │ │ ├── OrderByClauseGrammarAnalyzer.java
│ │ │ │ ├── SelectClauseGrammarAnalyzer.java
│ │ │ │ └── WhereClauseGrammarAnalyzer.java
│ │ │ │ └── statement
│ │ │ │ └── SelectStatementAdapter.java
│ │ │ ├── engine
│ │ │ ├── ExecuteEngine.java
│ │ │ ├── ExecuteEnvironment.java
│ │ │ ├── SemanticAnalyzer.java
│ │ │ ├── StatementExecutePlan.java
│ │ │ ├── StatementExecutePlanCache.java
│ │ │ ├── StatementExecutor.java
│ │ │ └── extension
│ │ │ │ └── SelectStatementExecutor.java
│ │ │ ├── internal
│ │ │ └── InternalResultSet.java
│ │ │ └── lang
│ │ │ ├── Clause.java
│ │ │ ├── Expression.java
│ │ │ ├── Keyword.java
│ │ │ ├── Statement.java
│ │ │ ├── expression
│ │ │ ├── Aggregation.java
│ │ │ ├── Argument.java
│ │ │ ├── Constant.java
│ │ │ ├── Function.java
│ │ │ ├── NonAggregation.java
│ │ │ ├── Null.java
│ │ │ ├── Reference.java
│ │ │ ├── context
│ │ │ │ └── Context.java
│ │ │ └── util
│ │ │ │ ├── ExpressionHelper.java
│ │ │ │ └── ExtensionExpressionFactory.java
│ │ │ └── extension
│ │ │ ├── ReservedKeyword.java
│ │ │ ├── clause
│ │ │ ├── FromClause.java
│ │ │ ├── GroupByClause.java
│ │ │ ├── HavingClause.java
│ │ │ ├── LimitClause.java
│ │ │ ├── OrderByClause.java
│ │ │ ├── SelectClause.java
│ │ │ └── WhereClause.java
│ │ │ ├── expression
│ │ │ ├── AdditionExpression.java
│ │ │ ├── AndExpression.java
│ │ │ ├── AverageFunction.java
│ │ │ ├── BetweenExpression.java
│ │ │ ├── ConcatFunction.java
│ │ │ ├── CountFunction.java
│ │ │ ├── DivisionExpression.java
│ │ │ ├── EqualToExpression.java
│ │ │ ├── GreaterThanExpression.java
│ │ │ ├── GreaterThanOrEqualToExpression.java
│ │ │ ├── InExpression.java
│ │ │ ├── IsNotNullExpression.java
│ │ │ ├── IsNullExpression.java
│ │ │ ├── LessThanExpression.java
│ │ │ ├── LessThanOrEqualToExpression.java
│ │ │ ├── LikeExpression.java
│ │ │ ├── MaxinumFunction.java
│ │ │ ├── MininumFunction.java
│ │ │ ├── ModuloExpression.java
│ │ │ ├── MultiplicationExpression.java
│ │ │ ├── NegativeExpression.java
│ │ │ ├── NotExpression.java
│ │ │ ├── NowFunction.java
│ │ │ ├── OrExpression.java
│ │ │ ├── PositiveExpression.java
│ │ │ ├── PreferentialExpression.java
│ │ │ ├── SubstringFunction.java
│ │ │ ├── SubtractionExpression.java
│ │ │ ├── SummaryFunction.java
│ │ │ └── UnequalToExpression.java
│ │ │ └── statement
│ │ │ └── SelectStatement.java
│ └── resources
│ │ └── META-INF
│ │ └── services
│ │ ├── java.sql.Driver
│ │ ├── org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer$ClauseGrammarAnalyzer
│ │ ├── org.codefamily.crabs.jdbc.compiler.StatementFactory$StatementAdapter
│ │ ├── org.codefamily.crabs.jdbc.engine.StatementExecutor
│ │ ├── org.codefamily.crabs.jdbc.engine.extension.SelectStatementExecutor$SelectStatementExecutePlan
│ │ └── org.codefamily.crabs.jdbc.lang.Expression
│ └── test
│ └── java
│ └── org
│ └── codefamily
│ └── crabs
│ └── jdbc
│ ├── PreparedStatementTest.java
│ ├── ProtocolTest.java
│ ├── StatementTest.java
│ ├── StatementTestBase.java
│ ├── compiler
│ └── GrammarAnalyzerTest.java
│ └── engine
│ └── extension
│ └── SelectStatementExecutorTest.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | BENCHMARK.md
3 | .idea
4 | target
5 |
--------------------------------------------------------------------------------
/CHANGELOG.MD:
--------------------------------------------------------------------------------
1 | ## 1.0.0
2 | * the first release of crabs.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Crabs is a SQL-like JDBC driver and command line for elasticsearch(v1.2.2). It follows the SQL-92 specification, and we introduce some appropriate adjustments based on the features of elasticsearch. Crabs is very simple for users, we provide JDBC driver. With it you may use elasticsearch as simply as using SQL with traditional database.
2 |
3 | __NOTE:__ When you use crabs, there are some restrictions on elasticsearch index and type.
4 |
5 | name of index and type: must follow java identifier specification, that are:
6 |
7 | the first character is must be "_", "$" or english character.
8 |
9 | the other characters are must be digit, "_", "$" or english characters.
10 |
11 | field name of type: it is the same of above.
12 |
13 | all names are case sensitive
14 |
15 | you must set "_id" mapping and be associated with a path, more details: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-id-field.html
16 |
17 | ## Documentation
18 | Now, crabs support two types of select statement, detail as bellow:
19 |
20 | __NOTE:__ SQL is case sensitive
21 |
22 | ### Non-aggregation query SQL
23 | SELECT {derived column list}
24 | FROM type
25 | [WHERE {where condition}]
26 | [HAVING {having condition}]
27 | [ORDER BY order-specifications]
28 | [LIMIT offset, rowCount]
29 |
30 | #### where
31 | {derived column list}: '*' or comma-separated list of field names or constant and they can have aliases
32 | {where condition}:
33 | {field name} [>, >=, <, <=, =, <>] value
34 | {field name} like {pattern}
35 | {field name} not like {pattern}
36 | {field name} in(value1, value2, ...)
37 | {field name} not in(value1, value2, ...)
38 | {field name} between min-value and max-value
39 | {field name} not between min-value and max-value
40 | {where condition} and {where condition}
41 | {where condition} or {where condition}
42 | {having search}:
43 | similar to {where condition}, but field name is replaced with derived column name
44 | {order-specifications}:
45 | comma-separated list of {derived column name ASC|DESC}
46 | {offset}:
47 | start index of query result to returned, similar to "from" of elasticsearch
48 | {rowCount}:
49 | max count of rows to returned, similar to "size" of elasticsearch
50 | {pattern}:
51 | consist of '%' and string value.
52 |
53 | __NOTE:__ Now, crabs does not support scroll, so, when the query result is too large, it will be truncated. The defualt critical value is 500, of cause, you can set the property(clientScanSize) when you create a JDBC connection to change the default value.
54 |
55 | ### Aggregation query SQL
56 | SELECT {aggregation expression list}|{group by column list}|{value}
57 | FORM type
58 | [WHERE {where condition}]
59 | [GROUP BY {group column list}]
60 |
61 | #### where
62 | {aggregation expression list}:
63 | comma-separated list of aggregate functions and they can have aliases
64 | {group by column list}:
65 | comma-separated list of field names, and the field must be exist in group column list.
66 | {where condition}:
67 | similar to "where condition" of Non-aggregation query SQL
68 | {group column list}:
69 | comma-separated list of field names
70 | {aggregate functions}:
71 | sum('field name'), count('*'|'field name'), avg('field name'), max('field name'), min('field name')
72 |
73 | ### DataType
74 | double, float, long, int, boolean, String, Date
75 |
76 | __NOTE:__ For the date type, crabs also supports user-defined date format, only need to follow java date format pattern specification.
77 |
78 | ### JDBC URL
79 | jdbc:crabs://{elasticsearch address}[{, elasticsearch address}...]/indexName[?{propertyName=propertyValue}][{&propertyName=propertyValue}...]
80 |
81 | #### where
82 | {elasticsearch address} : ip:port
83 |
84 | #### properties
85 | Crabs has two system properties. Details as bellow:
86 |
87 | clientScanSize: define the max count of rows returned per query and only works on Non-aggregation query SQL
88 |
89 | metaDataTTL: define the ttl of meta data(index and type meta data) in crabs, its unit is minute.
90 |
91 | ## More
92 |
93 | Details about elasticsearch, http://www.elasticsearch.org
94 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | 1. 执行计划中对正则表达式的处理,需要将用户输入的含有特殊字符的的字符串转换成ES识别的普通字符串,有待处理的特殊字符有:
2 | . ? + * | { } [ ] ( ) " \ # @ & < > ~
3 | 2. 支持更多的数据类型:short, byte, time
4 | 3. 执行计划优化:批处理,代码结构优化
5 | 4. 常见运算表达式的支持
6 | 5. 集成sqlline命令行
--------------------------------------------------------------------------------
/crabs-common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | crabs
7 | org.codefamily
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | crabs-common
13 |
14 |
15 |
--------------------------------------------------------------------------------
/crabs-common/src/main/java/org/codefamily/crabs/Constants.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs;
2 |
3 | /**
4 | * 常量
5 | *
6 | * @author zhuchunlai
7 | * @version $Id: Constants.java, v1.0 2014/07/30 17:07 $
8 | */
9 | public interface Constants {
10 |
11 | static final String FIELD_INDEX_SHARDS_NUM = "number_of_shards";
12 |
13 | static final String FIELD_INDEX_REPLICAS_NUM = "number_of_replicas";
14 |
15 | /**
16 | * Index默认的shard数量
17 | */
18 | static final int DEFAULT_INDEX_SHARDS_NUM = 5;
19 |
20 | /**
21 | * Index默认的replicas数量
22 | */
23 | static final int DEFAULT_INDEX_REPLICAS_NUM = 1;
24 |
25 |
26 | /**
27 | * =============================================
28 | * 以下是定义的各类日期格式
29 | * =============================================
30 | */
31 |
32 | static final String PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
33 |
34 | static final String PATTERN_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
35 |
36 | static final String PATTERN_YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
37 |
38 | static final String WHITESPACE = " ";
39 |
40 | static final String EMPTY_STRING = "";
41 |
42 | static final byte BOOLEAN_TRUE_BYTE = 1;
43 |
44 | static final byte BOOLEAN_FALSE_BYTE = 0;
45 | }
46 |
--------------------------------------------------------------------------------
/crabs-common/src/main/java/org/codefamily/crabs/Product.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs;
2 |
3 | public final class Product {
4 |
5 | public static final int MAJOR_VERSION = 1;
6 |
7 | public static final int MINOR_VERSION = 0;
8 |
9 | public static final String NAME = "Crabs";
10 |
11 | public static final String VERSION = MAJOR_VERSION + "." + MINOR_VERSION;
12 |
13 | private Product() {
14 | // to do nothing.
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/crabs-common/src/main/java/org/codefamily/crabs/exception/CrabsError.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.exception;
2 |
3 | public final class CrabsError extends Error {
4 |
5 | private static final long serialVersionUID = 1811695293470214630L;
6 |
7 | public CrabsError() {
8 | // to do nothing.
9 | }
10 |
11 | public CrabsError(final String message) {
12 | this(message, null);
13 | }
14 |
15 | public CrabsError(final Throwable cause) {
16 | this(null, cause);
17 | }
18 |
19 | public CrabsError(final String message, final Throwable cause) {
20 | super(message, cause);
21 | }
22 |
23 | private String message;
24 |
25 | @Override
26 | public final String getMessage() {
27 | if (this.message == null) {
28 | return super.getMessage();
29 | } else {
30 | return this.message;
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/crabs-common/src/main/java/org/codefamily/crabs/exception/CrabsException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.exception;
2 |
3 | /**
4 | * General exception for crabs.
5 | *
6 | * @author zhuchunlai
7 | * @version $Id: CrabsException.java, v1.0 2014/08/01 17:53$
8 | */
9 | public class CrabsException extends Exception {
10 |
11 | public CrabsException(final String message){
12 | super(message);
13 | }
14 |
15 | public CrabsException(final Exception e){
16 | super(e.getMessage(), e);
17 | }
18 |
19 | public CrabsException(final String message, final Throwable cause){
20 | super(message, cause);
21 | }
22 |
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/crabs-common/src/main/java/org/codefamily/crabs/util/ReadonlyList.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.util;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collection;
5 |
6 | /**
7 | * 只读型的List
8 | *
9 | * @param 存储在集合中的元素类型
10 | * @author zhuchunlai
11 | * @version $Id: ReadonlyList.java, v1.0 2014/07/30 17:07 $
12 | */
13 | public abstract class ReadonlyList implements Iterable {
14 |
15 | public static ReadonlyList newInstance(final E... elements) {
16 | if (elements == null) {
17 | throw new IllegalArgumentException("Argument [elements] is null.");
18 | }
19 | return new ReadonlyArrayList(elements.clone());
20 | }
21 |
22 | @SuppressWarnings("unchecked")
23 | public static ReadonlyList newInstance(final Collection elements) {
24 | if (elements == null) {
25 | throw new IllegalArgumentException("Argument [elements] is null.");
26 | }
27 | return new ReadonlyArrayList(elements.toArray((E[]) (new Object[elements.size()])));
28 | }
29 |
30 | protected ReadonlyList() {
31 | // to do nothing.
32 | }
33 |
34 | public abstract boolean isEmpty();
35 |
36 | public abstract int size();
37 |
38 | public abstract E get(int index);
39 |
40 | public abstract Object[] toArray();
41 |
42 | public abstract E[] toArray(E[] array);
43 |
44 | private static final class ReadonlyArrayList extends ReadonlyList {
45 |
46 | ReadonlyArrayList(final E[] elements) {
47 | this.elements = elements;
48 | }
49 |
50 | private final E[] elements;
51 |
52 | @Override
53 | public final boolean isEmpty() {
54 | return this.size() == 0;
55 | }
56 |
57 | @Override
58 | public final int size() {
59 | return this.elements.length;
60 | }
61 |
62 | @Override
63 | public final E get(final int index) {
64 | return this.elements[index];
65 | }
66 |
67 | @Override
68 | public final Object[] toArray() {
69 | return this.elements.clone();
70 | }
71 |
72 | @SuppressWarnings("unchecked")
73 | @Override
74 | public final E[] toArray(final E[] array) {
75 | if (array == null) {
76 | throw new IllegalArgumentException("Argument [array] is null.");
77 | }
78 | final E[] elements = this.elements;
79 | final int elementCount = elements.length;
80 | if (array.length < elementCount) {
81 | return (E[]) Arrays.copyOf(elements, elementCount, array.getClass());
82 | } else {
83 | System.arraycopy(elements, 0, array, 0, elementCount);
84 | for (int i = elementCount; i < array.length; i++) {
85 | array[i] = null;
86 | }
87 | return array;
88 | }
89 | }
90 |
91 | @Override
92 | public final java.util.Iterator iterator() {
93 | return new Iterator();
94 | }
95 |
96 | @Override
97 | public final boolean equals(final Object object) {
98 | if (object != null && object instanceof ReadonlyArrayList) {
99 | if (object == this) {
100 | return true;
101 | }
102 | final Object[] thisElements = this.elements;
103 | final Object[] thatElements = ((ReadonlyArrayList>) object).elements;
104 | if (thisElements.length == thatElements.length) {
105 | for (int i = 0, elementCount = thisElements.length; i < elementCount; i++) {
106 | if (thisElements[i] == null) {
107 | if (thatElements[i] != null) {
108 | return false;
109 | }
110 | } else if (!thisElements[i].equals(thatElements[i])) {
111 | return false;
112 | }
113 | }
114 | return true;
115 | }
116 | }
117 | return false;
118 | }
119 |
120 | private final class Iterator implements java.util.Iterator {
121 |
122 | Iterator() {
123 | this.position = 0;
124 | }
125 |
126 | private int position;
127 |
128 | @Override
129 | public final boolean hasNext() {
130 | return this.position < ReadonlyArrayList.this.elements.length;
131 | }
132 |
133 | @Override
134 | public final E next() {
135 | return ReadonlyArrayList.this.elements[this.position++];
136 | }
137 |
138 | @Override
139 | public final void remove() {
140 | throw new UnsupportedOperationException("List is readonly.");
141 | }
142 |
143 | }
144 |
145 | }
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/crabs-common/src/main/java/org/codefamily/crabs/util/RegularExpressionHelper.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.util;
2 |
3 | public final class RegularExpressionHelper {
4 |
5 | private static final char SINGLE_CHAR = '_';
6 |
7 | private static final char MULTI_CHAR = '%';
8 |
9 | private static final String SINGLE_REGULAR_EXPRESSION = "\\E.*\\Q";
10 |
11 | private static final String MULTI_REGULAR_EXPRESSION = "\\E.\\Q";
12 |
13 | public static String toJavaRegularExpression(final String SQLRegularExpression) {
14 | if (SQLRegularExpression == null) {
15 | throw new IllegalArgumentException("Argument [SQLRegularExpression] is null.");
16 | }
17 | final StringBuilder stringBuilder = new StringBuilder(SQLRegularExpression.length());
18 | // From the JDK doc: \Q and \E protect everything between them
19 | stringBuilder.append("\\Q");
20 | boolean wasSlash = false;
21 | for (int i = 0; i < SQLRegularExpression.length(); i++) {
22 | final char character = SQLRegularExpression.charAt(i);
23 | if (wasSlash) {
24 | stringBuilder.append(character);
25 | wasSlash = false;
26 | } else {
27 | switch (character) {
28 | case SINGLE_CHAR:
29 | stringBuilder.append(MULTI_REGULAR_EXPRESSION);
30 | break;
31 | case MULTI_CHAR:
32 | stringBuilder.append(SINGLE_REGULAR_EXPRESSION);
33 | break;
34 | case '\\':
35 | wasSlash = true;
36 | break;
37 | default:
38 | stringBuilder.append(character);
39 | }
40 | }
41 | }
42 | stringBuilder.append("\\E");
43 | // Found nothing interesting
44 | return stringBuilder.toString();
45 | }
46 |
47 | private RegularExpressionHelper() {
48 | // to do nothing.
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/crabs-common/src/main/java/org/codefamily/crabs/util/StringUtils.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.util;
2 |
3 | /**
4 | * 字符处理工具
5 | *
6 | * @author zhuchunlai
7 | * @version $Id: StringUtils.java, v1.0 2014/07/30 17:07 $
8 | */
9 | public final class StringUtils {
10 |
11 | private StringUtils() {
12 | // nothing to do.
13 | }
14 |
15 | /**
16 | * 判断给定字符串是否是null
或者""
17 | *
18 | * @param value 需要判断的字符串
19 | * @return true
,字符串是null
或者""
;反之则是false
20 | */
21 | public static boolean isNullOrEmptyAfterTrim(final String value) {
22 | return value == null || value.trim().length() == 0;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/crabs-common/src/main/java/org/codefamily/crabs/util/TimeCacheMap.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.util;
2 |
3 | import java.util.HashMap;
4 | import java.util.Iterator;
5 | import java.util.LinkedList;
6 | import java.util.Map;
7 |
8 | public final class TimeCacheMap {
9 | //this default ensures things expire at most 50% past the expiration time
10 | private static final int DEFAULT_NUM_BUCKETS = 3;
11 |
12 | public static interface ExpiredCallback {
13 | public void expire(K key, V val);
14 | }
15 |
16 | private LinkedList> _buckets;
17 |
18 | private final Object _lock = new Object();
19 | private Thread _cleaner;
20 | private ExpiredCallback _callback;
21 |
22 | @SuppressWarnings("unchecked")
23 | public TimeCacheMap(int expirationSecs, int numBuckets, ExpiredCallback callback) {
24 | if (numBuckets < 2) {
25 | throw new IllegalArgumentException("numBuckets must be >= 2");
26 | }
27 | _buckets = new LinkedList>();
28 | for (int i = 0; i < numBuckets; i++) {
29 | _buckets.add(new HashMap());
30 | }
31 |
32 |
33 | _callback = callback;
34 | final long expirationMillis = expirationSecs * 1000L;
35 | final long sleepTime = expirationMillis / (numBuckets - 1);
36 | _cleaner = new Thread(new Runnable() {
37 | public void run() {
38 | try {
39 | while (true) {
40 | Map dead = null;
41 | Thread.sleep(sleepTime);
42 | synchronized (_lock) {
43 | dead = _buckets.removeLast();
44 | _buckets.addFirst(new HashMap());
45 | }
46 | if (_callback != null) {
47 | for (Map.Entry entry : dead.entrySet()) {
48 | _callback.expire(entry.getKey(), entry.getValue());
49 | }
50 | }
51 | }
52 | } catch (InterruptedException e) {
53 | // nothing to do.
54 | }
55 | }
56 | });
57 | _cleaner.setDaemon(true);
58 | _cleaner.start();
59 | }
60 |
61 | public TimeCacheMap(int expirationSecs, ExpiredCallback callback) {
62 | this(expirationSecs, DEFAULT_NUM_BUCKETS, callback);
63 | }
64 |
65 | public TimeCacheMap(int expirationSecs) {
66 | this(expirationSecs, DEFAULT_NUM_BUCKETS);
67 | }
68 |
69 | public TimeCacheMap(int expirationSecs, int numBuckets) {
70 | this(expirationSecs, numBuckets, null);
71 | }
72 |
73 |
74 | public boolean containsKey(K key) {
75 | synchronized (_lock) {
76 | for (HashMap bucket : _buckets) {
77 | if (bucket.containsKey(key)) {
78 | return true;
79 | }
80 | }
81 | return false;
82 | }
83 | }
84 |
85 | public V get(K key) {
86 | synchronized (_lock) {
87 | for (HashMap bucket : _buckets) {
88 | if (bucket.containsKey(key)) {
89 | return bucket.get(key);
90 | }
91 | }
92 | return null;
93 | }
94 | }
95 |
96 | public void put(K key, V value) {
97 | synchronized (_lock) {
98 | Iterator> it = _buckets.iterator();
99 | HashMap bucket = it.next();
100 | bucket.put(key, value);
101 | while (it.hasNext()) {
102 | bucket = it.next();
103 | bucket.remove(key);
104 | }
105 | }
106 | }
107 |
108 | public Object remove(K key) {
109 | synchronized (_lock) {
110 | for (HashMap bucket : _buckets) {
111 | if (bucket.containsKey(key)) {
112 | return bucket.remove(key);
113 | }
114 | }
115 | return null;
116 | }
117 | }
118 |
119 | public int size() {
120 | synchronized (_lock) {
121 | int size = 0;
122 | for (HashMap bucket : _buckets) {
123 | size += bucket.size();
124 | }
125 | return size;
126 | }
127 | }
128 |
129 | public void cleanup() {
130 | _cleaner.interrupt();
131 | }
132 | }
--------------------------------------------------------------------------------
/crabs-core/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | crabs
7 | org.codefamily
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | crabs-core
13 |
14 |
15 |
16 | org.codefamily
17 | crabs-common
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/Document.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core;
2 |
3 | import org.codefamily.crabs.core.exception.UnsupportedDataTypeException;
4 |
5 | import java.sql.Timestamp;
6 | import java.util.Date;
7 |
8 | /**
9 | * 表示存储在elasticsearch type中的单个document
10 | * 说明:Document仅用于插入、更新、删除和按_id检索的场景
11 | *
12 | * @author zhuchunlai
13 | * @version $Id: Document.java, v1.0 2014/07/30 17:16 $
14 | */
15 | public final class Document {
16 |
17 | private final TypeDefinition typeDefinition;
18 |
19 | private final Object[] values;
20 |
21 | Document(final TypeDefinition typeDefinition) {
22 | this.typeDefinition = typeDefinition;
23 | this.values = new Object[this.typeDefinition.getFieldDefinitionCount()];
24 | }
25 |
26 | public final void setValue(final int fieldIndex, final Object value) {
27 | final TypeDefinition.FieldDefinition fieldDefinition = this.typeDefinition.getFieldDefinition(fieldIndex);
28 | this.setValue(fieldDefinition, value);
29 | }
30 |
31 | public final Object getValue(final int fieldIndex) {
32 | final int count = this.typeDefinition.getFieldDefinitionCount();
33 | if (fieldIndex < 0 || fieldIndex >= count) {
34 | throw new IndexOutOfBoundsException("fieldIndex must between 0 and " + count);
35 | }
36 | return this.values[fieldIndex];
37 | }
38 |
39 | public final void setValue(final Identifier identifier, final Object value) {
40 | final TypeDefinition.FieldDefinition fieldDefinition = this.typeDefinition.getFieldDefinition(identifier);
41 | this.setValue(fieldDefinition, value);
42 | }
43 |
44 | public final Object getValue(final Identifier identifier) {
45 | final TypeDefinition.FieldDefinition fieldDefinition = this.typeDefinition.getFieldDefinition(identifier);
46 | return this.values[fieldDefinition.fieldDefinitionIndex];
47 | }
48 |
49 | public final TypeDefinition getTypeDefinition() {
50 | return this.typeDefinition;
51 | }
52 |
53 | public final IndexDefinition getIndexDefinition() {
54 | return this.typeDefinition.getIndexDefinition();
55 | }
56 |
57 | private void setValue(final TypeDefinition.FieldDefinition fieldDefinition, final Object value) {
58 | final int fieldIndex = fieldDefinition.fieldDefinitionIndex;
59 | switch (fieldDefinition.getDataType()) {
60 | case STRING:
61 | this.values[fieldIndex] = (String) value;
62 | break;
63 | case INTEGER:
64 | if (!(value instanceof Number)) {
65 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to int.");
66 | }
67 | this.values[fieldIndex] = ((Number) value).intValue();
68 | break;
69 | case LONG:
70 | if (!(value instanceof Number)) {
71 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to long.");
72 | }
73 | this.values[fieldIndex] = ((Number) value).longValue();
74 | break;
75 | case FLOAT:
76 | if (!(value instanceof Number)) {
77 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to float.");
78 | }
79 | this.values[fieldIndex] = ((Number) value).floatValue();
80 | break;
81 | case DOUBLE:
82 | if (!(value instanceof Number)) {
83 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to double.");
84 | }
85 | this.values[fieldIndex] = ((Number) value).doubleValue();
86 | break;
87 | case BOOLEAN:
88 | if (value instanceof String) {
89 | this.values[fieldIndex] = Boolean.parseBoolean((String) value);
90 | } else if (value instanceof Boolean) {
91 | this.values[fieldIndex] = value;
92 | } else {
93 | throw new ClassCastException("can not cast " + value.getClass().getName() + " to boolean.");
94 | }
95 | break;
96 | case DATE:
97 | if (!(value instanceof Timestamp || value instanceof Date || value instanceof String)) {
98 | throw new ClassCastException("can not cast " + value + " to java.util.Date.");
99 | }
100 | if (value instanceof Timestamp) {
101 | this.values[fieldIndex] = value;
102 | } else if (value instanceof Date) {
103 | this.values[fieldIndex] = new Timestamp(((Date) value).getTime());
104 | } else {
105 | final String timestampString = (String) value;
106 | try {
107 | this.values[fieldIndex] = new Timestamp(
108 | java.sql.Date.valueOf(timestampString).getTime()
109 | );
110 | } catch (IllegalArgumentException e) {
111 | this.values[fieldIndex] = Timestamp.valueOf(timestampString);
112 | }
113 | }
114 | break;
115 | default:
116 | throw new UnsupportedDataTypeException("DataType[" + fieldDefinition.getDataType() + "] is not supported.");
117 | }
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/DocumentFactory.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core;
2 |
3 | /**
4 | * @author zhuchunlai
5 | * @version $Id: DocumentFactory.java, v1.0 2014/08/01 16:11 $
6 | */
7 | public final class DocumentFactory {
8 |
9 | private DocumentFactory() {
10 | // nothing to do.
11 | }
12 |
13 | public static Document createDocument(final TypeDefinition typeDefinition) {
14 | throw new UnsupportedOperationException();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/Identifier.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core;
2 |
3 | import org.codefamily.crabs.util.StringUtils;
4 |
5 | /**
6 | * 标识类,通常用于表示特定类型实例的名称标识,如:TypeDefinition的名称标识
7 | *
8 | * @author zhuchunlai
9 | * @version $Id: Identifier.java, v1.0 2014/07/30 15:36 $
10 | */
11 | public final class Identifier {
12 |
13 | private final String value;
14 |
15 | private final int hashCode;
16 |
17 | public Identifier(final String value) {
18 | if (StringUtils.isNullOrEmptyAfterTrim(value)) {
19 | throw new IllegalArgumentException("Value is required.");
20 | }
21 | this.value = value.intern();
22 | this.hashCode = this.value.hashCode();
23 | }
24 |
25 | @Override
26 | public boolean equals(final Object obj) {
27 | return obj instanceof Identifier
28 | && this.value == ((Identifier) obj).value;
29 | }
30 |
31 | @Override
32 | public final String toString() {
33 | return this.value;
34 | }
35 |
36 | @Override
37 | public final int hashCode() {
38 | return this.hashCode;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/IndexDefinition.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core;
2 |
3 | import static org.codefamily.crabs.Constants.DEFAULT_INDEX_REPLICAS_NUM;
4 | import static org.codefamily.crabs.Constants.DEFAULT_INDEX_SHARDS_NUM;
5 |
6 | /**
7 | * 定义elasticsearch中的Index结构
8 | *
9 | * @author zhuchunlai
10 | * @version $Id: IndexDefinition.java, v1.0 2014/07/30 15:36 $
11 | */
12 | public final class IndexDefinition {
13 |
14 | private final Identifier identifier;
15 |
16 | private final int shardsNum;
17 |
18 | private final int replicasNum;
19 |
20 | /**
21 | * 构造方法,shard数量和replicas数量均采用默认值,具体见{@link org.codefamily.crabs.Constants#DEFAULT_INDEX_SHARDS_NUM}和
22 | * {@link org.codefamily.crabs.Constants#DEFAULT_INDEX_REPLICAS_NUM}
23 | *
24 | * @param identifier index名称标识
25 | */
26 | public IndexDefinition(final Identifier identifier) {
27 | this(identifier, DEFAULT_INDEX_SHARDS_NUM, DEFAULT_INDEX_REPLICAS_NUM);
28 | }
29 |
30 | /**
31 | * 构造方法
32 | *
33 | * @param identifier index名称标识
34 | * @param shardsNum shard的数量,具体见elasticsearch中的概念
35 | * @param replicasNum replicas的数量,具体见elasticsearch中的概念
36 | */
37 | public IndexDefinition(final Identifier identifier, final int shardsNum, final int replicasNum) {
38 | if (identifier == null) {
39 | throw new IllegalArgumentException("Argument[identifier] is required.");
40 | }
41 | if (shardsNum < 1) {
42 | throw new IllegalArgumentException("Value of argument[shardsNum] is must greater than 1.");
43 | }
44 | if (replicasNum < 0) {
45 | throw new IllegalArgumentException("Value of argument[replicasNum] is must greater than 0.");
46 | }
47 | this.identifier = identifier;
48 | this.shardsNum = shardsNum;
49 | this.replicasNum = replicasNum;
50 | }
51 |
52 | public final Identifier getIdentifier() {
53 | return this.identifier;
54 | }
55 |
56 | public final int getShardsNum() {
57 | return this.shardsNum;
58 | }
59 |
60 | public final int getReplicasNum() {
61 | return this.replicasNum;
62 | }
63 |
64 | @Override
65 | public final boolean equals(final Object obj) {
66 | return obj instanceof IndexDefinition
67 | && this.identifier.equals(((IndexDefinition) obj).identifier);
68 | }
69 |
70 | @Override
71 | public final int hashCode() {
72 | return this.identifier.hashCode();
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/FieldAlreadyExistsException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | import org.codefamily.crabs.core.TypeDefinition;
4 |
5 | /**
6 | * Field在指定的Type中已经存在时抛出此异常
7 | *
8 | * @author zhuchunlai
9 | * @version $Id: FieldAlreadyExistException.java, v1.0 2014/07/30 16:24 $
10 | */
11 | public final class FieldAlreadyExistsException extends RuntimeException {
12 |
13 | public FieldAlreadyExistsException(final TypeDefinition.FieldDefinition fieldDefinition) {
14 | this("Field[" + fieldDefinition.getIdentifier() + "] is already exists.");
15 | }
16 |
17 | public FieldAlreadyExistsException(final String message) {
18 | super(message);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/FieldNotExistsException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | import org.codefamily.crabs.core.TypeDefinition;
4 |
5 | /**
6 | * Field在指定的Type中不存在时抛出此异常
7 | *
8 | * @author zhuchunlai
9 | * @version $Id: FieldNotExistException.java, v1.0 2014/07/30 16:24 $
10 | */
11 | public final class FieldNotExistsException extends RuntimeException {
12 |
13 | public FieldNotExistsException(final TypeDefinition.FieldDefinition fieldDefinition) {
14 | this("Field[" + fieldDefinition.getIdentifier() + "] is not exists.");
15 | }
16 |
17 | public FieldNotExistsException(final String message) {
18 | super(message);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/FormatPatternNotFoundException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | /**
4 | * @author zhuchunlai
5 | * @version $Id: NoFormatFoundException.java, v1.0 2014/09/02 11:43 $
6 | */
7 | public final class FormatPatternNotFoundException extends Exception {
8 |
9 | public FormatPatternNotFoundException(final String message) {
10 | super(message);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/IndexAlreadyExistsException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | import org.codefamily.crabs.core.IndexDefinition;
4 |
5 | /**
6 | * @author zhuchunlai
7 | * @version $Id: IndexAlreadyExistsException.java, v1.0 2014/08/04 13:46 $
8 | */
9 | public final class IndexAlreadyExistsException extends RuntimeException {
10 |
11 | public IndexAlreadyExistsException(final IndexDefinition indexDefinition) {
12 | this("Index[" + indexDefinition.getIdentifier().toString() + "] is already exists.");
13 | }
14 |
15 | public IndexAlreadyExistsException(final String message) {
16 | super(message);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/IndexNotExistsException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | import org.codefamily.crabs.core.IndexDefinition;
4 |
5 | /**
6 | * @author zhuchunlai
7 | * @version $Id: IndexNotExistsException.java, v1.0 2014/08/04 13:47 $
8 | */
9 | public final class IndexNotExistsException extends RuntimeException {
10 |
11 | public IndexNotExistsException(final IndexDefinition indexDefinition) {
12 | this("Index[" + indexDefinition.getIdentifier().toString() + "] is not exists.");
13 | }
14 |
15 |
16 | public IndexNotExistsException(final String message) {
17 | super(message);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/PrimaryFieldAlreadyExistsException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | import org.codefamily.crabs.core.TypeDefinition;
4 |
5 | /**
6 | * @author zhuchunlai
7 | * @version $Id: PrimaryFieldAlreadyExistsException.java, v1.0 2014/08/14 16:14 $
8 | */
9 | public final class PrimaryFieldAlreadyExistsException extends RuntimeException {
10 |
11 | public PrimaryFieldAlreadyExistsException(final TypeDefinition typeDefinition) {
12 | super("There's already exists primary field[" +
13 | typeDefinition.getPrimaryFieldDefinition().getIdentifier().toString() +
14 | "] in the Type[" +
15 | typeDefinition.getIndexDefinition().getIdentifier().toString() +
16 | "." + typeDefinition.getIdentifier().toString() +
17 | "]");
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/PrimaryFieldNotFoundException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | import org.codefamily.crabs.core.TypeDefinition;
4 |
5 | /**
6 | * @author zhuchunlai
7 | * @version $Id: PrimaryFieldNotFoundException.java, v1.0 2014/08/14 16:15 $
8 | */
9 | public final class PrimaryFieldNotFoundException extends RuntimeException {
10 |
11 | public PrimaryFieldNotFoundException(final TypeDefinition typeDefinition) {
12 | super("There's no primary field in the Type[" +
13 | typeDefinition.getIndexDefinition().getIdentifier().toString() +
14 | "." + typeDefinition.getIdentifier().toString() +
15 | "].");
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/TypeAlreadyExistsException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | import org.codefamily.crabs.core.TypeDefinition;
4 |
5 | /**
6 | * @author zhuchunlai
7 | * @version $Id: TypeAlreadyExistsException.java, v1.0 2014/08/04 13:44 $
8 | */
9 | public final class TypeAlreadyExistsException extends RuntimeException {
10 |
11 | public TypeAlreadyExistsException(final TypeDefinition typeDefinition) {
12 | this("Type[" + typeDefinition.getIdentifier().toString() + "] is already exists.");
13 | }
14 |
15 | public TypeAlreadyExistsException(final String message) {
16 | super(message);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/TypeNotExistsException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | import org.codefamily.crabs.core.TypeDefinition;
4 |
5 | /**
6 | * @author zhuchunlai
7 | * @version $Id: TypeNotExistsException.java, v1.0 2014/08/04 13:43 $
8 | */
9 | public final class TypeNotExistsException extends RuntimeException {
10 |
11 | public TypeNotExistsException(final TypeDefinition typeDefinition) {
12 | this("Type[" + typeDefinition.getIdentifier() + "] is not exists.");
13 | }
14 |
15 | public TypeNotExistsException(final String message) {
16 | super(message);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/crabs-core/src/main/java/org/codefamily/crabs/core/exception/UnsupportedDataTypeException.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.exception;
2 |
3 | /**
4 | * @author zhuchunlai
5 | * @version $Id: UnsupportedDataTypeException.java, v1.0 2014/08/01 10:23 $
6 | */
7 | public final class UnsupportedDataTypeException extends RuntimeException {
8 |
9 | public UnsupportedDataTypeException(final String message) {
10 | super(message);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/crabs-core/src/test/java/org/codefamily/crabs/core/client/IndexDefinitionManagerTest.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.client;
2 |
3 | import org.codefamily.crabs.common.util.ReadonlyList;
4 | import org.codefamily.crabs.core.Identifier;
5 | import org.codefamily.crabs.core.IndexDefinition;
6 | import org.junit.After;
7 | import org.junit.Before;
8 | import org.junit.Test;
9 |
10 | import java.io.IOException;
11 | import java.util.ArrayList;
12 |
13 | import static org.junit.Assert.*;
14 |
15 | public class IndexDefinitionManagerTest {
16 |
17 | private AdvancedClient advancedClient;
18 |
19 | private IndexDefinitionManager indexDefinitionManager;
20 |
21 | private static final String HOST = "127.0.0.1";
22 | // private static final String HOST = "192.168.213.50";
23 |
24 | @Before
25 | public final void setUp() {
26 | this.advancedClient = new AdvancedClient(
27 | new AdvancedClient.ElasticsearchAddress[]{
28 | new AdvancedClient.ElasticsearchAddress(HOST, 9300)
29 | }
30 | );
31 | this.indexDefinitionManager = new IndexDefinitionManager(this.advancedClient);
32 | }
33 |
34 | @Test
35 | public final void testExists() throws Exception {
36 | final Identifier indexIdentifier = new Identifier("storm_log");
37 | boolean isExists = this.indexDefinitionManager.exists(indexIdentifier);
38 | if (isExists) {
39 | this.indexDefinitionManager.dropIndex(indexIdentifier);
40 | isExists = this.indexDefinitionManager.exists(indexIdentifier);
41 | }
42 | assertFalse(isExists);
43 | }
44 |
45 | @Test
46 | public final void testCreateIndex() throws Exception {
47 | final Identifier identifier = new Identifier("storm_log");
48 | final IndexDefinition indexDefinition = new IndexDefinition(identifier, 5, 1);
49 | if (this.indexDefinitionManager.exists(identifier)) {
50 | this.indexDefinitionManager.dropIndex(identifier);
51 | }
52 | this.indexDefinitionManager.createIndex(indexDefinition);
53 | assertTrue(this.indexDefinitionManager.exists(identifier));
54 | }
55 |
56 | @Test
57 | public final void testDropIndex() throws Exception {
58 | final Identifier identifier = new Identifier("storm_log");
59 | final IndexDefinition indexDefinition = new IndexDefinition(identifier, 5, 1);
60 | if (!this.indexDefinitionManager.exists(identifier)) {
61 | this.indexDefinitionManager.createIndex(indexDefinition);
62 | }
63 | this.indexDefinitionManager.dropIndex(identifier);
64 | assertFalse(this.indexDefinitionManager.exists(identifier));
65 | }
66 |
67 | @Test
68 | public final void testGetAllIndices() throws Exception {
69 | final ReadonlyList expected = ReadonlyList.newInstance(
70 | new ArrayList() {{
71 | add(new IndexDefinition(new Identifier("test"), 1, 1));
72 | add(new IndexDefinition(new Identifier("storm_log"), 5, 1));
73 | }}
74 | );
75 | for (IndexDefinition indexDefinition : expected) {
76 | if (!this.indexDefinitionManager.exists(indexDefinition.getIdentifier())) {
77 | this.indexDefinitionManager.createIndex(indexDefinition);
78 | }
79 | }
80 | final ReadonlyList actual = this.indexDefinitionManager.getAllIndices();
81 | assertEquals(expected, actual);
82 | }
83 |
84 | @Test
85 | public final void testGetIndex() throws Exception {
86 | final Identifier indexIdentifier = new Identifier("storm_log");
87 | if (!this.indexDefinitionManager.exists(indexIdentifier)) {
88 | this.indexDefinitionManager.createIndex(new IndexDefinition(indexIdentifier));
89 | }
90 | this.indexDefinitionManager.getIndexDefinition(indexIdentifier);
91 | }
92 |
93 | @After
94 | public final void tearDown() throws IOException {
95 | this.advancedClient.close();
96 | }
97 | }
--------------------------------------------------------------------------------
/crabs-core/src/test/java/org/codefamily/crabs/core/client/TypeDefinitionManagerTest.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.core.client;
2 |
3 | import org.codefamily.crabs.common.util.ReadonlyList;
4 | import org.codefamily.crabs.core.Identifier;
5 | import org.codefamily.crabs.core.IndexDefinition;
6 | import org.codefamily.crabs.core.TypeDefinition;
7 | import org.junit.After;
8 | import org.junit.Before;
9 | import org.junit.Test;
10 |
11 | import static org.junit.Assert.*;
12 | import static org.codefamily.crabs.Constants.PATTERN_YYYY_MM_DD_HH_MM_SS;
13 |
14 | public class TypeDefinitionManagerTest {
15 |
16 | private AdvancedClient advancedClient;
17 |
18 | private TypeDefinitionManager typeDefinitionManager;
19 |
20 | private IndexDefinition indexDefinition;
21 |
22 | private static final String HOST = "127.0.0.1";
23 | // private static final String HOST = "192.168.213.50";
24 |
25 | @Before
26 | public void setUp() throws Exception {
27 | this.advancedClient = new AdvancedClient(
28 | new AdvancedClient.ElasticsearchAddress[]{
29 | new AdvancedClient.ElasticsearchAddress(HOST, 9300)
30 | }
31 | );
32 | this.typeDefinitionManager = new TypeDefinitionManager(this.advancedClient);
33 | this.indexDefinition = new IndexDefinition(new Identifier("storm_log"), 5, 1);
34 | final IndexDefinitionManager indexDefinitionManager = new IndexDefinitionManager(this.advancedClient);
35 | if (!indexDefinitionManager.exists(this.indexDefinition.getIdentifier())) {
36 | indexDefinitionManager.createIndex(this.indexDefinition);
37 | }
38 | }
39 |
40 | @After
41 | public void tearDown() throws Exception {
42 | this.advancedClient.close();
43 | }
44 |
45 | @Test
46 | public void testCreateType() throws Exception {
47 | final TypeDefinition typeDefinition = new TypeDefinition(
48 | new IndexDefinition(new Identifier("storm_log")),
49 | new Identifier("BJHC_16779"),
50 | true,
51 | false
52 | );
53 | typeDefinition.defineStringField(new Identifier("_string"));
54 | typeDefinition.defineIntegerField(new Identifier("_integer")).asPrimaryField();
55 | typeDefinition.defineLongField(new Identifier("_long"));
56 | typeDefinition.defineFloatField(new Identifier("_float"));
57 | typeDefinition.defineDoubleField(new Identifier("_double"));
58 | typeDefinition.defineBooleanField(new Identifier("_boolean"));
59 | typeDefinition.defineDateField(new Identifier("_date"), PATTERN_YYYY_MM_DD_HH_MM_SS);
60 | typeDefinition.publish();
61 | if (this.typeDefinitionManager.exists(typeDefinition)) {
62 | this.typeDefinitionManager.dropType(typeDefinition);
63 | }
64 | this.typeDefinitionManager.createType(typeDefinition);
65 | assertTrue(this.typeDefinitionManager.exists(typeDefinition));
66 | }
67 |
68 | @Test
69 | public void testAlterType() throws Exception {
70 |
71 | }
72 |
73 | @Test
74 | public void testDropType() throws Exception {
75 | final TypeDefinition typeDefinition = new TypeDefinition(
76 | this.indexDefinition,
77 | new Identifier("BJHC_16779")
78 | );
79 | typeDefinition.defineStringField(new Identifier("_string"));
80 | typeDefinition.defineIntegerField(new Identifier("_integer")).asPrimaryField();
81 | typeDefinition.defineLongField(new Identifier("_long"));
82 | typeDefinition.defineFloatField(new Identifier("_float"));
83 | typeDefinition.defineDoubleField(new Identifier("_double"));
84 | typeDefinition.defineBooleanField(new Identifier("_boolean"));
85 | typeDefinition.defineDateField(new Identifier("_date"), PATTERN_YYYY_MM_DD_HH_MM_SS);
86 | typeDefinition.publish();
87 | if (!this.typeDefinitionManager.exists(typeDefinition)) {
88 | this.typeDefinitionManager.createType(typeDefinition);
89 | }
90 | this.typeDefinitionManager.dropType(typeDefinition);
91 | assertFalse(this.typeDefinitionManager.exists(typeDefinition));
92 | }
93 |
94 | @Test
95 | public void testGetTypeDefinitions() throws Exception {
96 | final TypeDefinition bjhc16779 = new TypeDefinition(this.indexDefinition, new Identifier("BJHC_16779"), true, false);
97 | bjhc16779.defineStringField(new Identifier("_string"));
98 | bjhc16779.defineIntegerField(new Identifier("_integer")).asPrimaryField();
99 | bjhc16779.defineLongField(new Identifier("_long"));
100 | bjhc16779.defineFloatField(new Identifier("_float"));
101 | bjhc16779.defineDoubleField(new Identifier("_double"));
102 | bjhc16779.defineBooleanField(new Identifier("_boolean"));
103 | bjhc16779.defineDateField(new Identifier("_date"), PATTERN_YYYY_MM_DD_HH_MM_SS);
104 | bjhc16779.publish();
105 | final ReadonlyList expected = ReadonlyList.newInstance(bjhc16779);
106 | final ReadonlyList actual = this.typeDefinitionManager.getTypeDefinitions(new Identifier("storm_log"));
107 | assertEquals(expected, actual);
108 | }
109 |
110 | @Test
111 | public void testGetTypeDefinition() throws Exception {
112 | final Identifier typeIdentifier = new Identifier("BJHC_16779");
113 | final TypeDefinition expected = new TypeDefinition(this.indexDefinition, typeIdentifier, true, false);
114 | expected.defineStringField(new Identifier("_string"));
115 | expected.defineIntegerField(new Identifier("_integer")).asPrimaryField();
116 | expected.defineLongField(new Identifier("_long"));
117 | expected.defineFloatField(new Identifier("_float"));
118 | expected.defineDoubleField(new Identifier("_double"));
119 | expected.defineBooleanField(new Identifier("_boolean"));
120 | expected.defineDateField(new Identifier("_date"), PATTERN_YYYY_MM_DD_HH_MM_SS);
121 | expected.publish();
122 | if (!this.typeDefinitionManager.exists(expected)) {
123 | this.typeDefinitionManager.createType(expected);
124 | }
125 | final TypeDefinition actual = this.typeDefinitionManager.getTypeDefinition(indexDefinition, typeIdentifier);
126 | assertEquals(expected, actual);
127 | }
128 |
129 | @Test
130 | public void testExists() throws Exception {
131 |
132 | }
133 | }
--------------------------------------------------------------------------------
/crabs-jdbc/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | crabs
7 | org.codefamily
8 | 1.0.0
9 |
10 | 4.0.0
11 |
12 | crabs-jdbc
13 |
14 |
15 |
16 | org.codefamily
17 | crabs-core
18 |
19 |
20 |
21 |
22 |
23 |
24 | org.apache.maven.plugins
25 | maven-assembly-plugin
26 |
27 | false
28 |
29 | jar-with-dependencies
30 |
31 |
32 |
33 |
34 | make-assembly
35 | package
36 |
37 | single
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/DataSource.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc;
2 |
3 | import org.codefamily.crabs.core.client.AdvancedClient.ElasticsearchAddress;
4 |
5 | import java.io.PrintWriter;
6 | import java.sql.SQLException;
7 | import java.sql.SQLFeatureNotSupportedException;
8 | import java.util.Properties;
9 | import java.util.logging.Logger;
10 |
11 | public final class DataSource implements javax.sql.DataSource {
12 |
13 | DataSource(final ElasticsearchAddress[] addresses,
14 | final String database,
15 | final String username,
16 | final String password) {
17 | if (addresses == null || addresses.length == 0) {
18 | throw new IllegalArgumentException("Argument[addresses] is null.");
19 | }
20 | final int length = addresses.length;
21 | final ElasticsearchAddress[] finallyAddresses = new ElasticsearchAddress[length];
22 | ElasticsearchAddress address;
23 | for (int index = 0; index < length; index++) {
24 | address = addresses[index];
25 | if (address == null) {
26 | throw new IllegalArgumentException("Argument[addresses[" + index + "]] is null.");
27 | }
28 | finallyAddresses[index] = address;
29 | }
30 | this.addresses = finallyAddresses;
31 | this.database = database;
32 | this.username = username;
33 | this.password = password;
34 | }
35 |
36 | private final ElasticsearchAddress[] addresses;
37 |
38 | private final String database;
39 |
40 | private final String username;
41 |
42 | private final String password;
43 |
44 | private PrintWriter logWriter;
45 |
46 | private int loginTimeout;
47 |
48 | @Override
49 | public final PrintWriter getLogWriter() throws SQLException {
50 | return this.logWriter;
51 | }
52 |
53 | @Override
54 | public final int getLoginTimeout() throws SQLException {
55 | return this.loginTimeout;
56 | }
57 |
58 | @Override
59 | public Logger getParentLogger() throws SQLFeatureNotSupportedException {
60 | throw new SQLFeatureNotSupportedException();
61 | }
62 |
63 | @Override
64 | public final Connection getConnection() throws SQLException {
65 | return this.getConnection(this.username, this.password);
66 | }
67 |
68 | @Override
69 | public final Connection getConnection(final String username,
70 | final String password) throws SQLException {
71 | if (username == null) {
72 | throw new IllegalArgumentException("Argument[username] is null.");
73 | }
74 | if (password == null) {
75 | throw new IllegalArgumentException("Argument[password] is null.");
76 | }
77 | final StringBuilder URLBuilder = new StringBuilder();
78 | URLBuilder.append(Protocol.JDBC_PREFIX);
79 | URLBuilder.append(':');
80 | String delimiter = "";
81 | for (int index = 0, length = this.addresses.length; index < length; index++) {
82 | URLBuilder.append(delimiter).append(this.addresses[index]);
83 | delimiter = ",";
84 | }
85 | URLBuilder.append("/").append(this.database);
86 | return new Connection(URLBuilder.toString(), new Properties());
87 | }
88 |
89 | @Override
90 | public final boolean isWrapperFor(final Class> iface) throws SQLException {
91 | if (iface == null) {
92 | throw new IllegalArgumentException("Argument [iface] is null.");
93 | }
94 | return iface.isInstance(this);
95 | }
96 |
97 | @Override
98 | public final void setLogWriter(final PrintWriter logWriter)
99 | throws SQLException {
100 | this.logWriter = logWriter;
101 | }
102 |
103 | @Override
104 | public final void setLoginTimeout(final int loginTimeout)
105 | throws SQLException {
106 | this.loginTimeout = loginTimeout;
107 | }
108 |
109 | @Override
110 | @SuppressWarnings("unchecked")
111 | public final T unwrap(final Class iface) throws SQLException {
112 | if (iface == null) {
113 | throw new IllegalArgumentException("Argument [iface] is null.");
114 | }
115 | if (!iface.isInstance(this)) {
116 | throw new SQLException(this.getClass().getName()
117 | + " not unwrappable from " + iface.getName());
118 | }
119 | return (T) this;
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/DataSourceFactory.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc;
2 |
3 | import org.codefamily.crabs.core.client.AdvancedClient.ElasticsearchAddress;
4 |
5 | import javax.naming.Context;
6 | import javax.naming.Name;
7 | import javax.naming.RefAddr;
8 | import javax.naming.Reference;
9 | import javax.naming.spi.ObjectFactory;
10 | import java.util.Hashtable;
11 |
12 | public final class DataSourceFactory implements ObjectFactory {
13 |
14 | private final static String DATA_SOURCE_CLASS_NAME = DataSource.class
15 | .getName();
16 |
17 | public DataSourceFactory() {
18 | // to do nothing.
19 | }
20 |
21 | @Override
22 | public final Object getObjectInstance(final Object object,
23 | final Name name,
24 | final Context context,
25 | final Hashtable, ?> environment) throws Exception {
26 | final Reference reference = (Reference) object;
27 | final String className = reference.getClassName();
28 | if ((className != null) && className.equals(DATA_SOURCE_CLASS_NAME)) {
29 | final String serverAddresses = getReferenceValue(reference, "serverAddresses");
30 | final String databaseName = getReferenceValue(reference, "databaseName");
31 | final String userName = getReferenceValue(reference, "user");
32 | final String password = getReferenceValue(reference, "password");
33 |
34 | return new DataSource(
35 | ElasticsearchAddress.toElasticsearchAddresses(serverAddresses),
36 | databaseName,
37 | userName,
38 | password
39 | );
40 | } else {
41 | return null;
42 | }
43 | }
44 |
45 | private static String getReferenceValue(final Reference reference,
46 | final String referenceName) {
47 | final RefAddr refAddr = reference.get(referenceName);
48 | return refAddr != null ? (String) refAddr.getContent() : null;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/Driver.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc;
2 |
3 | import java.sql.DriverManager;
4 | import java.sql.DriverPropertyInfo;
5 | import java.sql.SQLException;
6 | import java.sql.SQLFeatureNotSupportedException;
7 | import java.util.Properties;
8 | import java.util.logging.Logger;
9 |
10 | public final class Driver implements java.sql.Driver {
11 |
12 | public static final int MAJOR_VERSION = 1;
13 |
14 | public static final int MINOR_VERSION = 0;
15 |
16 | public static final String NAME = Driver.class.getName();
17 |
18 | public static final String VERSION = MAJOR_VERSION + "." + MINOR_VERSION;
19 |
20 | private static final DriverPropertyInfo[] EMPTY_DRIVER_PROPERTIES = new DriverPropertyInfo[0];
21 |
22 | static {
23 | try {
24 | DriverManager.registerDriver(new Driver());
25 | } catch (SQLException e) {
26 | throw new IllegalStateException("Unable to register driver[" + NAME + "]: " + e.getMessage());
27 | }
28 | }
29 |
30 | public Driver() {
31 | // to do nothing.
32 | }
33 |
34 | public final String getName() {
35 | return NAME;
36 | }
37 |
38 | @Override
39 | public final int getMajorVersion() {
40 | return MAJOR_VERSION;
41 | }
42 |
43 | @Override
44 | public final int getMinorVersion() {
45 | return MINOR_VERSION;
46 | }
47 |
48 | @Override
49 | public final DriverPropertyInfo[] getPropertyInfo(final String URL,
50 | final Properties properties) throws SQLException {
51 | return EMPTY_DRIVER_PROPERTIES;
52 | }
53 |
54 | @Override
55 | public final boolean acceptsURL(final String URL) throws SQLException {
56 | if (URL == null) {
57 | throw new IllegalArgumentException("Argument [URL] is null.");
58 | }
59 | return URL.startsWith(Protocol.JDBC_PREFIX);
60 | }
61 |
62 | @Override
63 | public final Connection connect(final String URL,
64 | Properties properties) throws SQLException {
65 | if (!acceptsURL(URL)) {
66 | throw new SQLException("Driver does not understand the given URL, it must be start with '"
67 | + Protocol.JDBC_PREFIX + "'");
68 | }
69 | if (properties == null) {
70 | properties = new Properties();
71 | }
72 | properties.setProperty(
73 | Protocol.PROPERTY_ENTRY$DRIVER_NAME.identifier,
74 | this.getClass().getName()
75 | );
76 | properties.setProperty(
77 | Protocol.PROPERTY_ENTRY$DRIVER_MAJOR_VERSION.identifier,
78 | Integer.toString(getMajorVersion())
79 | );
80 | properties.setProperty(
81 | Protocol.PROPERTY_ENTRY$DRIVER_MINOR_VERSION.identifier,
82 | Integer.toString(getMinorVersion())
83 | );
84 | return new Connection(URL, properties);
85 | }
86 |
87 | @Override
88 | public final boolean jdbcCompliant() {
89 | return false;
90 | }
91 |
92 | @Override
93 | public final Logger getParentLogger() throws SQLFeatureNotSupportedException {
94 | throw new SQLFeatureNotSupportedException();
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/StatementCache.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler;
2 |
3 | import org.codefamily.crabs.jdbc.lang.Statement;
4 |
5 | import java.lang.ref.ReferenceQueue;
6 | import java.lang.ref.SoftReference;
7 | import java.util.HashMap;
8 |
9 | /**
10 | * SQL语句缓存
11 | *
12 | * @author zhuchunlai
13 | * @version $Id: StatementCache.java, v1.0 2013/08/26 10:06 $
14 | */
15 | public final class StatementCache {
16 |
17 | public StatementCache() {
18 | this.statementMap = new HashMap();
19 | this.referenceQueue = new ReferenceQueue();
20 | this.cleaner = new Cleaner();
21 | }
22 |
23 | private final HashMap statementMap;
24 |
25 | private final ReferenceQueue referenceQueue;
26 |
27 | private final Cleaner cleaner;
28 |
29 | public final Statement getStatement(final String statementString) {
30 | if (statementString == null) {
31 | throw new IllegalArgumentException("Argument [statementString] is null.");
32 | }
33 | final StatementReference reference = this.statementMap.get(statementString);
34 | return reference == null ? null : reference.get();
35 | }
36 |
37 | public final void putStatement(final String statementString,
38 | final Statement statement) {
39 | if (statementString == null) {
40 | throw new IllegalArgumentException("Argument [statementString] is null.");
41 | }
42 | if (statement == null) {
43 | throw new IllegalArgumentException("Argument [statement] is null.");
44 | }
45 | if (!this.statementMap.containsKey(statementString)) {
46 | synchronized (this.statementMap) {
47 | if (!this.statementMap.containsKey(statementString)) {
48 | this.statementMap.put(
49 | statementString,
50 | new StatementReference(
51 | statementString,
52 | statement,
53 | this.referenceQueue
54 | )
55 | );
56 | }
57 | }
58 | }
59 | }
60 |
61 | public final void start() {
62 | this.cleaner.start();
63 | }
64 |
65 | public final void stop() {
66 | this.cleaner.setRunSwitch(false);
67 | this.cleaner.interrupt();
68 | }
69 |
70 | private final class Cleaner extends Thread {
71 |
72 | Cleaner() {
73 | super("Statement cache cleaner");
74 | this.setDaemon(true);
75 | this.runSwitch = true;
76 | }
77 |
78 | private volatile boolean runSwitch;
79 |
80 | final void setRunSwitch(final boolean runSwitch) {
81 | this.runSwitch = runSwitch;
82 | }
83 |
84 | @Override
85 | public final void run() {
86 | final HashMap statementMap = StatementCache.this.statementMap;
87 | final ReferenceQueue referenceQueue = StatementCache.this.referenceQueue;
88 | StatementReference statementReference;
89 | while (this.runSwitch
90 | && (statementReference = (StatementReference) referenceQueue.poll()) != null) {
91 | synchronized (statementMap) {
92 | statementMap.remove(statementReference.cacheKey);
93 | }
94 | }
95 | }
96 | }
97 |
98 | private static final class StatementReference extends SoftReference {
99 |
100 | StatementReference(final String cacheKey, final Statement statement,
101 | final ReferenceQueue super Statement> referenceQueue) {
102 | super(statement, referenceQueue);
103 | this.cacheKey = cacheKey;
104 | }
105 |
106 | final String cacheKey;
107 |
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/StatementFactory.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler;
2 |
3 | import org.codefamily.crabs.util.ExtensionClassCollector;
4 | import org.codefamily.crabs.util.ReadonlyList;
5 | import org.codefamily.crabs.jdbc.lang.Clause;
6 | import org.codefamily.crabs.jdbc.lang.Statement;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.sql.SQLException;
11 | import java.util.HashMap;
12 | import java.util.Iterator;
13 | import java.util.List;
14 |
15 | public final class StatementFactory {
16 |
17 | private static final Logger LOGGER = LoggerFactory.getLogger(StatementFactory.class);
18 |
19 | private static final HashMap, StatementAdapter> STATEMENT_ADAPTER_MAP
20 | = new HashMap, StatementAdapter>();
21 |
22 | public static void recollectStatementAdapters() {
23 | synchronized (StatementFactory.class) {
24 | final Iterator> adapterClassIterator
25 | = ExtensionClassCollector.getExtensionClasses(StatementAdapter.class);
26 | while (adapterClassIterator.hasNext()) {
27 | final Class extends StatementAdapter> adapterClass = adapterClassIterator
28 | .next();
29 | try {
30 | final StatementAdapter statementAdapter = adapterClass.newInstance();
31 | final Class extends Clause> key = statementAdapter.markClauseClass;
32 | final StatementAdapter existedStatementAdapter = STATEMENT_ADAPTER_MAP.get(key);
33 | if (existedStatementAdapter != null) {
34 | if (existedStatementAdapter.getClass() != adapterClass) {
35 | throw new RuntimeException("Statement adapter conflicted." + adapterClass.getName());
36 | }
37 | continue;
38 | }
39 | STATEMENT_ADAPTER_MAP.put(key, statementAdapter);
40 | } catch (Throwable exception) {
41 | LOGGER.error("Can not register statement adapter.", exception);
42 | }
43 | }
44 | }
45 | }
46 |
47 | static Statement toStatement(final List clauseList) throws SQLException {
48 | final ReadonlyList readonlyClauseList = ReadonlyList.newInstance(clauseList);
49 | for (int i = 0, clauseCount = readonlyClauseList.size(); i < clauseCount; i++) {
50 | final StatementAdapter statementAdapter = STATEMENT_ADAPTER_MAP.get(readonlyClauseList.get(i).getClass());
51 | if (statementAdapter != null) {
52 | return statementAdapter.adaptStatement(readonlyClauseList);
53 | }
54 | }
55 | return null;
56 | }
57 |
58 | static {
59 | recollectStatementAdapters();
60 | }
61 |
62 | private StatementFactory() {
63 | // to do nothing.
64 | }
65 |
66 | public static abstract class StatementAdapter {
67 |
68 | protected StatementAdapter(final Class extends Clause> markClauseClass) {
69 | if (markClauseClass == null) {
70 | throw new IllegalArgumentException("Argument [markClauseClass] is null.");
71 | }
72 | this.markClauseClass = markClauseClass;
73 | }
74 |
75 | final Class extends Clause> markClauseClass;
76 |
77 | protected abstract Statement adaptStatement(ReadonlyList clauseList) throws SQLException;
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/FromClauseGrammarAnalyzer.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler.extension.clause;
2 |
3 | import org.codefamily.crabs.jdbc.lang.Clause.TableDeclare;
4 | import org.codefamily.crabs.jdbc.lang.extension.clause.FromClause;
5 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer;
6 |
7 | import java.sql.SQLException;
8 | import java.util.ArrayList;
9 |
10 | public final class FromClauseGrammarAnalyzer extends ClauseGrammarAnalyzer {
11 |
12 | public FromClauseGrammarAnalyzer() {
13 | super(FromClause.PREFIX_KEYWORD_LIST);
14 | }
15 |
16 | @Override
17 | protected final FromClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException {
18 | return new FromClause(analyzeTableDeclares(context));
19 | }
20 |
21 | private static TableDeclare[] analyzeTableDeclares(final GrammarAnalyzeContext context) throws SQLException {
22 | final ArrayList tableDeclareList = new ArrayList();
23 | for (; ; ) {
24 | final int currentTokenStartPosition = context.currentTokenStartPosition();
25 | final TableDeclare tableDeclare = analyzeTableDeclare(context);
26 | if (tableDeclare == null) {
27 | throw newSQLException(context, "Expect a table declare.", currentTokenStartPosition);
28 | }
29 | tableDeclareList.add(tableDeclare);
30 | if (context.currentTokenType() == TokenType.SYMBOL
31 | && context.currentTokenToSymbol() == ',') {
32 | /*context.toNextToken();
33 | continue;*/
34 | // TODO 暂不支持多表关联
35 | throw newSQLException(context, "Now only support a single table declare.", currentTokenStartPosition);
36 | }
37 | break;
38 | }
39 | return tableDeclareList.toArray(new TableDeclare[tableDeclareList.size()]);
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/GroupByClauseGrammarAnalyzer.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler.extension.clause;
2 |
3 | import org.codefamily.crabs.jdbc.lang.Expression;
4 | import org.codefamily.crabs.jdbc.lang.extension.clause.GroupByClause;
5 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer;
6 |
7 | import java.sql.SQLException;
8 | import java.util.ArrayList;
9 |
10 | public final class GroupByClauseGrammarAnalyzer extends ClauseGrammarAnalyzer {
11 |
12 | public GroupByClauseGrammarAnalyzer() {
13 | super(GroupByClause.PREFIX_KEYWORD_LIST);
14 | }
15 |
16 | @Override
17 | protected final GroupByClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException {
18 | final ArrayList groupByExpressionList = context.getExpressionList();
19 | final int startListIndex = groupByExpressionList.size();
20 | for (; ; ) {
21 | final int currentTokenStartPosition = context
22 | .currentTokenStartPosition();
23 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context);
24 | if (expression != null) {
25 | groupByExpressionList.add(expression);
26 | if (context.currentTokenType() == TokenType.SYMBOL
27 | && context.currentTokenToSymbol() == ',') {
28 | context.toNextToken();
29 | continue;
30 | }
31 | break;
32 | } else {
33 | throw newSQLException(context, "Expect an expression.", currentTokenStartPosition);
34 | }
35 | }
36 | return new GroupByClause(expressionsListToArray(groupByExpressionList, startListIndex));
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/HavingClauseGrammarAnalyzer.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler.extension.clause;
2 |
3 | import org.codefamily.crabs.jdbc.lang.Expression;
4 | import org.codefamily.crabs.jdbc.lang.extension.clause.HavingClause;
5 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer;
6 |
7 | import java.sql.SQLException;
8 |
9 | public final class HavingClauseGrammarAnalyzer extends ClauseGrammarAnalyzer {
10 |
11 | public HavingClauseGrammarAnalyzer() {
12 | super(HavingClause.PREFIX_KEYWORD_LIST);
13 | }
14 |
15 | @Override
16 | protected final HavingClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException {
17 | final int currentTokenStartPosition = context.currentTokenStartPosition();
18 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context);
19 | if (expression == null) {
20 | throw newSQLException(context, "Expect an expression.", currentTokenStartPosition);
21 | }
22 | return new HavingClause(expression);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/LimitClauseGrammarAnalyzer.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler.extension.clause;
2 |
3 | import org.codefamily.crabs.jdbc.lang.Expression;
4 | import org.codefamily.crabs.jdbc.lang.expression.Constant;
5 | import org.codefamily.crabs.jdbc.lang.extension.clause.LimitClause;
6 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer;
7 |
8 | import java.sql.SQLException;
9 |
10 | public final class LimitClauseGrammarAnalyzer extends ClauseGrammarAnalyzer {
11 |
12 | public LimitClauseGrammarAnalyzer() {
13 | super(LimitClause.PREFIX_KEYWORD_LIST);
14 | }
15 |
16 | @Override
17 | protected final LimitClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException {
18 | final Expression offset, rowCount;
19 | switch (context.currentTokenType()) {
20 | case NUMBERS:
21 | offset = this.tryToParseConstant(context);
22 | context.toNextToken();
23 | if (context.currentTokenType() == TokenType.SYMBOL
24 | && context.currentTokenToSymbol() == ',') {
25 | context.toNextToken();
26 | switch (context.currentTokenType()) {
27 | case NUMBERS:
28 | rowCount = this.tryToParseConstant(context);
29 | context.toNextToken();
30 | return new LimitClause(offset, rowCount);
31 | case SYMBOL:
32 | if (context.currentTokenToSymbol() == '?') {
33 | rowCount = context.newArgument();
34 | context.toNextToken();
35 | return new LimitClause(offset, rowCount);
36 | }
37 | throw newSQLException(
38 | context,
39 | "Expect NUMBERS or '?'",
40 | context.currentTokenStartPosition()
41 | );
42 | default:
43 | throw newSQLException(
44 | context,
45 | "Expect NUMBERS or '?'",
46 | context.currentTokenStartPosition()
47 | );
48 | }
49 | }
50 | throw newSQLException(context, "Expect symbol ','", context.currentTokenStartPosition());
51 | case SYMBOL:
52 | if (context.currentTokenToSymbol() == '?') {
53 | offset = context.newArgument();
54 | context.toNextToken();
55 | if (context.currentTokenType() == TokenType.SYMBOL
56 | && context.currentTokenToSymbol() == ',') {
57 | context.toNextToken();
58 | switch (context.currentTokenType()) {
59 | case NUMBERS:
60 | rowCount = this.tryToParseConstant(context);
61 | context.toNextToken();
62 | return new LimitClause(offset, rowCount);
63 | case SYMBOL:
64 | if (context.currentTokenToSymbol() == '?') {
65 | rowCount = context.newArgument();
66 | context.toNextToken();
67 | return new LimitClause(offset, rowCount);
68 | }
69 | throw newSQLException(
70 | context,
71 | "Expect NUMBERS or '?'",
72 | context.currentTokenStartPosition()
73 | );
74 | default:
75 | throw newSQLException(
76 | context,
77 | "Expect NUMBERS or '?'",
78 | context.currentTokenStartPosition()
79 | );
80 | }
81 | }
82 | }
83 | throw newSQLException(context, "Expect NUMBERS or '?'", context.currentTokenStartPosition());
84 | default:
85 | throw newSQLException(context, "Expect NUMBERS or '?'", context.currentTokenStartPosition());
86 | }
87 | }
88 |
89 | private Constant tryToParseConstant(final GrammarAnalyzeContext context) throws SQLException {
90 | final String tokenValue = context.currentTokenToString();
91 | final long value = Long.parseLong(tokenValue);
92 | if (value > Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
93 | return new Constant((int) value);
94 | } else {
95 | throw newSQLException(
96 | context,
97 | "Unsupported number."
98 | + tokenValue, context.currentTokenStartPosition()
99 | );
100 | }
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/OrderByClauseGrammarAnalyzer.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler.extension.clause;
2 |
3 | import org.codefamily.crabs.jdbc.lang.Expression;
4 | import org.codefamily.crabs.jdbc.lang.Keyword;
5 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword;
6 | import org.codefamily.crabs.jdbc.lang.extension.clause.OrderByClause;
7 | import org.codefamily.crabs.jdbc.lang.extension.clause.OrderByClause.OrderSpecification;
8 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer;
9 |
10 | import java.sql.SQLException;
11 | import java.util.ArrayList;
12 |
13 | public final class OrderByClauseGrammarAnalyzer extends ClauseGrammarAnalyzer {
14 |
15 | public OrderByClauseGrammarAnalyzer() {
16 | super(OrderByClause.PREFIX_KEYWORD_LIST);
17 | }
18 |
19 | @Override
20 | protected final OrderByClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException {
21 | return new OrderByClause(analyzeOrderSpecifications(context));
22 | }
23 |
24 | private static OrderSpecification[] analyzeOrderSpecifications(final GrammarAnalyzeContext context)
25 | throws SQLException {
26 | final ArrayList orderSpecificationList = new ArrayList(1);
27 | for (; ; ) {
28 | final int currentTokenStartPosition = context.currentTokenStartPosition();
29 | final OrderSpecification orderSpecification = analyzeOrderSpecification(context);
30 | if (orderSpecification == null) {
31 | throw newSQLException(
32 | context,
33 | "Expect a order specification.",
34 | currentTokenStartPosition
35 | );
36 | }
37 | orderSpecificationList.add(orderSpecification);
38 | if (context.currentTokenType() == TokenType.SYMBOL && context.currentTokenToSymbol() == ',') {
39 | context.toNextToken();
40 | continue;
41 | }
42 | break;
43 | }
44 | return orderSpecificationList.toArray(new OrderSpecification[orderSpecificationList.size()]);
45 | }
46 |
47 | private static OrderSpecification analyzeOrderSpecification(final GrammarAnalyzeContext context)
48 | throws SQLException {
49 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context);
50 | if (expression == null) {
51 | return null;
52 | }
53 | final boolean ascendingOrder;
54 | final boolean nullsFirst;
55 | if (context.currentTokenType() == TokenType.KEYWORD) {
56 | Keyword keyword = context.currentTokenToKeyword();
57 | if (keyword == ReservedKeyword.ASC) {
58 | ascendingOrder = true;
59 | context.toNextToken();
60 | } else if (keyword == ReservedKeyword.DESC) {
61 | ascendingOrder = false;
62 | context.toNextToken();
63 | } else {
64 | ascendingOrder = true;
65 | }
66 | } else {
67 | ascendingOrder = true;
68 | }
69 | return new OrderSpecification(expression, ascendingOrder);
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/SelectClauseGrammarAnalyzer.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler.extension.clause;
2 |
3 | import org.codefamily.crabs.jdbc.lang.Expression;
4 | import org.codefamily.crabs.jdbc.lang.Keyword;
5 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword;
6 | import org.codefamily.crabs.jdbc.lang.extension.clause.SelectClause;
7 | import org.codefamily.crabs.jdbc.lang.extension.clause.SelectClause.ResultColumnDeclare;
8 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer;
9 |
10 | import java.sql.SQLException;
11 | import java.util.ArrayList;
12 |
13 | public final class SelectClauseGrammarAnalyzer extends ClauseGrammarAnalyzer {
14 |
15 | public SelectClauseGrammarAnalyzer() {
16 | super(SelectClause.PREFIX_KEYWORD_LIST);
17 | }
18 |
19 | @Override
20 | protected final SelectClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException {
21 | Boolean distinct = null;
22 | Expression topNExpression = null;
23 | for (; ; ) {
24 | if (context.currentTokenType() == TokenType.KEYWORD) {
25 | final Keyword keyword = context.currentTokenToKeyword();
26 | if (keyword == ReservedKeyword.DISTINCT) {
27 | /*if (distinct == null) {
28 | context.toNextToken();
29 | distinct = true;
30 | continue;
31 | } else {
32 | throw new SQLException("Conflict distinct declare in select clause.");
33 | }*/
34 | // TODO 暂时不支持DISTINCT
35 | throw new SQLException("Now, distinct is not supported in select clause.");
36 | } else if (keyword == ReservedKeyword.TOP) {
37 | /*if (topNExpression == null) {
38 | context.toNextToken();
39 | final int currentTokenStartPosition = context.currentTokenStartPosition();
40 | topNExpression = ExpressionGrammarAnalyzer.analyze(context);
41 | if (topNExpression == null) {
42 | throw newSQLException(
43 | context,
44 | "Expect an expression.",
45 | currentTokenStartPosition
46 | );
47 | }
48 | continue;
49 | } else {
50 | throw new SQLException("Conflict top N declare in select clause.");
51 | }*/
52 | // TODO 暂时不支持TOP N
53 | throw new SQLException("Now, top N is not supported in select clause.");
54 | }
55 | }
56 | break;
57 | }
58 | return new SelectClause(distinct, topNExpression, analyzeResultColumnDeclares(context));
59 | }
60 |
61 | private static ResultColumnDeclare[] analyzeResultColumnDeclares(
62 | final GrammarAnalyzeContext context) throws SQLException {
63 | final ArrayList columnDeclareList = new ArrayList();
64 | for (; ; ) {
65 | final int currentTokenStartPosition = context.currentTokenStartPosition();
66 | final ResultColumnDeclare columnDeclare = analyzeColumnDeclare(context);
67 | if (columnDeclare == null) {
68 | throw newSQLException(
69 | context,
70 | "Expect a column declare of result set.",
71 | currentTokenStartPosition
72 | );
73 | }
74 | columnDeclareList.add(columnDeclare);
75 | if (context.currentTokenType() == TokenType.SYMBOL
76 | && context.currentTokenToSymbol() == ',') {
77 | context.toNextToken();
78 | continue;
79 | }
80 | break;
81 | }
82 | return columnDeclareList.toArray(new ResultColumnDeclare[columnDeclareList.size()]);
83 | }
84 |
85 | private static ResultColumnDeclare analyzeColumnDeclare(
86 | final GrammarAnalyzeContext context) throws SQLException {
87 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context);
88 | if (expression == null) {
89 | return null;
90 | }
91 | final String alias;
92 | if (context.currentTokenType() == TokenType.KEYWORD
93 | && context.currentTokenToKeyword() == ReservedKeyword.AS) {
94 | context.toNextToken();
95 | final int currentTokenStartPosition = context.currentTokenStartPosition();
96 | alias = analyzeGeneralizedIdentifier(context);
97 | if (alias == null) {
98 | throw newSQLException(
99 | context,
100 | "Expect a column declare alias.",
101 | currentTokenStartPosition
102 | );
103 | }
104 | } else {
105 | alias = analyzeGeneralizedIdentifier(context);
106 | }
107 | return new ResultColumnDeclare(alias, expression);
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/clause/WhereClauseGrammarAnalyzer.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler.extension.clause;
2 |
3 | import org.codefamily.crabs.jdbc.lang.Expression;
4 | import org.codefamily.crabs.jdbc.lang.extension.clause.WhereClause;
5 | import org.codefamily.crabs.jdbc.compiler.GrammarAnalyzer.ClauseGrammarAnalyzer;
6 |
7 | import java.sql.SQLException;
8 |
9 | public final class WhereClauseGrammarAnalyzer extends ClauseGrammarAnalyzer {
10 |
11 | public WhereClauseGrammarAnalyzer() {
12 | super(WhereClause.PREFIX_KEYWORD_LIST);
13 | }
14 |
15 | @Override
16 | protected final WhereClause doAnalyze(final GrammarAnalyzeContext context) throws SQLException {
17 | final int currentTokenStartPosition = context.currentTokenStartPosition();
18 | final Expression expression = ExpressionGrammarAnalyzer.analyze(context);
19 | if (expression == null) {
20 | throw newSQLException(
21 | context,
22 | "Expect an expression.",
23 | currentTokenStartPosition
24 | );
25 | }
26 | return new WhereClause(expression);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/compiler/extension/statement/SelectStatementAdapter.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.compiler.extension.statement;
2 |
3 | import org.codefamily.crabs.util.ReadonlyList;
4 | import org.codefamily.crabs.jdbc.lang.Clause;
5 | import org.codefamily.crabs.jdbc.lang.Keyword;
6 | import org.codefamily.crabs.jdbc.lang.Statement;
7 | import org.codefamily.crabs.jdbc.lang.extension.ReservedKeyword;
8 | import org.codefamily.crabs.jdbc.lang.extension.statement.SelectStatement;
9 | import org.codefamily.crabs.jdbc.compiler.StatementFactory;
10 | import org.codefamily.crabs.jdbc.lang.extension.clause.*;
11 |
12 | import java.sql.SQLException;
13 |
14 | public final class SelectStatementAdapter extends StatementFactory.StatementAdapter {
15 |
16 | public SelectStatementAdapter() {
17 | super(SelectClause.class);
18 | }
19 |
20 | @Override
21 | protected final Statement adaptStatement(final ReadonlyList clauseList) throws SQLException {
22 | SelectClause selectClause = null;
23 | FromClause fromClause = null;
24 | WhereClause whereClause = null;
25 | GroupByClause groupByClause = null;
26 | HavingClause havingClause = null;
27 | OrderByClause orderByClause = null;
28 | LimitClause limitClause = null;
29 | for (int i = 0, clauseCount = clauseList.size(); i < clauseCount; i++) {
30 | final Clause clause = clauseList.get(i);
31 | if (clause.prefixKeywordList.isEmpty()) {
32 | throw new SQLException("Unexpected clause in select statement. " + clause.prefixKeywordList);
33 | }
34 | final Keyword keyword = clause.prefixKeywordList.get(0);
35 | if (keyword == ReservedKeyword.SELECT) {
36 | if (selectClause != null) {
37 | throw new SQLException("Conflict select clause in select statement.");
38 | }
39 | selectClause = (SelectClause) clause;
40 | } else if (keyword == ReservedKeyword.FROM) {
41 | if (fromClause != null) {
42 | throw new SQLException("Conflict from clause in select statement.");
43 | }
44 | fromClause = (FromClause) clause;
45 | } else if (keyword == ReservedKeyword.WHERE) {
46 | if (whereClause != null) {
47 | throw new SQLException("Conflict where clause in select statement.");
48 | }
49 | whereClause = (WhereClause) clause;
50 | } else if (keyword == ReservedKeyword.GROUP) {
51 | if (groupByClause != null) {
52 | throw new SQLException("Conflict group by clause in select statement.");
53 | }
54 | groupByClause = (GroupByClause) clause;
55 | } else if (keyword == ReservedKeyword.HAVING) {
56 | if (havingClause != null) {
57 | throw new SQLException("Conflict having clause in select statement.");
58 | }
59 | havingClause = (HavingClause) clause;
60 | } else if (keyword == ReservedKeyword.ORDER) {
61 | if (orderByClause != null) {
62 | throw new SQLException("Conflict order by clause in select statement.");
63 | }
64 | orderByClause = (OrderByClause) clause;
65 | } else if (keyword == ReservedKeyword.LIMIT) {
66 | if (limitClause != null) {
67 | throw new SQLException("Conflict limit clause in select statement.");
68 | }
69 | limitClause = (LimitClause) clause;
70 | } else {
71 | throw new SQLException("Unexpected clause in select statement. " + clause.prefixKeywordList);
72 | }
73 | }
74 | if (selectClause == null) {
75 | throw new SQLException("Missing select clause in select statement.");
76 | }
77 | if (fromClause == null) {
78 | throw new SQLException("Missing from clause in select statement.");
79 | }
80 | // todo 控制子句的先后顺序
81 | return new SelectStatement(
82 | selectClause,
83 | fromClause,
84 | whereClause,
85 | groupByClause,
86 | havingClause,
87 | orderByClause,
88 | limitClause
89 | );
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/engine/ExecuteEngine.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.engine;
2 |
3 | import org.codefamily.crabs.util.ExtensionClassCollector;
4 | import org.codefamily.crabs.core.client.AdvancedClient;
5 | import org.codefamily.crabs.jdbc.lang.Statement;
6 | import org.codefamily.crabs.exception.CrabsException;
7 |
8 | import java.util.Iterator;
9 |
10 | public final class ExecuteEngine {
11 |
12 | public static TResult executeStatement(
13 | final AdvancedClient advancedClient,
14 | final ExecuteEnvironment environment,
15 | TStatement statement,
16 | final Object[] argumentValues,
17 | final Class resultClass) throws CrabsException {
18 | if (advancedClient == null) {
19 | throw new IllegalArgumentException("Argument[advancedClient] is null.");
20 | }
21 | if (environment == null) {
22 | throw new IllegalArgumentException("Argument[environment] is null.");
23 | }
24 | if (statement == null) {
25 | throw new IllegalArgumentException("Argument[statement] is null.");
26 | }
27 | if (argumentValues == null) {
28 | throw new IllegalArgumentException("Argument[argumentValues] is null.");
29 | }
30 | if (resultClass == null) {
31 | throw new IllegalArgumentException("Argument[resultClass] is null.");
32 | }
33 | @SuppressWarnings("unchecked")
34 | final StatementExecutor statementExecutor
35 | = STATEMENT_EXECUTOR_SET.getStatementExecutor((Class) (statement.getClass()), resultClass);
36 | if (statementExecutor == null) {
37 | throw new CrabsException("Can not found statement execute engine for "
38 | + statement.getClass().getSimpleName()
39 | + ", result class " + resultClass.getName());
40 | }
41 | return statementExecutor.execute(advancedClient, statement, environment, argumentValues);
42 | }
43 |
44 | public static void recollectStatementExecutor() {
45 | synchronized (ExecuteEngine.class) {
46 | @SuppressWarnings("rawtypes")
47 | final Iterator> statementExecutorClassIterator
48 | = ExtensionClassCollector.getExtensionClasses(StatementExecutor.class);
49 | try {
50 | while (statementExecutorClassIterator.hasNext()) {
51 | @SuppressWarnings("rawtypes")
52 | final Class extends StatementExecutor> statementExecutorClass
53 | = statementExecutorClassIterator.next();
54 | if (STATEMENT_EXECUTOR_SET.registerStatementExecutor(statementExecutorClass)
55 | != statementExecutorClass) {
56 | throw new RuntimeException(
57 | "Statement executor conflicted." + statementExecutorClass.getName()
58 | );
59 | }
60 | }
61 | } catch (CrabsException e) {
62 | throw new RuntimeException(e);
63 | }
64 | }
65 | }
66 |
67 | private static final StatementExecutorSet STATEMENT_EXECUTOR_SET = new StatementExecutorSet(10);
68 |
69 | static {
70 | recollectStatementExecutor();
71 | }
72 |
73 | private ExecuteEngine() {
74 | // to do nothing.
75 | }
76 |
77 | private static final class StatementExecutorSet {
78 |
79 | StatementExecutorSet(final int capacity) {
80 | this.map = new StatementExecutor[capacity];
81 | }
82 |
83 | private final StatementExecutor, ?>[] map;
84 |
85 | @SuppressWarnings("unchecked")
86 | final StatementExecutor getStatementExecutor(
87 | final Class statementClass,
88 | final Class resultClass) {
89 | StatementExecutor, ?> currentExecutor = this.map[this.hashIndexOf(statementClass, resultClass)];
90 | while (currentExecutor != null) {
91 | if (currentExecutor.statementClass == statementClass
92 | && currentExecutor.resultClass == resultClass) {
93 | break;
94 | } else {
95 | currentExecutor = currentExecutor.nextInSet;
96 | }
97 | }
98 | return (StatementExecutor) currentExecutor;
99 | }
100 |
101 | @SuppressWarnings("rawtypes")
102 | final Class extends StatementExecutor> registerStatementExecutor(
103 | final Class extends StatementExecutor> statementExecutorClass)
104 | throws CrabsException {
105 | final StatementExecutor, ?> statementExecutor;
106 | try {
107 | statementExecutor = statementExecutorClass.newInstance();
108 | } catch (InstantiationException e) {
109 | throw new CrabsException(e);
110 | } catch (IllegalAccessException e) {
111 | throw new CrabsException(e);
112 | }
113 | final StatementExecutor, ?> existedStatementExecutor
114 | = getStatementExecutor(statementExecutor.statementClass, statementExecutor.resultClass);
115 | if (existedStatementExecutor != null) {
116 | return existedStatementExecutor.getClass();
117 | } else {
118 | final int hashIndex = this.hashIndexOf(
119 | statementExecutor.statementClass,
120 | statementExecutor.resultClass
121 | );
122 | statementExecutor.nextInSet = this.map[hashIndex];
123 | this.map[hashIndex] = statementExecutor;
124 | return statementExecutorClass;
125 | }
126 | }
127 |
128 | private int hashIndexOf(
129 | final Class extends Statement> statementClass,
130 | final Class> resultClass) {
131 | return (31 * statementClass.hashCode() + resultClass.hashCode())
132 | & (this.map.length - 1);
133 | }
134 |
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/crabs-jdbc/src/main/java/org/codefamily/crabs/jdbc/engine/ExecuteEnvironment.java:
--------------------------------------------------------------------------------
1 | package org.codefamily.crabs.jdbc.engine;
2 |
3 | import org.codefamily.crabs.util.TimeCacheMap;
4 | import org.codefamily.crabs.core.Identifier;
5 | import org.codefamily.crabs.core.IndexDefinition;
6 | import org.codefamily.crabs.core.TypeDefinition;
7 | import org.codefamily.crabs.core.client.AdvancedClient;
8 | import org.codefamily.crabs.exception.CrabsException;
9 | import org.codefamily.crabs.jdbc.Protocol;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import java.io.Closeable;
14 | import java.io.IOException;
15 | import java.util.Map;
16 | import java.util.Properties;
17 |
18 | public final class ExecuteEnvironment implements Closeable {
19 |
20 | private static final Logger LOG = LoggerFactory.getLogger(ExecuteEnvironment.class);
21 |
22 | private static final Properties EMPTY_PROPERTIES = new Properties();
23 |
24 | private final AdvancedClient advancedClient;
25 |
26 | private final Identifier indexIdentifier;
27 |
28 | private final Properties properties;
29 |
30 | private final TimeCacheMap typeDefinitionCache;
31 |
32 | public ExecuteEnvironment(final AdvancedClient advancedClient,
33 | final Identifier indexIdentifier) {
34 | this(advancedClient, indexIdentifier, EMPTY_PROPERTIES);
35 | }
36 |
37 | public ExecuteEnvironment(final AdvancedClient advancedClient,
38 | final Identifier indexIdentifier,
39 | final Properties properties) {
40 | if (advancedClient == null) {
41 | throw new IllegalArgumentException("Argument[advancedClient] is null.");
42 | }
43 | if (indexIdentifier == null) {
44 | throw new IllegalArgumentException("Argument[indexIdentifier] is null.");
45 | }
46 | final Properties finallyProperties = new Properties();
47 | for (Map.Entry