├── .checkstyle
├── .classpath
├── .gitignore
├── .project
├── .settings
├── org.eclipse.core.resources.prefs
├── org.eclipse.jdt.core.prefs
└── org.eclipse.m2e.core.prefs
├── LICENSE
├── README.md
├── pom.xml
└── src
├── it
└── java
│ └── info
│ └── michaelwittig
│ └── javaq
│ └── connector
│ └── impl
│ ├── ATest.java
│ ├── ATestWithConnection.java
│ ├── ATestWithConnectionSync.java
│ ├── QConnectorAsyncImplReconnectTest.java
│ ├── QConnectorSyncImplReconnectTest.java
│ ├── QConnectorSyncImplTest.java
│ ├── QConnectorSyncTSImplReconnectTest.java
│ └── QConnectorSyncTSImplTest.java
├── main
└── java
│ ├── info
│ └── michaelwittig
│ │ └── javaq
│ │ ├── Builder.java
│ │ ├── Q.java
│ │ ├── connector
│ │ ├── QConnector.java
│ │ ├── QConnectorAsync.java
│ │ ├── QConnectorDataListener.java
│ │ ├── QConnectorError.java
│ │ ├── QConnectorException.java
│ │ ├── QConnectorListener.java
│ │ ├── QConnectorSync.java
│ │ └── impl
│ │ │ ├── CResultHelper.java
│ │ │ ├── QConnectorAsyncImpl.java
│ │ │ ├── QConnectorFactory.java
│ │ │ ├── QConnectorImpl.java
│ │ │ ├── QConnectorSyncImpl.java
│ │ │ ├── QConnectorSyncTSImpl.java
│ │ │ └── cmd
│ │ │ ├── AConnectorSyncCommand.java
│ │ │ ├── ConnectorAsyncCommand.java
│ │ │ ├── ConnectorAsyncCommandQ.java
│ │ │ ├── ConnectorSyncCommand.java
│ │ │ ├── ConnectorSyncCommandFunction.java
│ │ │ ├── ConnectorSyncCommandQ.java
│ │ │ └── ConnectorSyncCommandSelect.java
│ │ └── query
│ │ ├── ATableResult.java
│ │ ├── EmptyResult.java
│ │ ├── FlipFlipResult.java
│ │ ├── FlipResult.java
│ │ ├── Function.java
│ │ ├── ListResult.java
│ │ ├── PrimitiveResult.java
│ │ ├── Result.java
│ │ ├── Select.java
│ │ ├── Table.java
│ │ ├── TableResult.java
│ │ ├── TableRow.java
│ │ ├── column
│ │ ├── AggregateColumn.java
│ │ ├── AggregatingNominal.java
│ │ ├── AggregatingOrdinal.java
│ │ ├── Aggregation.java
│ │ ├── Column.java
│ │ ├── VirtualColumn.java
│ │ ├── Virtualling.java
│ │ └── impl
│ │ │ ├── ASimpleNominalColumn.java
│ │ │ ├── ASimpleOrdinalColumn.java
│ │ │ ├── AggregateColumnImpl.java
│ │ │ ├── BooleanColumn.java
│ │ │ ├── DateColumn.java
│ │ │ ├── DateTimeColumn.java
│ │ │ ├── FloatColumn.java
│ │ │ ├── IntegerColumn.java
│ │ │ ├── LongColumn.java
│ │ │ ├── RealColumn.java
│ │ │ ├── SymbolColumn.java
│ │ │ ├── TimeColumn.java
│ │ │ ├── TimestampColumn.java
│ │ │ └── VirtualColumnImpl.java
│ │ ├── filter
│ │ ├── ComparisonFiltering.java
│ │ ├── EqualityFiltering.java
│ │ ├── Filter.java
│ │ └── impl
│ │ │ ├── FilterComparator.java
│ │ │ └── FilterImpl.java
│ │ ├── group
│ │ ├── Group.java
│ │ ├── Grouping.java
│ │ ├── XbarGrouping.java
│ │ └── impl
│ │ │ └── XbarGroupImpl.java
│ │ ├── impl
│ │ ├── ATable.java
│ │ ├── FunctionImpl.java
│ │ ├── SelectImpl.java
│ │ ├── TableImpl.java
│ │ ├── TableIterator.java
│ │ └── TableRowImpl.java
│ │ ├── type
│ │ ├── List.java
│ │ ├── NominalType.java
│ │ ├── OrdinalType.java
│ │ ├── Type.java
│ │ ├── ValueFactory.java
│ │ └── impl
│ │ │ ├── TypeBoolean.java
│ │ │ ├── TypeDate.java
│ │ │ ├── TypeDateTime.java
│ │ │ ├── TypeFloat.java
│ │ │ ├── TypeInteger.java
│ │ │ ├── TypeList.java
│ │ │ ├── TypeLong.java
│ │ │ ├── TypeReal.java
│ │ │ ├── TypeSymbol.java
│ │ │ ├── TypeTime.java
│ │ │ └── TypeTimestamp.java
│ │ └── value
│ │ ├── Value.java
│ │ └── impl
│ │ ├── AValue.java
│ │ ├── BooleanValue.java
│ │ ├── DateTimeValue.java
│ │ ├── DateValue.java
│ │ ├── FloatValue.java
│ │ ├── IntegerValue.java
│ │ ├── ListValue.java
│ │ ├── LongValue.java
│ │ ├── RealValue.java
│ │ ├── SymbolValue.java
│ │ ├── TimeValue.java
│ │ └── TimestampValue.java
│ └── kx
│ └── c.java
└── test
└── java
└── info
└── michaelwittig
└── javaq
├── demo
├── ConsoleSubscriber.java
├── ReconnectTest.java
├── SelectQueryExample.java
└── tabledefinition
│ ├── MyTable.java
│ └── SelectQueryExample.java
└── query
├── column
└── impl
│ ├── ASimpleNominalColumnTest.java
│ └── ASimpleOrdinalColumnTest.java
├── filter
└── impl
│ └── FilterImplTest.java
├── impl
├── FunctionImplTest.java
├── SelectImplTest.java
└── TableImplTest.java
└── value
└── impl
├── BooleanValueTest.java
├── FloatValueTest.java
├── IntegerValueTest.java
├── LongValueTest.java
├── RealValueTest.java
├── SymbolValueTest.java
├── TimeValueTest.java
└── TimestampValueTest.java
/.checkstyle:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | .idea/
3 | *.iml
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | java-q
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | net.sf.eclipsecs.core.CheckstyleBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.m2e.core.maven2Builder
20 |
21 |
22 |
23 |
24 |
25 | org.eclipse.m2e.core.maven2Nature
26 | org.eclipse.jdt.core.javanature
27 | net.sf.eclipsecs.core.CheckstyleNature
28 |
29 |
30 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding//src/main/java=UTF-8
3 | encoding//src/test/java=UTF-8
4 | encoding/=UTF-8
5 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
5 | org.eclipse.jdt.core.compiler.source=1.6
6 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | #Wed Mar 21 08:36:35 CET 2012
2 | activeProfiles=
3 | eclipse.preferences.version=1
4 | resolveWorkspaceProjects=true
5 | version=1
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](http://travis-ci.org/michaelwittig/java-q)
2 |
3 | # java-q
4 |
5 | Hej folks! Again and again we have to interact with a [kdb+](http://kx.com/kdb+.php) and [kdb+tick](http://kx.com/kdb+tick.php). The guys from [KX Systems](http://kx.com/) provide us [c.java](http://code.kx.com/wsvn/code/kx/kdb%2B/c/kx/c.java) to interact with their product. You might experienced that c.java is not really using an object oriented style (because q does not?), so we started to write our own wrapper and called it java-q. Feel free to create [Issues](https://github.com/michaelwittig/java-q/issues) if something is missing for you. And now: have fun:)
6 |
7 | ## Encapsulation
8 |
9 | **You do not need to be a q god to use this library!**
10 |
11 | We encapsulate all the q stuff for you! It's just simple Java. Look at the following example. Have you ever seen a [q-sql select](http://code.kx.com/wiki/JB:QforMortals/queries_q_sql) so Java pretty?
12 |
13 | ```java
14 | Select select = trade.select()
15 | .column(size.sum())
16 | .column(price.avg())
17 | .group(sym.group())
18 | .group(time.xbar(LongValue.from(60000L)))
19 | .filter(sym.filterIn(SymbolValue.froms(new String[] {"AAA", "BBB"})))
20 | .order(Direction.descending, time)
21 | .build();
22 | ```
23 |
24 | ## Schema definition
25 |
26 | Your schema is defined by code not by text! You get easy refactoring and lesser typos for free:)
27 |
28 | [Learn more about how to define your schema with a few lines of code.](https://github.com/michaelwittig/java-q/wiki/HowTo:-Schema)
29 |
30 | ```java
31 | public class MyTable extends ATable {
32 | private static MyTable INSTANCE = new MyTable();
33 | public static MyTable get() {
34 | return INSTANCE;
35 | }
36 |
37 | public TimeColumn time = new TimeColumn("time");
38 | public SymbolColumn sym = new SymbolColumn("sym");
39 | public FloatColumn price = new FloatColumn("price");
40 | public IntegerColumn size = new IntegerColumn("size");
41 |
42 | private MyTable() {
43 | super("mytable");
44 | this.addColumn(this.time);
45 | this.addColumn(this.sym);
46 | this.addColumn(this.price);
47 | this.addColumn(this.size);
48 | }
49 | }
50 | ```
51 |
52 | ## Synchronous Access
53 |
54 | ### Queries using select
55 |
56 | [Learn more about how to create a q query.](https://github.com/michaelwittig/java-q/wiki/HowTo:-Query)
57 |
58 | ```java
59 | // get table schema
60 | MyTable table = MyTable.get();
61 |
62 | // create select query
63 | Select select = table.select()
64 | .column(table.size.sum())
65 | .column(table.price.avg())
66 | .group(table.sym.group())
67 | .filter(table.sym.filterIn(SymbolValue.froms(new String[] {"AAA", "BBB"})))
68 | .order(Direction.descending, table.time)
69 | .build();
70 | System.out.println("q: " + select.toQ());
71 |
72 | // connect to kdb+
73 | QConnectorSync kx = QConnectorFactory.create("localhost", 5011);
74 | kx.connect();
75 |
76 | // execute select query and print the result
77 | Result result = kx.select(select);
78 | for (TableRow row : table.read(result)) {
79 | System.out.println(row.get(table.time));
80 | System.out.println(row.get(table.sym));
81 | System.out.println(row.get(table.price));
82 | System.out.println(row.get(table.size));
83 | }
84 |
85 | // close connection
86 | kx.disconnect();
87 | ```
88 |
89 | ## Asynchronous Access
90 |
91 | ### Subscription using .u.sub[]
92 |
93 | [Learn more about how to subscribe to q kdb+tick environement.](https://github.com/michaelwittig/java-q/wiki/HowTo:-Subscription)
94 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | org.sonatype.oss
5 | oss-parent
6 | 9
7 |
8 | info.michaelwittig
9 | java-q
10 | 1.0.1-SNAPSHOT
11 | Q interfacing with Java
12 | ...
13 | https://github.com/michaelwittig/java-q
14 | 2012
15 |
16 |
17 | Apache License, Version 2.0
18 | http://www.apache.org/licenses/LICENSE-2.0.txt
19 | repo
20 |
21 |
22 |
23 | scm:git:git@github.com:michaelwittig/java-q.git
24 | scm:git:git@github.com:michaelwittig/java-q.git
25 | git@github.com:michaelwittig/java-q.git
26 |
27 |
28 | github
29 | https://github.com/michaelwittig/java-q/issues
30 |
31 |
32 | UTF-8
33 | yyyyMMdd-HHmmss
34 |
35 |
36 |
37 | mwittig
38 | post@michaelwittig.info
39 | Michael Wittig
40 |
41 |
42 | thoeger
43 | thorsten.hoeger@hoegernet.com
44 | Thorsten Hoeger
45 |
46 |
47 |
48 |
49 |
50 | org.apache.commons
51 | commons-lang3
52 | 3.3.2
53 |
54 |
55 | com.google.guava
56 | guava
57 | 18.0
58 |
59 |
60 | net.java.dev.jna
61 | jna
62 | 4.1.0
63 | test
64 |
65 |
66 | net.java.dev.jna
67 | platform
68 | 3.5.2
69 | test
70 |
71 |
72 | junit
73 | junit
74 | 4.11
75 | test
76 |
77 |
78 |
79 |
80 |
81 | org.apache.maven.plugins
82 | maven-compiler-plugin
83 |
84 | 1.7
85 | 1.7
86 | true
87 |
88 |
89 |
90 |
91 |
92 | 3.0.0
93 |
94 |
95 |
--------------------------------------------------------------------------------
/src/it/java/info/michaelwittig/javaq/connector/impl/ATest.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector.impl;
2 |
3 | import java.lang.reflect.Field;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | import com.sun.jna.Pointer;
8 | import com.sun.jna.platform.win32.Kernel32;
9 | import com.sun.jna.platform.win32.WinNT;
10 | import org.apache.commons.lang3.SystemUtils;
11 |
12 | /**
13 | * Assumes the ENV QHOME to be set!
14 | *
15 | * @author mwittig
16 | * @author bdupreez.. added windows support
17 | */
18 | public abstract class ATest {
19 |
20 | private static final Map port2pid = new HashMap();
21 | private static final String DEFAULT_QHOME = "C:/q";
22 |
23 | protected void launchQProcess() throws Exception {
24 | this.launchQProcess(5000);
25 | }
26 |
27 | protected synchronized void launchQProcess(final int port) throws Exception {
28 | String qhome = System.getenv("QHOME");
29 | if (qhome == null) {
30 | qhome = DEFAULT_QHOME;
31 | }
32 | if (ATest.port2pid.containsKey(port)) {
33 | throw new RuntimeException("port already used");
34 | }
35 | final String path;
36 | if (SystemUtils.IS_OS_LINUX) {
37 | path = qhome + "/l32/q";
38 | } else if (SystemUtils.IS_OS_MAC) {
39 | path = qhome + "/m32/q";
40 | } else if (SystemUtils.IS_OS_WINDOWS) {
41 | path = qhome + "/w32/q";
42 | } else {
43 | throw new RuntimeException("OS not supported!");
44 | }
45 | final Process p = new ProcessBuilder(path, "-p", String.valueOf(port)).start();
46 | final int pid;
47 | try {
48 | if (SystemUtils.IS_OS_WINDOWS) {
49 | pid = determineWindowsProcessId(p);
50 | } else {
51 | pid = getLinuxMacPid(p);
52 | }
53 | } catch (final Exception e) {
54 | throw new RuntimeException("OS related exception!", e);
55 | }
56 | ATest.port2pid.put(port, pid);
57 | Thread.sleep(200); // wait until started
58 | }
59 |
60 | private int getLinuxMacPid(final Process p) throws NoSuchFieldException, IllegalAccessException {
61 | final Field f = p.getClass().getDeclaredField("pid");
62 | f.setAccessible(true);
63 | return f.getInt(p);
64 | }
65 |
66 | protected void terminateQProcess() throws Exception {
67 | this.terminateQProcess(5000);
68 | }
69 |
70 | protected void terminateQProcess(final int port) throws Exception {
71 | final Integer pid = ATest.port2pid.get(port);
72 | ATest.port2pid.remove(port);
73 | if (pid == null) {
74 | throw new RuntimeException("port not used");
75 | }
76 | if (SystemUtils.IS_OS_WINDOWS) {
77 | new ProcessBuilder("taskkill", "/PID", pid.toString(), "/T", "/F").start().waitFor();
78 | }else {
79 | new ProcessBuilder("kill", "-9", pid.toString()).start().waitFor();
80 | }
81 | }
82 |
83 | private int determineWindowsProcessId(final Process proc) {
84 | if (proc.getClass().getName().equals("java.lang.Win32Process")
85 | || proc.getClass().getName().equals("java.lang.ProcessImpl")) {
86 | try {
87 | final Field f = proc.getClass().getDeclaredField("handle");
88 | f.setAccessible(true);
89 | final long handleId = f.getLong(proc);
90 | final Kernel32 kernel = Kernel32.INSTANCE;
91 | final WinNT.HANDLE handle = new WinNT.HANDLE();
92 | handle.setPointer(Pointer.createConstant(handleId));
93 | return kernel.GetProcessId(handle);
94 | } catch (final Throwable e) {
95 | throw new RuntimeException(e.getMessage());
96 | }
97 | }
98 | return 0;
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/it/java/info/michaelwittig/javaq/connector/impl/ATestWithConnection.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector.impl;
2 |
3 | import info.michaelwittig.javaq.connector.QConnector;
4 |
5 | import org.junit.After;
6 | import org.junit.Before;
7 |
8 | /**
9 | * Assumes running q process on localhost:5000!
10 | *
11 | * @author mwittig
12 | *
13 | * @param QConnector
14 | *
15 | */
16 | @SuppressWarnings("javadoc")
17 | public abstract class ATestWithConnection extends ATest {
18 |
19 | private volatile T c;
20 |
21 |
22 | abstract T create(String host, int port);
23 |
24 | @Before
25 | public void setUp() throws Exception {
26 | this.launchQProcess();
27 | this.c = this.create("localhost", 5000);
28 | this.c.connect();
29 | }
30 |
31 | @After
32 | public void tearDOwn() throws Exception {
33 | this.terminateQProcess();
34 | }
35 |
36 | protected T c() {
37 | return this.c;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/it/java/info/michaelwittig/javaq/connector/impl/QConnectorAsyncImplReconnectTest.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector.impl;
2 |
3 | import info.michaelwittig.javaq.connector.QConnectorError;
4 | import info.michaelwittig.javaq.connector.QConnectorException;
5 | import info.michaelwittig.javaq.connector.QConnectorListener;
6 | import info.michaelwittig.javaq.query.Result;
7 |
8 | import org.junit.Assert;
9 | import org.junit.Test;
10 |
11 | /**
12 | * @author mwittig
13 | *
14 | */
15 | @SuppressWarnings("javadoc")
16 | public final class QConnectorAsyncImplReconnectTest extends ATest {
17 |
18 | @Test
19 | public void testConnectionFail() throws Exception {
20 | this.launchQProcess();
21 | final QConnectorAsyncImpl c = new QConnectorAsyncImpl(new QConnectorListener() {
22 |
23 | @Override
24 | public void error(QConnectorError e) {
25 | // reports about reconnects
26 | }
27 |
28 | @Override
29 | public void exception(QConnectorException e) {
30 | // reports about exceptions
31 | }
32 |
33 | @Override
34 | public void resultReceived(final String handle, final Result result) {
35 | // data received
36 | }
37 | }, "localhost", 5000, false);
38 | c.connect();
39 | c.subscribe("test", new String[] {"test"}, new String[] {"TEST"});
40 | Thread.sleep(1500);
41 | this.terminateQProcess();
42 | Thread.sleep(1500);
43 | try {
44 | c.disconnect();
45 | Assert.fail("should fail because disconnect is already triggert");
46 | } catch (final Exception e) {
47 | // nothing
48 | }
49 | this.launchQProcess();
50 | c.connect();
51 | Thread.sleep(500);
52 | c.disconnect();
53 | this.terminateQProcess();
54 | }
55 |
56 | @Test()
57 | public void testConnectionFailWithReconnect() throws Exception {
58 | this.launchQProcess();
59 | final QConnectorAsyncImpl c = new QConnectorAsyncImpl(new QConnectorListener() {
60 |
61 | @Override
62 | public void error(QConnectorError e) {
63 | // reports about reconnects
64 | }
65 |
66 | @Override
67 | public void exception(QConnectorException e) {
68 | throw new RuntimeException(e);
69 | }
70 |
71 | @Override
72 | public void resultReceived(final String handle, final Result result) {
73 | // data received
74 | }
75 | }, "localhost", 5000, true);
76 | c.connect();
77 | c.subscribe("test", new String[] {"test"}, new String[] {"TEST"});
78 | Thread.sleep(1500);
79 | this.terminateQProcess();
80 | Thread.sleep(3000);
81 | this.launchQProcess();
82 | Thread.sleep(1500);
83 | c.disconnect();
84 | this.terminateQProcess();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/it/java/info/michaelwittig/javaq/connector/impl/QConnectorSyncImplReconnectTest.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector.impl;
2 |
3 | import info.michaelwittig.javaq.query.PrimitiveResult;
4 | import info.michaelwittig.javaq.query.Result;
5 |
6 | import org.junit.Assert;
7 | import org.junit.Test;
8 |
9 | /**
10 | * @author mwittig
11 | *
12 | */
13 | @SuppressWarnings("javadoc")
14 | public final class QConnectorSyncImplReconnectTest extends ATest {
15 |
16 | @Test
17 | public void testConnectionFail() throws Exception {
18 | this.launchQProcess();
19 | final QConnectorSyncImpl c = new QConnectorSyncImpl("localhost", 5000, false);
20 | c.connect();
21 | Result r1 = c.execute("1+1");
22 | Assert.assertTrue(r1 instanceof PrimitiveResult);
23 | this.terminateQProcess();
24 | Thread.sleep(1000);
25 | try {
26 | c.execute("1+1");
27 | Assert.fail("Should fail");
28 | } catch (final Exception e) {
29 | e.printStackTrace();
30 | }
31 | Thread.sleep(1000);
32 | this.launchQProcess();
33 | try {
34 | c.execute("1+1");
35 | Assert.fail("Should fail");
36 | } catch (final Exception e) {
37 | e.printStackTrace();
38 | } finally {
39 | this.terminateQProcess();
40 | }
41 | }
42 |
43 | @Test
44 | public void testConnectionFailWithReconnect() throws Exception {
45 | this.launchQProcess();
46 | final QConnectorSyncImpl c = new QConnectorSyncImpl("localhost", 5000, true);
47 | c.connect();
48 | Result r1 = c.execute("1+1");
49 | Assert.assertTrue(r1 instanceof PrimitiveResult);
50 | this.terminateQProcess();
51 | Thread.sleep(1000);
52 | try {
53 | c.execute("1+1");
54 | Assert.fail("Should fail");
55 | } catch (final Exception e) {
56 | e.printStackTrace();
57 | }
58 | Thread.sleep(1000);
59 | this.launchQProcess();
60 | Result r2 = c.execute("1+1");
61 | Assert.assertTrue(r2 instanceof PrimitiveResult);
62 | this.terminateQProcess();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/it/java/info/michaelwittig/javaq/connector/impl/QConnectorSyncImplTest.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector.impl;
2 |
3 | /**
4 | * @author mwittig
5 | *
6 | */
7 | public final class QConnectorSyncImplTest extends ATestWithConnectionSync {
8 |
9 | @Override
10 | QConnectorSyncImpl create(final String host, final int port) {
11 | return new QConnectorSyncImpl(host, port, true);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/it/java/info/michaelwittig/javaq/connector/impl/QConnectorSyncTSImplReconnectTest.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector.impl;
2 |
3 | import info.michaelwittig.javaq.query.PrimitiveResult;
4 | import info.michaelwittig.javaq.query.Result;
5 | import info.michaelwittig.javaq.query.TableResult;
6 |
7 | import org.junit.Assert;
8 | import org.junit.Test;
9 |
10 | /**
11 | * @author mwittig
12 | *
13 | */
14 | @SuppressWarnings("javadoc")
15 | public final class QConnectorSyncTSImplReconnectTest extends ATest {
16 |
17 | @Test
18 | public void testConnectionFail() throws Exception {
19 | this.launchQProcess();
20 | final QConnectorSyncTSImpl c = new QConnectorSyncTSImpl("localhost", 5000, false);
21 | c.connect();
22 | Result r1 = c.execute("1+1");
23 | Assert.assertTrue(r1 instanceof PrimitiveResult);
24 | this.terminateQProcess();
25 | Thread.sleep(1000);
26 | try {
27 | c.execute("1+1");
28 | Assert.fail("Should fail");
29 | } catch (final Exception e) {
30 | e.printStackTrace();
31 | }
32 | Thread.sleep(1000);
33 | this.launchQProcess();
34 | try {
35 | c.execute("1+1");
36 | Assert.fail("Should fail");
37 | } catch (final Exception e) {
38 | e.printStackTrace();
39 | } finally {
40 | this.terminateQProcess();
41 | }
42 | }
43 |
44 | @Test
45 | public void testConnectionFailWithReconnect() throws Exception {
46 | this.launchQProcess();
47 | final QConnectorSyncTSImpl c = new QConnectorSyncTSImpl("localhost", 5000, true);
48 | c.connect();
49 | Result r1 = c.execute("1+1");
50 | Assert.assertTrue(r1 instanceof PrimitiveResult);
51 | this.terminateQProcess();
52 | Thread.sleep(1000);
53 | try {
54 | c.execute("1+1");
55 | Assert.fail("Should fail");
56 | } catch (final Exception e) {
57 | e.printStackTrace();
58 | }
59 | Thread.sleep(1000);
60 | this.launchQProcess();
61 | Result r2 = c.execute("1+1");
62 | Assert.assertTrue(r2 instanceof PrimitiveResult);
63 | this.terminateQProcess();
64 | }
65 |
66 | @Test
67 | public void testReadTable() throws Exception {
68 | try {
69 | this.launchQProcess();
70 | final QConnectorSyncTSImpl c = new QConnectorSyncTSImpl("localhost", 5000, true);
71 | c.connect();
72 | final TableResult res = (TableResult) c.execute("([] a:(1 2 3 4 5 6); b:(111000b); c:(`a`b`c`d`e`f))");
73 | Assert.assertEquals(3, res.getCols());
74 | Assert.assertEquals(6, res.getRows());
75 | Assert.assertArrayEquals(new String[] {"a", "b", "c"}, res.getColNames());
76 | Assert.assertEquals(1L, res.getAt(0, 0));
77 | Assert.assertEquals(1L, res.getAt("a", 0));
78 | } finally {
79 | this.terminateQProcess();
80 | }
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/it/java/info/michaelwittig/javaq/connector/impl/QConnectorSyncTSImplTest.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector.impl;
2 |
3 | /**
4 | * @author mwittig
5 | *
6 | */
7 | public final class QConnectorSyncTSImplTest extends ATestWithConnectionSync {
8 |
9 | @Override
10 | QConnectorSyncTSImpl create(final String host, final int port) {
11 | return new QConnectorSyncTSImpl(host, port, true);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/Builder.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq;
2 |
3 | /**
4 | * Builder.
5 | *
6 | * @author mwittig
7 | *
8 | * @param Class
9 | */
10 | public interface Builder {
11 |
12 | /**
13 | * @return Class
14 | */
15 | C build();
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/Q.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq;
2 |
3 | /**
4 | * Represent a q command line.
5 | *
6 | * @author mwittig
7 | *
8 | */
9 | public interface Q {
10 |
11 | /**
12 | * @return Q
13 | */
14 | String toQ();
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/connector/QConnector.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector;
2 |
3 | /**
4 | * QConnector.
5 | *
6 | * Error / Exception handling: Errors are failures that the system can handle automatically and to correct the failure situation. For
7 | * example if the connection is lost and reconnectOnError is true, the QConnector will try to reconnect to the server. Exceptions are
8 | * failures that the system can not handle by itself. For example an malformed q command.
9 | *
10 | * @author mwittig
11 | *
12 | */
13 | public abstract interface QConnector {
14 |
15 | /**
16 | * Connect.
17 | *
18 | * @throws QConnectorException If the connection can not be established
19 | * @throws QConnectorError If the QConnector is already connected
20 | */
21 | void connect() throws QConnectorException, QConnectorError;
22 |
23 | /**
24 | * Disconnect.
25 | *
26 | * @throws QConnectorError If the connection was disconnected already
27 | */
28 | void disconnect() throws QConnectorError;
29 |
30 | /**
31 | * @return Host
32 | */
33 | String getHost();
34 |
35 | /**
36 | * @return Port
37 | */
38 | int getPort();
39 |
40 | /**
41 | * @return Reconnect on error?
42 | */
43 | boolean reconnectOnError();
44 |
45 | /**
46 | * @return Connected?
47 | */
48 | boolean isConnected();
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/connector/QConnectorAsync.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector;
2 |
3 | /**
4 | * QConnector asynchronous.
5 | *
6 | * Thread-safe? yes
7 | *
8 | * @author mwittig
9 | *
10 | */
11 | public interface QConnectorAsync extends QConnector {
12 |
13 | /**
14 | * Subscribe and receive data via global QConnectorListener.
15 | *
16 | * @param handle Unique handle to identify received data
17 | * @param tables Tables to subscribe
18 | * @param symbols Symbols to subscribe
19 | * @throws QConnectorException If the communication fails or the subscription is corrupt
20 | */
21 | void subscribe(String handle, String[] tables, String[] symbols) throws QConnectorException;
22 |
23 | /**
24 | * Subscribe and receive data via local QConnectorDataListener.
25 | *
26 | * @param listener Listener
27 | * @param tables Table to subscribe
28 | * @param symbols Symbols to subscribe
29 | * @throws QConnectorException If the communication fails or the subscription is corrupt
30 | */
31 | void subscribe(QConnectorDataListener listener, String[] tables, String[] symbols) throws QConnectorException;
32 |
33 | /**
34 | * Unsubscribe.
35 | *
36 | * @param handle Unique handle to identify received data
37 | */
38 | void unsubscribe(String handle);
39 |
40 | /**
41 | * Unsubscribe.
42 | *
43 | * @param listener Listener
44 | */
45 | void unsubscribe(QConnectorDataListener listener);
46 |
47 | /**
48 | * @return QConnectorListener
49 | */
50 | QConnectorListener getConnectorListener();
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/connector/QConnectorDataListener.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector;
2 |
3 | import info.michaelwittig.javaq.query.Result;
4 |
5 | /**
6 | * QConnector data listener.
7 | *
8 | * @author mwittig
9 | *
10 | */
11 | public interface QConnectorDataListener {
12 |
13 | /**
14 | * QConnectorException occurred. Must be handled by yourself!
15 | *
16 | * @param e Exception
17 | */
18 | void exception(QConnectorException e);
19 |
20 | /**
21 | * Result received.
22 | *
23 | * @param handle Unique handle to identify received data
24 | * @param result Result
25 | */
26 | void resultReceived(Result result);
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/connector/QConnectorError.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector;
2 |
3 | /**
4 | * QConnectorErrors are handled by the QConnector. They are just an information. Nothing needs to be done!
5 | *
6 | * @author mwittig
7 | *
8 | */
9 | public final class QConnectorError extends Exception {
10 |
11 | /** Serial version UID. */
12 | private static final long serialVersionUID = 1L;
13 |
14 |
15 | /**
16 | * @param message Message
17 | */
18 | public QConnectorError(final String message) {
19 | super(message);
20 | }
21 |
22 | @Override
23 | public String toString() {
24 | return "QConnectorError: " + this.getMessage();
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/connector/QConnectorException.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector;
2 |
3 | /**
4 | * QConnectorExceptions must be handled by yourself! They are indicating that the system is not in a proper state any longer.
5 | *
6 | * @author mwittig
7 | *
8 | */
9 | public final class QConnectorException extends Exception {
10 |
11 | /** Serial version UID. */
12 | private static final long serialVersionUID = 1L;
13 |
14 |
15 | /**
16 | * @param message Message
17 | * @param cause Cause
18 | */
19 | public QConnectorException(final String message, final Throwable cause) {
20 | super(message, cause);
21 | }
22 |
23 | /**
24 | * @param message Message
25 | */
26 | public QConnectorException(final String message) {
27 | super(message);
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return "QConnectorException: " + this.getMessage();
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/connector/QConnectorListener.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector;
2 |
3 | import info.michaelwittig.javaq.query.Result;
4 |
5 | /**
6 | * QConnector listener.
7 | *
8 | * @author mwittig
9 | *
10 | */
11 | public interface QConnectorListener {
12 |
13 | /**
14 | * QConnectorError occurred. Is handled by the QConnector. Just an information.
15 | *
16 | * @param e Error
17 | */
18 | void error(QConnectorError e);
19 |
20 | /**
21 | * QConnectorException occurred. Must be handled by yourself!
22 | *
23 | * @param e Exception
24 | */
25 | void exception(QConnectorException e);
26 |
27 | /**
28 | * Result received.
29 | *
30 | * @param handle Unique handle to identify received data
31 | * @param result Result
32 | */
33 | void resultReceived(final String handle, Result result);
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/connector/QConnectorSync.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector;
2 |
3 | import info.michaelwittig.javaq.query.Function;
4 | import info.michaelwittig.javaq.query.Result;
5 | import info.michaelwittig.javaq.query.Select;
6 |
7 | /**
8 | * QConnector synchronous.
9 | *
10 | * Thread-safe? depends on implementation
11 | *
12 | * @author mwittig
13 | *
14 | */
15 | public interface QConnectorSync extends QConnector {
16 |
17 | /**
18 | * Synchronous execute.
19 | *
20 | * @param q Q code
21 | * @return Result
22 | * @throws QConnectorException If something went wrong
23 | */
24 | Result execute(String q) throws QConnectorException;
25 |
26 | /**
27 | * Synchronous select.
28 | *
29 | * @param select Select
30 | * @return Result
31 | * @throws QConnectorException If something went wrong
32 | */
33 | Result select(Select select) throws QConnectorException;
34 |
35 | /**
36 | * Synchronous call.
37 | *
38 | * @param function Function
39 | * @return Result
40 | * @throws QConnectorException If something went wrong
41 | */
42 | Result call(Function function) throws QConnectorException;
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/info/michaelwittig/javaq/connector/impl/CResultHelper.java:
--------------------------------------------------------------------------------
1 | package info.michaelwittig.javaq.connector.impl;
2 |
3 | import info.michaelwittig.javaq.connector.QConnectorException;
4 | import info.michaelwittig.javaq.query.EmptyResult;
5 | import info.michaelwittig.javaq.query.FlipFlipResult;
6 | import info.michaelwittig.javaq.query.FlipResult;
7 | import info.michaelwittig.javaq.query.ListResult;
8 | import info.michaelwittig.javaq.query.PrimitiveResult;
9 | import info.michaelwittig.javaq.query.Result;
10 |
11 | import java.util.UUID;
12 |
13 | import kx.c;
14 |
15 | import org.apache.commons.lang3.ArrayUtils;
16 |
17 | /**
18 | * @author mwittig
19 | *
20 | */
21 | public final class CResultHelper {
22 |
23 | /**
24 | * Converts an result from the kx c library to a QConnector Result.
25 | *
26 | * @param res Result from q
27 | * @return Result
28 | * @throws QConnectorException If the result type is not supported
29 | */
30 | public static Result convert(final Object res) throws QConnectorException {
31 | if (res == null) {
32 | return new EmptyResult();
33 | }
34 | // table
35 | if (res instanceof c.Flip) {
36 | return new FlipResult("", (c.Flip) res);
37 | }
38 | // dict
39 | if (res instanceof c.Dict) {
40 | final c.Dict dict = (c.Dict) res;
41 | if ((dict.x instanceof c.Flip) && (dict.y instanceof c.Flip)) {
42 | final c.Flip key = (c.Flip) dict.x;
43 | final c.Flip data = (c.Flip) dict.y;
44 | return new FlipFlipResult("", key, data);
45 | }
46 | }
47 | if (res instanceof Object[]) {
48 | final Object[] oa = (Object[]) res;
49 | if ((oa.length == 2) && (oa[0] instanceof String) && (oa[1] instanceof c.Flip)) {
50 | final String table = (String) oa[0];
51 | final c.Flip flip = (c.Flip) oa[1];
52 | return new FlipResult(table, flip);
53 | } else if ((oa.length == 3) && (oa[1] instanceof String) && (oa[2] instanceof c.Flip)) {
54 | final String table = (String) oa[1];
55 | final c.Flip flip = (c.Flip) oa[2];
56 | return new FlipResult(table, flip);
57 | } else {
58 | return new ListResult