├── .gitignore
├── LICENSE
├── README.md
├── ebean-ignite-config.xml
├── hazelcast-client.xml
├── logback1.xml
├── logback2.xml
├── node1-ebean.properties
├── node2-ebean.properties
├── pom.xml
├── src
├── main
│ ├── java
│ │ └── org
│ │ │ └── example
│ │ │ ├── domain
│ │ │ ├── Address.kt
│ │ │ ├── BaseModel.kt
│ │ │ ├── Contact.kt
│ │ │ ├── Country.kt
│ │ │ ├── Customer.kt
│ │ │ ├── Order.kt
│ │ │ ├── OrderDetail.kt
│ │ │ ├── Product.kt
│ │ │ ├── finder
│ │ │ │ ├── AddressFinder.java
│ │ │ │ ├── ContactFinder.java
│ │ │ │ ├── CountryFinder.java
│ │ │ │ ├── CustomerFinder.java
│ │ │ │ ├── OrderDetailFinder.java
│ │ │ │ ├── OrderFinder.java
│ │ │ │ └── ProductFinder.java
│ │ │ └── query
│ │ │ │ ├── QAddress.java
│ │ │ │ ├── QContact.java
│ │ │ │ ├── QCountry.java
│ │ │ │ ├── QCustomer.java
│ │ │ │ ├── QOrder.java
│ │ │ │ ├── QOrderDetail.java
│ │ │ │ ├── QProduct.java
│ │ │ │ └── assoc
│ │ │ │ ├── QAssocAddress.java
│ │ │ │ ├── QAssocContact.java
│ │ │ │ ├── QAssocCountry.java
│ │ │ │ ├── QAssocCustomer.java
│ │ │ │ ├── QAssocOrder.java
│ │ │ │ ├── QAssocOrderDetail.java
│ │ │ │ └── QAssocProduct.java
│ │ │ ├── extension
│ │ │ └── Extension.kt
│ │ │ ├── module
│ │ │ ├── DbModule.kt
│ │ │ └── EbeanServerProvider.kt
│ │ │ ├── service
│ │ │ ├── LoadExampleData.kt
│ │ │ └── MetricService.kt
│ │ │ └── web
│ │ │ ├── BeanValidationException.kt
│ │ │ ├── ObjectMapperResolver.java
│ │ │ ├── api
│ │ │ ├── BaseResource.kt
│ │ │ ├── CountryResource.kt
│ │ │ ├── CustomerResource.kt
│ │ │ └── HelloResource.kt
│ │ │ └── module
│ │ │ └── WebModule.kt
│ ├── resources
│ │ ├── META-INF
│ │ │ └── ebean-typequery.mf
│ │ ├── dbmigration
│ │ │ └── model
│ │ │ │ └── 1.0__initial.model.xml
│ │ ├── ebean.properties
│ │ └── elastic-mapping
│ │ │ ├── country_v1.mapping.json
│ │ │ ├── customer_v1.mapping.json
│ │ │ ├── order_v1.mapping.json
│ │ │ └── product_v1.mapping.json
│ └── webapp
│ │ ├── WEB-INF
│ │ └── web.xml
│ │ ├── assets
│ │ └── placeholder.html
│ │ ├── metric-listen.html
│ │ └── websocket-test.html
└── test
│ ├── java
│ ├── main
│ │ ├── JavaMain.java
│ │ ├── MainDbMigration.kt
│ │ ├── MainQueryBeanGenerator.kt
│ │ ├── RunApp.kt
│ │ └── RunLoad.kt
│ └── org
│ │ └── example
│ │ ├── domain
│ │ └── BigLoad.kt
│ │ └── service
│ │ └── LoadExampleDataTest.kt
│ └── resources
│ ├── logback-test.xml
│ └── test-ebean.properties
├── start1.sh
└── start2.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | *.autofetch
2 | *.sql
3 | *.orig
4 | .classpath
5 | .project
6 | .settings/
7 | target/
8 | logs/
9 | log/
10 | ebean-autotune.xml
11 | ebean-profiling*.xml
12 |
13 | # Intellij project files
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # JRebel config
20 | rebel.xml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # example-kotlin-web
2 | Kotlin, Guice, RestEasy, JAX-RS, Ebean runnable war example application
3 |
4 | # Main's
5 |
6 | `src/test/main/RunApp` ... runs webapp using Jetty on port 9090
7 |
8 | `src/test/main/MainDbMigration` ... runs DB migration without offline (using EbeanServer in offline mode, no DB connection required)
9 |
10 | `src/test/main/MainQueryBeanGenerator` ... generates "Query Beans", because the entity beans are written in Kotlin (not java) then we can't use the java annotation processor (yet).
11 |
12 |
13 | # Guice Modules
14 | - org/example/module/DbModule
15 | - org/example/web/module/WebModule
16 |
17 | # Maven
18 |
19 | mvn clean package ... to build the runnable war in /target
20 |
21 | # Maven tiles
22 |
23 | Uses tiles for Ebean enhancement, Java compile, Kotlin compile
24 |
--------------------------------------------------------------------------------
/ebean-ignite-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 0
6 | PARTITIONED
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/hazelcast-client.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | 1000
9 | LRU
10 |
11 |
12 |
13 | 5000
14 | LRU
15 |
16 |
17 |
--------------------------------------------------------------------------------
/logback1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/logback2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/node1-ebean.properties:
--------------------------------------------------------------------------------
1 |
2 | #ebean.cluster.active=true
3 | #ebean.cluster.localHostPort=127.0.0.1:9942
4 | #ebean.cluster.members=127.0.0.1:9942,127.0.0.1:9943
5 |
6 | datasource.default=db
7 |
8 | datasource.db.username=kt
9 | datasource.db.password=kt
10 | datasource.db.databaseUrl=jdbc:postgresql://127.0.0.1:5432/kt
11 | datasource.db.databaseDriver=org.postgresql.Driver
12 |
13 | #ebean.docstore.url=http://127.0.0.1:9200
14 | #ebean.docstore.active=true
15 | #ebean.docstore.generateMapping=true
16 | #ebean.docstore.create=true
--------------------------------------------------------------------------------
/node2-ebean.properties:
--------------------------------------------------------------------------------
1 |
2 | #ebean.cluster.active=true
3 | #ebean.cluster.localHostPort=127.0.0.1:9943
4 | #ebean.cluster.members=127.0.0.1:9942,127.0.0.1:9943
5 |
6 | datasource.default=db
7 |
8 | datasource.db.username=kt
9 | datasource.db.password=kt
10 | datasource.db.databaseUrl=jdbc:postgresql://127.0.0.1:5432/kt
11 | datasource.db.databaseDriver=org.postgresql.Driver
12 |
13 |
14 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | org.avaje.jetty
9 | runnable-war
10 | 2.2.1
11 |
12 |
13 | org.example
14 | example-kotlin-web
15 | 1.1-SNAPSHOT
16 | war
17 |
18 |
19 | 1.8
20 | 1.0.1
21 | debug=0
22 | 2.1.1
23 | 4.9.1
24 |
25 |
26 |
27 |
28 |
29 |
30 | org.avaje.resteasy
31 | avaje-resteasy-guice
32 | 1.1.2
33 |
34 |
35 |
36 | org.avaje.ebeanorm
37 | avaje-ebeanorm-jackson
38 | 6.12.1
39 |
40 |
41 |
42 | org.jboss.resteasy
43 | resteasy-servlet-initializer
44 | 3.0.16.Final
45 |
46 |
47 |
48 | org.jboss.resteasy
49 | resteasy-guice
50 | 3.0.16.Final
51 |
52 |
53 |
54 | org.jboss.resteasy
55 | resteasy-jackson2-provider
56 | 3.0.16.Final
57 |
58 |
59 |
60 | net.java.dev.jna
61 | jna
62 | 4.2.1
63 |
64 |
65 |
66 | com.google.guava
67 | guava
68 | 18.0
69 |
70 |
71 |
72 | com.google.inject
73 | guice
74 | 4.0
75 |
76 |
77 |
78 | org.slf4j
79 | slf4j-api
80 | 1.7.20
81 |
82 |
83 |
84 | org.jetbrains.kotlin
85 | kotlin-stdlib
86 | ${kotlin.version}
87 |
88 |
89 |
90 | org.jetbrains.kotlin
91 | kotlin-reflect
92 | ${kotlin.version}
93 |
94 |
95 |
96 | org.avaje.metric
97 | avaje-metric-core
98 | 4.4.2
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | org.avaje.ebeanorm
109 | avaje-ebeanorm-ignite
110 | 1.2.1-SNAPSHOT
111 |
112 |
113 |
114 | org.avaje.ebeanorm
115 | avaje-ebeanorm-elastic
116 | 1.1.3
117 |
118 |
119 |
120 | org.avaje.ebeanorm
121 | avaje-ebeanorm
122 | 7.9.1-SNAPSHOT
123 |
124 |
125 |
126 | org.avaje.ebeanorm
127 | avaje-ebeanorm-querybean
128 | 7.2.1
129 |
130 |
131 |
132 | org.avaje.ebeanorm
133 | querybean-generator
134 | 2.1.1
135 | provided
136 |
137 |
138 |
139 | javax.validation
140 | validation-api
141 | 1.0.0.GA
142 |
143 |
144 |
145 | org.postgresql
146 | postgresql
147 | 9.4-1202-jdbc41
148 |
149 |
150 |
151 | org.avaje.ebeanorm
152 | avaje-ebeanorm-typequery-generator
153 | 1.5.3
154 | test
155 |
156 |
157 |
158 | org.avaje.composite
159 | composite-testing
160 | 2.1
161 | pom
162 | test
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | io.repaint.maven
172 | tiles-maven-plugin
173 | 2.8
174 | true
175 |
176 |
177 | org.avaje.tile:java-compile:1.1
178 | org.avaje.tile:kotlin-compile:1.1
179 | org.avaje.tile:ebean-enhancement:1.2
180 |
181 |
182 |
183 |
184 |
185 | org.avaje.metric
186 | enhance-maven-plugin
187 | 4.3.1
188 |
189 |
190 | main
191 | process-classes
192 |
193 |
194 | org.example.**
195 | debug=1
196 |
197 |
198 | enhance
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/Address.kt:
--------------------------------------------------------------------------------
1 | package org.example.domain;
2 |
3 | import org.example.domain.finder.AddressFinder
4 | import javax.persistence.Entity
5 | import javax.persistence.ManyToOne
6 | import javax.persistence.Table
7 | import javax.validation.constraints.Size
8 |
9 | /**
10 | * Address entity bean.
11 | */
12 | @Entity
13 | @Table(name = "o_address")
14 | class Address : BaseModel() {
15 |
16 | @Size(max = 100)
17 | var line1: String? = null;
18 |
19 | @Size(max = 100)
20 | var line2: String? = null;
21 |
22 | @Size(max = 100)
23 | var city: String? = null;
24 |
25 | @ManyToOne(optional = false)
26 | var country: Country? = null;
27 |
28 | companion object : AddressFinder() {}
29 |
30 | }
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/BaseModel.kt:
--------------------------------------------------------------------------------
1 | package org.example.domain;
2 |
3 | import com.avaje.ebean.Model
4 | import com.avaje.ebean.annotation.WhenCreated
5 | import com.avaje.ebean.annotation.WhenModified
6 | import java.sql.Timestamp;
7 |
8 | import javax.persistence.Id;
9 | import javax.persistence.MappedSuperclass;
10 | import javax.persistence.Version;
11 |
12 | /**
13 | * Base domain object with Id, version, whenCreated and whenUpdated.
14 | *
15 | *
16 | * Extending Model to enable the 'active record' style.
17 | *
18 | *
19 | * whenCreated and whenUpdated are generally useful for maintaining external search services (like
20 | * elasticsearch) and audit.
21 | */
22 | @MappedSuperclass
23 | abstract class BaseModel : Model() {
24 |
25 | @Id
26 | var id: Long? = null
27 |
28 | @Version
29 | var version: Long? = null
30 |
31 | @WhenCreated
32 | var whenCreated: Timestamp? = null
33 |
34 | @WhenModified
35 | var whenModified: Timestamp? = null
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/Contact.kt:
--------------------------------------------------------------------------------
1 | package org.example.domain;
2 |
3 | import org.example.domain.finder.ContactFinder
4 | import javax.persistence.Entity
5 | import javax.persistence.ManyToOne
6 | import javax.persistence.Table
7 | import javax.validation.constraints.NotNull
8 | import javax.validation.constraints.Size
9 |
10 | /**
11 | * Contact entity bean.
12 | */
13 | @Entity
14 | @Table(name = "be_contact")
15 | class Contact() : BaseModel() {
16 |
17 | @Size(max = 50)
18 | var firstName: String? = null
19 |
20 | @Size(max = 50)
21 | var lastName: String? = null
22 |
23 | @Size(max = 200)
24 | var email: String? = null;
25 |
26 | @Size(max = 20)
27 | var phone: String? = null;
28 |
29 | @NotNull
30 | @ManyToOne(optional = false)
31 | var customer: Customer? = null;
32 |
33 | /**
34 | * Construct with firstName and lastName.
35 | */
36 | constructor(firstName: String, lastName: String) : this() {
37 | this.firstName = firstName;
38 | this.lastName = lastName;
39 | }
40 |
41 | companion object : ContactFinder() {}
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/Country.kt:
--------------------------------------------------------------------------------
1 | package org.example.domain;
2 |
3 | import com.avaje.ebean.Model
4 | import com.avaje.ebean.annotation.Cache
5 | import com.avaje.ebean.annotation.DocStore
6 | import org.example.domain.finder.CountryFinder
7 | import javax.persistence.Entity
8 | import javax.persistence.Id
9 | import javax.persistence.Table
10 | import javax.validation.constraints.Size
11 |
12 | /**
13 | * Country entity bean.
14 | *
15 | * Uses constructor with properties having default values.
16 | */
17 | @DocStore
18 | @Cache(enableQueryCache=true)
19 | @Entity
20 | @Table(name = "o_country")
21 | class Country(
22 |
23 | @Id @Size(max = 2)
24 | var code: String,
25 |
26 | @Size(max = 60)
27 | var name: String
28 |
29 | ) : Model() {
30 |
31 | override fun toString(): String {
32 | return "code:$code name:$name";
33 | }
34 |
35 | /**
36 | * Find helper singleton.
37 | */
38 | companion object : CountryFinder() {}
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/Customer.kt:
--------------------------------------------------------------------------------
1 | package org.example.domain;
2 |
3 | import com.avaje.ebean.annotation.Cache
4 | import com.avaje.ebean.annotation.DocStore
5 | import com.avaje.ebean.annotation.SoftDelete
6 | import org.example.domain.finder.CustomerFinder
7 | import java.util.*
8 | import javax.persistence.*
9 | import javax.validation.constraints.NotNull
10 | import javax.validation.constraints.Size
11 |
12 | /**
13 | * Customer entity bean.
14 | */
15 | @DocStore
16 | @Cache(enableQueryCache = true)
17 | @Entity
18 | @Table(name = "be_customer")
19 | class Customer(
20 |
21 | // name is required property
22 | @NotNull @Size(max = 100)
23 | val name: String,
24 |
25 | @SoftDelete
26 | var deleted: Boolean = false,
27 |
28 | var registered: Date? = null,
29 |
30 | @Size(max = 1000)
31 | var comments: String? = null,
32 |
33 | @ManyToOne(cascade = arrayOf(CascadeType.ALL))
34 | var billingAddress: Address? = null,
35 |
36 | @ManyToOne(cascade = arrayOf(CascadeType.ALL))
37 | var shippingAddress: Address? = null,
38 |
39 | @OneToMany(mappedBy = "customer", cascade = arrayOf(CascadeType.PERSIST))
40 | var contacts: MutableList = ArrayList()
41 |
42 | ) : BaseModel() {
43 |
44 | companion object find : CustomerFinder() {}
45 |
46 | override fun toString(): String {
47 | return "customer(id:$id name:$name)";
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/Order.kt:
--------------------------------------------------------------------------------
1 | package org.example.domain;
2 |
3 | import com.avaje.ebean.annotation.DocCode
4 | import com.avaje.ebean.annotation.DocEmbedded
5 | import com.avaje.ebean.annotation.DocStore
6 | import org.example.domain.finder.OrderFinder
7 | import java.sql.Date
8 | import java.time.LocalDate
9 | import java.util.*
10 | import javax.persistence.*
11 | import javax.validation.constraints.NotNull
12 |
13 | /**
14 | * Order entity bean.
15 | */
16 | @DocStore
17 | @Entity
18 | @Table(name = "o_order")
19 | class Order : BaseModel() {
20 |
21 | companion object find : OrderFinder() {}
22 |
23 | enum class Status {
24 | NEW,
25 | APPROVED,
26 | SHIPPED,
27 | COMPLETE
28 | }
29 |
30 | @DocCode
31 | var status: Status = Status.NEW;
32 |
33 | var orderDate: LocalDate? = null;
34 |
35 | var shipDate: LocalDate? = null;
36 |
37 | @DocEmbedded(doc = "id,name")
38 | @ManyToOne @NotNull
39 | var customer: Customer? = null;
40 |
41 | @ManyToOne
42 | var shippingAddress: Address? = null;
43 |
44 | @DocEmbedded(doc = "*,product(id,sku,name)")
45 | @OneToMany(mappedBy = "order", cascade = arrayOf(CascadeType.PERSIST))
46 | @OrderBy("id asc")
47 | var details: MutableList = ArrayList();
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/OrderDetail.kt:
--------------------------------------------------------------------------------
1 | package org.example.domain;
2 |
3 | import com.avaje.ebean.Model
4 | import javax.persistence.Entity;
5 | import javax.persistence.ManyToOne;
6 | import javax.persistence.Table;
7 | import javax.validation.constraints.NotNull
8 |
9 | /**
10 | * Order Detail entity bean.
11 | */
12 | @Entity
13 | @Table(name = "o_order_detail")
14 | class OrderDetail() : BaseModel() {
15 |
16 | companion object find: Model.Find() {}
17 |
18 | /**
19 | * Construct with product, order quantity and unit price.
20 | */
21 | constructor(product: Product, orderQty: Int, unitPrice: Double) : this() {
22 | this.product = product
23 | this.orderQty = orderQty
24 | this.unitPrice = unitPrice
25 | }
26 |
27 | /**
28 | * The owning order - should be not null really.
29 | */
30 | @NotNull
31 | @ManyToOne
32 | var order: Order? = null;
33 |
34 | var orderQty: Int? = null;
35 |
36 | var shipQty: Int? = null;
37 |
38 | var unitPrice: Double? = null;
39 |
40 | @NotNull
41 | @ManyToOne
42 | var product: Product? = null;
43 |
44 | /**
45 | * Helper method to set some properties.
46 | */
47 | fun set(product: Product, orderQty: Int, unitPrice: Double) {
48 | this.product = product;
49 | this.unitPrice = unitPrice
50 | this.orderQty = orderQty
51 | }
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/Product.kt:
--------------------------------------------------------------------------------
1 | package org.example.domain;
2 |
3 | import com.avaje.ebean.Model
4 | import com.avaje.ebean.annotation.DocStore
5 | import javax.persistence.Entity;
6 | import javax.persistence.Table;
7 | import javax.validation.constraints.NotNull
8 | import javax.validation.constraints.Size;
9 |
10 |
11 | /**
12 | * Product entity bean.
13 | */
14 | @DocStore
15 | @Entity
16 | @Table(name = "o_product")
17 | class Product (
18 |
19 | @NotNull @Size(max = 20)
20 | var sku: String = "",
21 |
22 | @NotNull @Size(max = 100)
23 | var name: String = ""
24 |
25 | ) : BaseModel() {
26 |
27 | companion object : Model.Find() {}
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/finder/AddressFinder.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.finder;
2 |
3 | import com.avaje.ebean.Finder;
4 | import org.example.domain.Address;
5 | import org.example.domain.query.QAddress;
6 |
7 | public class AddressFinder extends Finder {
8 |
9 | /**
10 | * Construct using the default EbeanServer.
11 | */
12 | public AddressFinder() {
13 | super(Address.class);
14 | }
15 |
16 | /**
17 | * Construct with a given EbeanServer.
18 | */
19 | public AddressFinder(String serverName) {
20 | super(Address.class, serverName);
21 | }
22 |
23 | /**
24 | * Start a new typed query.
25 | */
26 | protected QAddress where() {
27 | return new QAddress(db());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/finder/ContactFinder.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.finder;
2 |
3 | import com.avaje.ebean.Finder;
4 | import org.example.domain.Contact;
5 | import org.example.domain.query.QContact;
6 |
7 | public class ContactFinder extends Finder {
8 |
9 | /**
10 | * Construct using the default EbeanServer.
11 | */
12 | public ContactFinder() {
13 | super(Contact.class);
14 | }
15 |
16 | /**
17 | * Construct with a given EbeanServer.
18 | */
19 | public ContactFinder(String serverName) {
20 | super(Contact.class, serverName);
21 | }
22 |
23 | /**
24 | * Start a new typed query.
25 | */
26 | protected QContact where() {
27 | return new QContact(db());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/finder/CountryFinder.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.finder;
2 |
3 | import com.avaje.ebean.Finder;
4 | import org.example.domain.Country;
5 | import org.example.domain.query.QCountry;
6 |
7 | public class CountryFinder extends Finder {
8 |
9 | /**
10 | * Construct using the default EbeanServer.
11 | */
12 | public CountryFinder() {
13 | super(Country.class);
14 | }
15 |
16 | /**
17 | * Construct with a given EbeanServer.
18 | */
19 | public CountryFinder(String serverName) {
20 | super(Country.class, serverName);
21 | }
22 |
23 | /**
24 | * Start a new typed query.
25 | */
26 | public QCountry where() {
27 | return new QCountry(db());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/finder/CustomerFinder.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.finder;
2 |
3 | import com.avaje.ebean.Finder;
4 | import org.example.domain.Customer;
5 | import org.example.domain.query.QCustomer;
6 |
7 | public class CustomerFinder extends Finder {
8 |
9 | /**
10 | * Construct using the default EbeanServer.
11 | */
12 | public CustomerFinder() {
13 | super(Customer.class);
14 | }
15 |
16 | /**
17 | * Construct with a given EbeanServer.
18 | */
19 | public CustomerFinder(String serverName) {
20 | super(Customer.class, serverName);
21 | }
22 |
23 | /**
24 | * Start a new typed query.
25 | */
26 | public QCustomer where() {
27 | return new QCustomer(db());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/finder/OrderDetailFinder.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.finder;
2 |
3 | import com.avaje.ebean.Finder;
4 | import org.example.domain.OrderDetail;
5 | import org.example.domain.query.QOrderDetail;
6 |
7 | public class OrderDetailFinder extends Finder {
8 |
9 | /**
10 | * Construct using the default EbeanServer.
11 | */
12 | public OrderDetailFinder() {
13 | super(OrderDetail.class);
14 | }
15 |
16 | /**
17 | * Construct with a given EbeanServer.
18 | */
19 | public OrderDetailFinder(String serverName) {
20 | super(OrderDetail.class, serverName);
21 | }
22 |
23 | /**
24 | * Start a new typed query.
25 | */
26 | protected QOrderDetail where() {
27 | return new QOrderDetail(db());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/finder/OrderFinder.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.finder;
2 |
3 | import com.avaje.ebean.Finder;
4 | import org.example.domain.Order;
5 | import org.example.domain.query.QOrder;
6 |
7 | public class OrderFinder extends Finder {
8 |
9 | /**
10 | * Construct using the default EbeanServer.
11 | */
12 | public OrderFinder() {
13 | super(Order.class);
14 | }
15 |
16 | /**
17 | * Construct with a given EbeanServer.
18 | */
19 | public OrderFinder(String serverName) {
20 | super(Order.class, serverName);
21 | }
22 |
23 | /**
24 | * Start a new typed query.
25 | */
26 | public QOrder where() {
27 | return new QOrder(db());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/finder/ProductFinder.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.finder;
2 |
3 | import com.avaje.ebean.Finder;
4 | import org.example.domain.Product;
5 | import org.example.domain.query.QProduct;
6 |
7 | public class ProductFinder extends Finder {
8 |
9 | /**
10 | * Construct using the default EbeanServer.
11 | */
12 | public ProductFinder() {
13 | super(Product.class);
14 | }
15 |
16 | /**
17 | * Construct with a given EbeanServer.
18 | */
19 | public ProductFinder(String serverName) {
20 | super(Product.class, serverName);
21 | }
22 |
23 | /**
24 | * Start a new typed query.
25 | */
26 | protected QProduct where() {
27 | return new QProduct(db());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/QAddress.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query;
2 |
3 | import com.avaje.ebean.EbeanServer;
4 | import org.avaje.ebean.typequery.PLong;
5 | import org.avaje.ebean.typequery.PString;
6 | import org.avaje.ebean.typequery.PTimestamp;
7 | import org.avaje.ebean.typequery.TQRootBean;
8 | import org.avaje.ebean.typequery.TypeQueryBean;
9 | import org.example.domain.Address;
10 | import org.example.domain.query.assoc.QAssocCountry;
11 |
12 | /**
13 | * Query bean for Address.
14 | *
15 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
16 | */
17 | @TypeQueryBean
18 | public class QAddress extends TQRootBean {
19 |
20 | private static final QAddress _alias = new QAddress(true);
21 |
22 | /**
23 | * Return the shared 'Alias' instance used to provide properties to
24 | * select()
and fetch()
25 | */
26 | public static QAddress alias() {
27 | return _alias;
28 | }
29 |
30 | public PLong id;
31 | public PLong version;
32 | public PTimestamp whenCreated;
33 | public PTimestamp whenModified;
34 | public PString line1;
35 | public PString line2;
36 | public PString city;
37 | public QAssocCountry country;
38 |
39 |
40 | /**
41 | * Construct with a given EbeanServer.
42 | */
43 | public QAddress(EbeanServer server) {
44 | super(Address.class, server);
45 | }
46 |
47 | /**
48 | * Construct using the default EbeanServer.
49 | */
50 | public QAddress() {
51 | super(Address.class);
52 | }
53 |
54 | /**
55 | * Construct for Alias.
56 | */
57 | private QAddress(boolean dummy) {
58 | super(dummy);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/QContact.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query;
2 |
3 | import com.avaje.ebean.EbeanServer;
4 | import org.avaje.ebean.typequery.PLong;
5 | import org.avaje.ebean.typequery.PString;
6 | import org.avaje.ebean.typequery.PTimestamp;
7 | import org.avaje.ebean.typequery.TQRootBean;
8 | import org.avaje.ebean.typequery.TypeQueryBean;
9 | import org.example.domain.Contact;
10 | import org.example.domain.query.assoc.QAssocCustomer;
11 |
12 | /**
13 | * Query bean for Contact.
14 | *
15 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
16 | */
17 | @TypeQueryBean
18 | public class QContact extends TQRootBean {
19 |
20 | private static final QContact _alias = new QContact(true);
21 |
22 | /**
23 | * Return the shared 'Alias' instance used to provide properties to
24 | * select()
and fetch()
25 | */
26 | public static QContact alias() {
27 | return _alias;
28 | }
29 |
30 | public PLong id;
31 | public PLong version;
32 | public PTimestamp whenCreated;
33 | public PTimestamp whenModified;
34 | public PString firstName;
35 | public PString lastName;
36 | public PString email;
37 | public PString phone;
38 | public QAssocCustomer customer;
39 |
40 |
41 | /**
42 | * Construct with a given EbeanServer.
43 | */
44 | public QContact(EbeanServer server) {
45 | super(Contact.class, server);
46 | }
47 |
48 | /**
49 | * Construct using the default EbeanServer.
50 | */
51 | public QContact() {
52 | super(Contact.class);
53 | }
54 |
55 | /**
56 | * Construct for Alias.
57 | */
58 | private QContact(boolean dummy) {
59 | super(dummy);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/QCountry.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query;
2 |
3 | import com.avaje.ebean.EbeanServer;
4 | import org.avaje.ebean.typequery.PString;
5 | import org.avaje.ebean.typequery.TQRootBean;
6 | import org.avaje.ebean.typequery.TypeQueryBean;
7 | import org.example.domain.Country;
8 |
9 | /**
10 | * Query bean for Country.
11 | *
12 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
13 | */
14 | @TypeQueryBean
15 | public class QCountry extends TQRootBean {
16 |
17 | private static final QCountry _alias = new QCountry(true);
18 |
19 | /**
20 | * Return the shared 'Alias' instance used to provide properties to
21 | * select()
and fetch()
22 | */
23 | public static QCountry alias() {
24 | return _alias;
25 | }
26 |
27 | public PString code;
28 | public PString name;
29 |
30 |
31 | /**
32 | * Construct with a given EbeanServer.
33 | */
34 | public QCountry(EbeanServer server) {
35 | super(Country.class, server);
36 | }
37 |
38 | /**
39 | * Construct using the default EbeanServer.
40 | */
41 | public QCountry() {
42 | super(Country.class);
43 | }
44 |
45 | /**
46 | * Construct for Alias.
47 | */
48 | private QCountry(boolean dummy) {
49 | super(dummy);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/QCustomer.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query;
2 |
3 | import com.avaje.ebean.EbeanServer;
4 | import org.avaje.ebean.typequery.PBoolean;
5 | import org.avaje.ebean.typequery.PLong;
6 | import org.avaje.ebean.typequery.PString;
7 | import org.avaje.ebean.typequery.PTimestamp;
8 | import org.avaje.ebean.typequery.PUtilDate;
9 | import org.avaje.ebean.typequery.TQRootBean;
10 | import org.avaje.ebean.typequery.TypeQueryBean;
11 | import org.example.domain.Customer;
12 | import org.example.domain.query.assoc.QAssocAddress;
13 | import org.example.domain.query.assoc.QAssocContact;
14 |
15 | /**
16 | * Query bean for Customer.
17 | *
18 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
19 | */
20 | @TypeQueryBean
21 | public class QCustomer extends TQRootBean {
22 |
23 | private static final QCustomer _alias = new QCustomer(true);
24 |
25 | /**
26 | * Return the shared 'Alias' instance used to provide properties to
27 | * select()
and fetch()
28 | */
29 | public static QCustomer alias() {
30 | return _alias;
31 | }
32 |
33 | public PLong id;
34 | public PLong version;
35 | public PTimestamp whenCreated;
36 | public PTimestamp whenModified;
37 | public PBoolean inactive;
38 | public PString name;
39 | public PUtilDate registered;
40 | public PString comments;
41 | public QAssocAddress billingAddress;
42 | public QAssocAddress shippingAddress;
43 | public QAssocContact contacts;
44 |
45 |
46 | /**
47 | * Construct with a given EbeanServer.
48 | */
49 | public QCustomer(EbeanServer server) {
50 | super(Customer.class, server);
51 | }
52 |
53 | /**
54 | * Construct using the default EbeanServer.
55 | */
56 | public QCustomer() {
57 | super(Customer.class);
58 | }
59 |
60 | /**
61 | * Construct for Alias.
62 | */
63 | private QCustomer(boolean dummy) {
64 | super(dummy);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/QOrder.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query;
2 |
3 | import com.avaje.ebean.EbeanServer;
4 | import org.avaje.ebean.typequery.PEnum;
5 | import org.avaje.ebean.typequery.PLocalDate;
6 | import org.avaje.ebean.typequery.PLong;
7 | import org.avaje.ebean.typequery.PSqlDate;
8 | import org.avaje.ebean.typequery.PTimestamp;
9 | import org.avaje.ebean.typequery.TQRootBean;
10 | import org.avaje.ebean.typequery.TypeQueryBean;
11 | import org.example.domain.Order;
12 | import org.example.domain.Order.Status;
13 | import org.example.domain.query.assoc.QAssocAddress;
14 | import org.example.domain.query.assoc.QAssocCustomer;
15 | import org.example.domain.query.assoc.QAssocOrderDetail;
16 |
17 | /**
18 | * Query bean for Order.
19 | *
20 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
21 | */
22 | @TypeQueryBean
23 | public class QOrder extends TQRootBean {
24 |
25 | private static final QOrder _alias = new QOrder(true);
26 |
27 | /**
28 | * Return the shared 'Alias' instance used to provide properties to
29 | * select()
and fetch()
30 | */
31 | public static QOrder alias() {
32 | return _alias;
33 | }
34 |
35 | public PLong id;
36 | public PLong version;
37 | public PTimestamp whenCreated;
38 | public PTimestamp whenModified;
39 | public PEnum status;
40 | public PLocalDate orderDate;
41 | public PLocalDate shipDate;
42 | public QAssocCustomer customer;
43 | public QAssocAddress shippingAddress;
44 | public QAssocOrderDetail details;
45 |
46 |
47 | /**
48 | * Construct with a given EbeanServer.
49 | */
50 | public QOrder(EbeanServer server) {
51 | super(Order.class, server);
52 | }
53 |
54 | /**
55 | * Construct using the default EbeanServer.
56 | */
57 | public QOrder() {
58 | super(Order.class);
59 | }
60 |
61 | /**
62 | * Construct for Alias.
63 | */
64 | private QOrder(boolean dummy) {
65 | super(dummy);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/QOrderDetail.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query;
2 |
3 | import com.avaje.ebean.EbeanServer;
4 | import org.avaje.ebean.typequery.PDouble;
5 | import org.avaje.ebean.typequery.PInteger;
6 | import org.avaje.ebean.typequery.PLong;
7 | import org.avaje.ebean.typequery.PTimestamp;
8 | import org.avaje.ebean.typequery.TQRootBean;
9 | import org.avaje.ebean.typequery.TypeQueryBean;
10 | import org.example.domain.OrderDetail;
11 | import org.example.domain.query.assoc.QAssocOrder;
12 | import org.example.domain.query.assoc.QAssocProduct;
13 |
14 | /**
15 | * Query bean for OrderDetail.
16 | *
17 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
18 | */
19 | @TypeQueryBean
20 | public class QOrderDetail extends TQRootBean {
21 |
22 | private static final QOrderDetail _alias = new QOrderDetail(true);
23 |
24 | /**
25 | * Return the shared 'Alias' instance used to provide properties to
26 | * select()
and fetch()
27 | */
28 | public static QOrderDetail alias() {
29 | return _alias;
30 | }
31 |
32 | public PLong id;
33 | public PLong version;
34 | public PTimestamp whenCreated;
35 | public PTimestamp whenModified;
36 | public QAssocOrder order;
37 | public PInteger orderQty;
38 | public PInteger shipQty;
39 | public PDouble unitPrice;
40 | public QAssocProduct product;
41 |
42 |
43 | /**
44 | * Construct with a given EbeanServer.
45 | */
46 | public QOrderDetail(EbeanServer server) {
47 | super(OrderDetail.class, server);
48 | }
49 |
50 | /**
51 | * Construct using the default EbeanServer.
52 | */
53 | public QOrderDetail() {
54 | super(OrderDetail.class);
55 | }
56 |
57 | /**
58 | * Construct for Alias.
59 | */
60 | private QOrderDetail(boolean dummy) {
61 | super(dummy);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/QProduct.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query;
2 |
3 | import com.avaje.ebean.EbeanServer;
4 | import org.avaje.ebean.typequery.PLong;
5 | import org.avaje.ebean.typequery.PString;
6 | import org.avaje.ebean.typequery.PTimestamp;
7 | import org.avaje.ebean.typequery.TQRootBean;
8 | import org.avaje.ebean.typequery.TypeQueryBean;
9 | import org.example.domain.Product;
10 |
11 | /**
12 | * Query bean for Product.
13 | *
14 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
15 | */
16 | @TypeQueryBean
17 | public class QProduct extends TQRootBean {
18 |
19 | private static final QProduct _alias = new QProduct(true);
20 |
21 | /**
22 | * Return the shared 'Alias' instance used to provide properties to
23 | * select()
and fetch()
24 | */
25 | public static QProduct alias() {
26 | return _alias;
27 | }
28 |
29 | public PLong id;
30 | public PLong version;
31 | public PTimestamp whenCreated;
32 | public PTimestamp whenModified;
33 | public PString sku;
34 | public PString name;
35 |
36 |
37 | /**
38 | * Construct with a given EbeanServer.
39 | */
40 | public QProduct(EbeanServer server) {
41 | super(Product.class, server);
42 | }
43 |
44 | /**
45 | * Construct using the default EbeanServer.
46 | */
47 | public QProduct() {
48 | super(Product.class);
49 | }
50 |
51 | /**
52 | * Construct for Alias.
53 | */
54 | private QProduct(boolean dummy) {
55 | super(dummy);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/assoc/QAssocAddress.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query.assoc;
2 |
3 | import org.avaje.ebean.typequery.PLong;
4 | import org.avaje.ebean.typequery.PString;
5 | import org.avaje.ebean.typequery.PTimestamp;
6 | import org.avaje.ebean.typequery.TQAssocBean;
7 | import org.avaje.ebean.typequery.TQProperty;
8 | import org.avaje.ebean.typequery.TypeQueryBean;
9 | import org.example.domain.Address;
10 | import org.example.domain.query.QAddress;
11 |
12 | /**
13 | * Association query bean for AssocAddress.
14 | *
15 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
16 | */
17 | @TypeQueryBean
18 | public class QAssocAddress extends TQAssocBean {
19 |
20 | public PLong id;
21 | public PLong version;
22 | public PTimestamp whenCreated;
23 | public PTimestamp whenModified;
24 | public PString line1;
25 | public PString line2;
26 | public PString city;
27 | public QAssocCountry country;
28 |
29 | /**
30 | * Eagerly fetch this association loading the specified properties.
31 | */
32 | @SafeVarargs
33 | public final R fetch(TQProperty... properties) {
34 | return fetchProperties(properties);
35 | }
36 |
37 | public QAssocAddress(String name, R root) {
38 | super(name, root);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/assoc/QAssocContact.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query.assoc;
2 |
3 | import org.avaje.ebean.typequery.PLong;
4 | import org.avaje.ebean.typequery.PString;
5 | import org.avaje.ebean.typequery.PTimestamp;
6 | import org.avaje.ebean.typequery.TQAssocBean;
7 | import org.avaje.ebean.typequery.TQProperty;
8 | import org.avaje.ebean.typequery.TypeQueryBean;
9 | import org.example.domain.Contact;
10 | import org.example.domain.query.QContact;
11 |
12 | /**
13 | * Association query bean for AssocContact.
14 | *
15 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
16 | */
17 | @TypeQueryBean
18 | public class QAssocContact extends TQAssocBean {
19 |
20 | public PLong id;
21 | public PLong version;
22 | public PTimestamp whenCreated;
23 | public PTimestamp whenModified;
24 | public PString firstName;
25 | public PString lastName;
26 | public PString email;
27 | public PString phone;
28 | public QAssocCustomer customer;
29 |
30 | /**
31 | * Eagerly fetch this association loading the specified properties.
32 | */
33 | @SafeVarargs
34 | public final R fetch(TQProperty... properties) {
35 | return fetchProperties(properties);
36 | }
37 |
38 | public QAssocContact(String name, R root) {
39 | super(name, root);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/assoc/QAssocCountry.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query.assoc;
2 |
3 | import org.avaje.ebean.typequery.PString;
4 | import org.avaje.ebean.typequery.TQAssocBean;
5 | import org.avaje.ebean.typequery.TQProperty;
6 | import org.avaje.ebean.typequery.TypeQueryBean;
7 | import org.example.domain.Country;
8 | import org.example.domain.query.QCountry;
9 |
10 | /**
11 | * Association query bean for AssocCountry.
12 | *
13 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
14 | */
15 | @TypeQueryBean
16 | public class QAssocCountry extends TQAssocBean {
17 |
18 | public PString code;
19 | public PString name;
20 |
21 | /**
22 | * Eagerly fetch this association loading the specified properties.
23 | */
24 | @SafeVarargs
25 | public final R fetch(TQProperty... properties) {
26 | return fetchProperties(properties);
27 | }
28 |
29 | public QAssocCountry(String name, R root) {
30 | super(name, root);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/assoc/QAssocCustomer.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query.assoc;
2 |
3 | import org.avaje.ebean.typequery.PBoolean;
4 | import org.avaje.ebean.typequery.PLong;
5 | import org.avaje.ebean.typequery.PString;
6 | import org.avaje.ebean.typequery.PTimestamp;
7 | import org.avaje.ebean.typequery.PUtilDate;
8 | import org.avaje.ebean.typequery.TQAssocBean;
9 | import org.avaje.ebean.typequery.TQProperty;
10 | import org.avaje.ebean.typequery.TypeQueryBean;
11 | import org.example.domain.Customer;
12 | import org.example.domain.query.QCustomer;
13 |
14 | /**
15 | * Association query bean for AssocCustomer.
16 | *
17 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
18 | */
19 | @TypeQueryBean
20 | public class QAssocCustomer extends TQAssocBean {
21 |
22 | public PLong id;
23 | public PLong version;
24 | public PTimestamp whenCreated;
25 | public PTimestamp whenModified;
26 | public PBoolean inactive;
27 | public PString name;
28 | public PUtilDate registered;
29 | public PString comments;
30 | public QAssocAddress billingAddress;
31 | public QAssocAddress shippingAddress;
32 | public QAssocContact contacts;
33 |
34 | /**
35 | * Eagerly fetch this association loading the specified properties.
36 | */
37 | @SafeVarargs
38 | public final R fetch(TQProperty... properties) {
39 | return fetchProperties(properties);
40 | }
41 |
42 | public QAssocCustomer(String name, R root) {
43 | super(name, root);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/assoc/QAssocOrder.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query.assoc;
2 |
3 | import org.avaje.ebean.typequery.PEnum;
4 | import org.avaje.ebean.typequery.PLong;
5 | import org.avaje.ebean.typequery.PSqlDate;
6 | import org.avaje.ebean.typequery.PTimestamp;
7 | import org.avaje.ebean.typequery.TQAssocBean;
8 | import org.avaje.ebean.typequery.TQProperty;
9 | import org.avaje.ebean.typequery.TypeQueryBean;
10 | import org.example.domain.Order;
11 | import org.example.domain.Order.Status;
12 | import org.example.domain.query.QOrder;
13 |
14 | /**
15 | * Association query bean for AssocOrder.
16 | *
17 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
18 | */
19 | @TypeQueryBean
20 | public class QAssocOrder extends TQAssocBean {
21 |
22 | public PLong id;
23 | public PLong version;
24 | public PTimestamp whenCreated;
25 | public PTimestamp whenModified;
26 | public PEnum status;
27 | public PSqlDate orderDate;
28 | public PSqlDate shipDate;
29 | public QAssocCustomer customer;
30 | public QAssocAddress shippingAddress;
31 | public QAssocOrderDetail details;
32 |
33 | /**
34 | * Eagerly fetch this association loading the specified properties.
35 | */
36 | @SafeVarargs
37 | public final R fetch(TQProperty... properties) {
38 | return fetchProperties(properties);
39 | }
40 |
41 | public QAssocOrder(String name, R root) {
42 | super(name, root);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/assoc/QAssocOrderDetail.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query.assoc;
2 |
3 | import org.avaje.ebean.typequery.PDouble;
4 | import org.avaje.ebean.typequery.PInteger;
5 | import org.avaje.ebean.typequery.PLong;
6 | import org.avaje.ebean.typequery.PTimestamp;
7 | import org.avaje.ebean.typequery.TQAssocBean;
8 | import org.avaje.ebean.typequery.TQProperty;
9 | import org.avaje.ebean.typequery.TypeQueryBean;
10 | import org.example.domain.OrderDetail;
11 | import org.example.domain.query.QOrderDetail;
12 |
13 | /**
14 | * Association query bean for AssocOrderDetail.
15 | *
16 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
17 | */
18 | @TypeQueryBean
19 | public class QAssocOrderDetail extends TQAssocBean {
20 |
21 | public PLong id;
22 | public PLong version;
23 | public PTimestamp whenCreated;
24 | public PTimestamp whenModified;
25 | public QAssocOrder order;
26 | public PInteger orderQty;
27 | public PInteger shipQty;
28 | public PDouble unitPrice;
29 | public QAssocProduct product;
30 |
31 | /**
32 | * Eagerly fetch this association loading the specified properties.
33 | */
34 | @SafeVarargs
35 | public final R fetch(TQProperty... properties) {
36 | return fetchProperties(properties);
37 | }
38 |
39 | public QAssocOrderDetail(String name, R root) {
40 | super(name, root);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/example/domain/query/assoc/QAssocProduct.java:
--------------------------------------------------------------------------------
1 | package org.example.domain.query.assoc;
2 |
3 | import org.avaje.ebean.typequery.PLong;
4 | import org.avaje.ebean.typequery.PString;
5 | import org.avaje.ebean.typequery.PTimestamp;
6 | import org.avaje.ebean.typequery.TQAssocBean;
7 | import org.avaje.ebean.typequery.TQProperty;
8 | import org.avaje.ebean.typequery.TypeQueryBean;
9 | import org.example.domain.Product;
10 | import org.example.domain.query.QProduct;
11 |
12 | /**
13 | * Association query bean for AssocProduct.
14 | *
15 | * THIS IS A GENERATED OBJECT, DO NOT MODIFY THIS CLASS.
16 | */
17 | @TypeQueryBean
18 | public class QAssocProduct extends TQAssocBean {
19 |
20 | public PLong id;
21 | public PLong version;
22 | public PTimestamp whenCreated;
23 | public PTimestamp whenModified;
24 | public PString sku;
25 | public PString name;
26 |
27 | /**
28 | * Eagerly fetch this association loading the specified properties.
29 | */
30 | @SafeVarargs
31 | public final R fetch(TQProperty... properties) {
32 | return fetchProperties(properties);
33 | }
34 |
35 | public QAssocProduct(String name, R root) {
36 | super(name, root);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/example/extension/Extension.kt:
--------------------------------------------------------------------------------
1 | package org.example.extension
2 |
3 | import org.slf4j.LoggerFactory
4 |
5 | /**
6 | * Helper function to create a Logger.
7 | */
8 | fun loggerFor(clazz: Class) = LoggerFactory.getLogger(clazz)
9 |
--------------------------------------------------------------------------------
/src/main/java/org/example/module/DbModule.kt:
--------------------------------------------------------------------------------
1 | package org.example.module
2 |
3 | import com.avaje.ebean.EbeanServer
4 | import com.google.inject.AbstractModule
5 | import org.example.extension.loggerFor
6 | import org.example.service.MetricService
7 |
8 | /**
9 | *
10 | */
11 | class DbModule : AbstractModule() {
12 |
13 | private val log = loggerFor(javaClass)
14 |
15 | override fun configure() {
16 |
17 | log.debug("configure ...")
18 | bind(MetricService::class.java).asEagerSingleton()
19 | bind(EbeanServer::class.java).toProvider(EbeanServerProvider::class.java).asEagerSingleton()
20 | }
21 | }
--------------------------------------------------------------------------------
/src/main/java/org/example/module/EbeanServerProvider.kt:
--------------------------------------------------------------------------------
1 | package org.example.module
2 |
3 | import com.avaje.ebean.EbeanServer
4 | import com.avaje.ebean.EbeanServerFactory
5 | import com.avaje.ebean.config.ServerConfig
6 | import com.google.inject.Provider
7 | import javax.inject.Singleton
8 |
9 | //import org.apache.ignite.configuration.IgniteConfiguration
10 | //import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi
11 | //import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder
12 | //import org.apache.ignite.spi.swapspace.file.FileSwapSpaceSpi
13 |
14 | /**
15 | * Creates the default EbeanServer instance.
16 | *
17 | * This should be a singleton.
18 | */
19 | @Singleton
20 | class EbeanServerProvider : Provider {
21 |
22 | override fun get(): EbeanServer {
23 |
24 | val config = ServerConfig()
25 | config.name = "db"
26 | config.isDefaultServer = true
27 | config.loadFromProperties()
28 |
29 | // val igniteConf = IgniteConfiguration()
30 | // igniteConf.isClientMode = true
31 | // igniteConf.swapSpaceSpi = FileSwapSpaceSpi()
32 | // igniteConf.discoverySpi = TcpDiscoverySpi()
33 | //
34 | // val multiCast = TcpDiscoveryMulticastIpFinder()
35 | // multiCast.setAddresses(arrayListOf("127.0.0.1"))
36 | //
37 | // val tcpDiscovery = TcpDiscoverySpi()
38 | // tcpDiscovery.ipFinder = multiCast
39 | // igniteConf.discoverySpi = tcpDiscovery
40 | //
41 | // config.putServiceObject("igniteConfiguration", igniteConf);
42 |
43 | return EbeanServerFactory.create(config);
44 | }
45 | }
--------------------------------------------------------------------------------
/src/main/java/org/example/service/LoadExampleData.kt:
--------------------------------------------------------------------------------
1 | package org.example.service;
2 |
3 | import com.avaje.ebean.Ebean
4 | import com.avaje.ebean.EbeanServer
5 | import org.example.domain.*
6 |
7 | class LoadExampleData {
8 |
9 | var runOnce: Boolean = false;
10 |
11 | val server: EbeanServer = Ebean.getDefaultServer();
12 |
13 | fun load() {
14 |
15 | if (runOnce) {
16 | return;
17 | }
18 |
19 | server.execute({
20 | deleteAll();
21 | insertCountries();
22 | insertProducts();
23 | insertTestCustAndOrders();
24 | });
25 | runOnce = true;
26 | }
27 |
28 | fun deleteAll() {
29 |
30 | Ebean.execute({
31 |
32 | // orm update use bean name and bean properties
33 | OrderDetail.find.query().delete()
34 | Order.find.query().delete()
35 | Contact.query().delete()
36 | Customer.find.query().delete()
37 | Address.query().delete()
38 | Country.query().delete()
39 | Product.query().delete()
40 |
41 | // server.createUpdate(OrderDetail::class.java, "delete from orderDetail").execute();
42 | // server.createUpdate(Order::class.java, "delete from order").execute();
43 | // server.createUpdate(Contact::class.java, "delete from contact").execute();
44 | // server.createUpdate(Customer::class.java, "delete from Customer").execute();
45 | // server.createUpdate(Address::class.java, "delete from address").execute();
46 |
47 | // // sql update uses table and column names
48 | // server.createSqlUpdate("delete from o_country").execute();
49 | // server.createSqlUpdate("delete from o_product").execute();
50 | })
51 | }
52 |
53 | fun insertCountries() {
54 |
55 | Country("NZ", "New Zealand").save()
56 | Country("AU", "Australia").save()
57 |
58 | Country.ref("NZ")
59 |
60 | val nz = Country.where()
61 | .code.equalTo("NZ")
62 | .findUnique()
63 | }
64 |
65 | fun insertProducts() {
66 |
67 | server.execute({
68 |
69 | // use alternate constructor function ...
70 | Product("Chair", "C001").save()
71 | Product("Desk", "DSK1").save()
72 | Product("C002", "Computer").save()
73 |
74 | // use set properties style ...
75 | val product = Product()
76 | product.name = "Printer"
77 | product.sku = "C003"
78 | product.save()
79 | });
80 | }
81 |
82 | fun insertTestCustAndOrders() {
83 |
84 | // TxRunnable is not really required ...
85 | server.execute({
86 | val cust1 = insertCustomer("Rob");
87 | val cust2 = insertCustomerNoAddress();
88 | insertCustomerFiona();
89 | insertCustomerNoContacts("NoContactsCust");
90 |
91 | createOrder1(cust1);
92 | createOrder2(cust2);
93 | createOrder3(cust1);
94 | createOrder4(cust1);
95 | });
96 | }
97 |
98 |
99 | var contactEmailNum: Int = 1;
100 |
101 | fun insertCustomerFiona(): Customer {
102 |
103 | val c = createCustomer("Fiona", "12 Apple St", "West Coast Rd", 1)
104 | c.contacts.add(createContact("Fiona", "Black"))
105 | c.contacts.add(createContact("Tracy", "Red"))
106 | c.save()
107 | return c;
108 | }
109 |
110 | fun createContact(firstName: String, lastName: String): Contact {
111 |
112 | val contact = Contact();
113 | contact.firstName = firstName;
114 | contact.lastName = lastName;
115 | contact.email = (contact.lastName + (contactEmailNum++) + "@test.com").toLowerCase();
116 | return contact;
117 | }
118 |
119 | fun insertCustomerNoContacts(name: String): Customer {
120 |
121 | val customer = createCustomer(name, "15 Kumera Way", "Bos town", 1);
122 | customer.save()
123 | return customer;
124 | }
125 |
126 | fun insertCustomerNoAddress(): Customer {
127 |
128 | val customer = Customer("Customer NoAddress");
129 | customer.contacts.add(createContact("Jack", "Black"));
130 | customer.save()
131 | return customer;
132 | }
133 |
134 | fun insertCustomer(name: String): Customer {
135 | val customer = createCustomer(name, "1 Banana St", "P.O.Box 1234", 1);
136 | customer.save()
137 | return customer;
138 | }
139 |
140 | fun createCustomer(name: String, shippingStreet: String?, billingStreet: String?, contactSuffix: Int): Customer {
141 |
142 | val customer = Customer(name);
143 | if (contactSuffix > 0) {
144 | customer.contacts.add(Contact("Jim" + contactSuffix, "Cricket"));
145 | customer.contacts.add(Contact("Fred" + contactSuffix, "Blue"));
146 | customer.contacts.add(Contact("Bugs" + contactSuffix, "Bunny"));
147 | }
148 |
149 | if (shippingStreet != null) {
150 | val shipAddress = Address();
151 | shipAddress.line1 = shippingStreet;
152 | shipAddress.line2 = "Sandringham";
153 | shipAddress.city = "Auckland";
154 | shipAddress.country = Country.ref("NZ")
155 |
156 | customer.shippingAddress = shipAddress;
157 | }
158 |
159 | if (billingStreet != null) {
160 | val billAddress = Address();
161 | billAddress.line1 = billingStreet;
162 | billAddress.line2 = "St Lukes";
163 | billAddress.city = "Auckland";
164 | billAddress.country = Country.ref("NZ")
165 |
166 | customer.billingAddress = billAddress;
167 | }
168 |
169 | return customer;
170 | }
171 |
172 | fun createOrder1(customer: Customer): Order {
173 |
174 | return with(Order()) {
175 | this.customer = customer;
176 | details.add(OrderDetail(Product.ref(1), 5, 10.50))
177 | details.add(OrderDetail(Product.ref(2), 3, 1.10))
178 | details.add(OrderDetail(Product.ref(3), 1, 2.00))
179 | save()
180 | this
181 | }
182 | }
183 |
184 | fun createOrder2(customer: Customer) {
185 |
186 | with(Order()) {
187 | status = Order.Status.SHIPPED
188 | this.customer = customer
189 | this.details.add(OrderDetail(Product.ref(1), 4, 10.50))
190 | save();
191 | }
192 | }
193 |
194 | fun createOrder3(customer: Customer) {
195 |
196 | with(Order()) {
197 | status = Order.Status.COMPLETE
198 | this.customer = customer;
199 | this.details.add(OrderDetail(Product.ref(1), 3, 10.50))
200 | this.details.add(OrderDetail(Product.ref(3), 40, 2.10))
201 | save()
202 | }
203 | }
204 |
205 | fun createOrder4(customer: Customer) {
206 |
207 | with(Order()) {
208 | this.customer = customer;
209 | save();
210 | }
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/src/main/java/org/example/service/MetricService.kt:
--------------------------------------------------------------------------------
1 | package org.example.service
2 |
3 | import org.avaje.metric.annotation.NotTimed
4 | import org.avaje.metric.report.MetricReportConfig
5 | import org.avaje.metric.report.MetricReportManager
6 | import org.example.extension.loggerFor
7 | import javax.inject.Inject
8 | import javax.inject.Singleton
9 |
10 | /**
11 | * Metric service to initialise metrics reporting.
12 | */
13 | @NotTimed
14 | @Singleton
15 | class MetricService {
16 |
17 | private val logger = loggerFor(javaClass)
18 |
19 | protected val reporter: MetricReportManager
20 |
21 | @Inject
22 | constructor() {
23 |
24 | logger.info("initialise the MetricReportManager")
25 |
26 | val config = MetricReportConfig()
27 | config.freqInSeconds = 10;
28 |
29 | reporter = MetricReportManager(config)
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/java/org/example/web/BeanValidationException.kt:
--------------------------------------------------------------------------------
1 | package org.example.web
2 |
3 | /**
4 | *
5 | */
6 | class BeanValidationException(message: String?, cause: Throwable?) : RuntimeException(message, cause) {
7 | }
--------------------------------------------------------------------------------
/src/main/java/org/example/web/ObjectMapperResolver.java:
--------------------------------------------------------------------------------
1 | package org.example.web;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.inject.Inject;
5 | import org.avaje.ebeanorm.jackson.DelayEbeanModule;
6 |
7 | import javax.ws.rs.ext.ContextResolver;
8 | import javax.ws.rs.ext.Provider;
9 |
10 | /**
11 | * Provides ObjectMapper with registered Ebean Jackson module.
12 | */
13 | @Provider
14 | public class ObjectMapperResolver implements ContextResolver {
15 |
16 | private final ObjectMapper mapper;
17 |
18 | @Inject
19 | public ObjectMapperResolver() {
20 | mapper = new ObjectMapper();
21 | mapper.registerModule(new DelayEbeanModule());
22 | }
23 |
24 | @Override
25 | public ObjectMapper getContext(Class> aClass) {
26 | return mapper;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/example/web/api/BaseResource.kt:
--------------------------------------------------------------------------------
1 | package org.example.web.api
2 |
3 | import com.avaje.ebean.EbeanServer
4 | import com.avaje.ebean.Query
5 | import com.avaje.ebean.text.json.JsonContext
6 | import com.avaje.ebean.text.json.JsonWriteOptions
7 | import org.example.web.BeanValidationException
8 | import org.slf4j.LoggerFactory
9 |
10 | import javax.inject.Inject
11 | import javax.ws.rs.Consumes
12 | import javax.ws.rs.DELETE
13 | import javax.ws.rs.GET
14 | import javax.ws.rs.POST
15 | import javax.ws.rs.PUT
16 | import javax.ws.rs.Path
17 | import javax.ws.rs.PathParam
18 | import javax.ws.rs.Produces
19 | import javax.ws.rs.core.Context
20 | import javax.ws.rs.core.MediaType
21 | import javax.ws.rs.core.Response
22 | import javax.ws.rs.core.UriInfo
23 |
24 | @Consumes(MediaType.APPLICATION_JSON)
25 | @Produces(MediaType.APPLICATION_JSON)
26 | abstract class BaseResource {
27 |
28 | protected val server: EbeanServer
29 |
30 | protected val beanType: Class
31 |
32 | protected var log = LoggerFactory.getLogger(javaClass)
33 |
34 | protected val jsonContext: JsonContext
35 |
36 | protected var updateReturnProperties = "id,whenUpdated,version"
37 |
38 | @Inject
39 | constructor(server: EbeanServer, beanType: Class) {
40 | this.server = server;
41 | this.beanType = beanType;
42 | this.jsonContext = server.json()
43 | }
44 |
45 | @GET
46 | open fun all(): List {
47 | val query = server.find(beanType).order().asc("id")
48 | return query.findList()
49 | }
50 |
51 | @GET
52 | @Path("/{id}")
53 | open fun getById(@PathParam("id") id: String): T? {
54 |
55 | val query = server.find(beanType).setId(id)//.select("*")
56 | applyGetByIdPredicates(query)
57 | return query.findUnique()
58 | }
59 |
60 | /**
61 | * Apply predicates and order by clauses to the query as necessary.
62 | */
63 | protected fun applyGetByIdPredicates(query: Query) {
64 |
65 | }
66 |
67 | protected fun sanitiseBean(bean: T) {
68 |
69 | }
70 |
71 | protected fun validateBean(bean: T) {
72 |
73 | }
74 | @POST
75 | open fun insert(@Context uriInfo: UriInfo, bean: T): Response {
76 |
77 | try {
78 | validateBean(bean);
79 | sanitiseBean(bean)
80 |
81 | server.save(bean)
82 | val id = server.getBeanId(bean)
83 |
84 | val ub = uriInfo.absolutePathBuilder
85 | val createdUri = ub.path("" + id).build()
86 |
87 | postInsert(bean)
88 |
89 | return Response.created(createdUri).entity(bean).build()
90 |
91 | } catch (e: BeanValidationException) {
92 | log.info("validation errors " + e)
93 | return Response.ok("TODO: BeanValidationException").build()
94 | }
95 |
96 | }
97 |
98 | /**
99 | * Override to lookup important related objects.
100 | */
101 | protected fun postInsert(bean: T) {
102 |
103 | }
104 |
105 | @PUT
106 | @Path("/{id}")
107 | open fun update(@PathParam("id") id: String, bean: T): Response {
108 | try {
109 | validateBean(bean);
110 | sanitiseBean(bean)
111 |
112 | server.setBeanId(bean, id)
113 | server.update(bean)
114 | postUpdate(bean)
115 |
116 | val beanUpdateOptions = JsonWriteOptions.parsePath("($updateReturnProperties)")
117 | val json = jsonContext.toJson(bean, beanUpdateOptions)
118 | return Response.ok(json).build()
119 |
120 | } catch (e: BeanValidationException) {
121 | log.info("validation errors " + e)
122 | return Response.ok("TODO: BeanValidationException").build()
123 | }
124 |
125 | }
126 |
127 | /**
128 | * Override to lookup important related objects etc.
129 | */
130 | protected fun postUpdate(bean: T) {
131 |
132 | }
133 |
134 | /**
135 | * Delete just using the Id. Note that this doesn't take into account
136 | * optimistic locking.
137 | *
138 | *
139 | * Also consume Application/XML as AngularJS will send that for some browsers.
140 | *
141 | */
142 | @Consumes(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
143 | @DELETE
144 | @Path("/{id}")
145 | fun delete(@PathParam("id") id: String): Response {
146 | return performDelete(id)
147 | }
148 |
149 | /**
150 | * Delete using a POST to get around issues with AngularJS sending the wrong
151 | * content type.
152 | */
153 | @POST
154 | @Path("/{id}/delete")
155 | fun deletePath(@PathParam("id") id: String): Response {
156 |
157 | return performDelete(id)
158 | }
159 |
160 | protected fun performDelete(id: String): Response {
161 | server.delete(beanType, id)
162 | return Response.ok().build()
163 | }
164 |
165 | // @Path("/query")
166 | // @POST
167 | // @Produces({ MediaType.APPLICATION_JSON })
168 | // public String query(QueryRequest queryRequest) {
169 | //
170 | // QueryResponse fetchData = fetchData(queryRequest);
171 | //
172 | // JsonWriteOptions writeOptions = null;// JsonWriteOptions.parsePath("(success,pageIndex,pageSize,list(*))");
173 | // String val = jsonContext.toJson(fetchData, writeOptions);
174 | //
175 | // // String val = jacksonService.serialise(fetchData);
176 | // return val;
177 | // }
178 | //
179 | // /**
180 | // * Apply predicates and order by clauses to the query as necessary.
181 | // */
182 | // protected void applyPredicates(QueryRequest request, Query query) {
183 | // if(request.getPredicate("order") != null){
184 | // query.orderBy(request.getPredicate("order"));
185 | // }
186 | // }
187 | //
188 | // /**
189 | // * Fetch the data based on the paging information.
190 | // */
191 | // public QueryResponse fetchData(QueryRequest request) {
192 | //
193 | // log.info("process query request for {}", beanType);
194 | // Query query = server.find(beanType);
195 | // if (request.hasPaging()) {
196 | // query.setFirstRow(request.getFirstRow());
197 | // query.setMaxRows(request.getPageSize());
198 | // }
199 | //
200 | // // Apply predicates and Order by clause to the query
201 | // applyPredicates(request, query);
202 | //
203 | // Future rowCount = null;
204 | // if (request.getPageSize() > 0 && request.getPageIndex() == 0) {
205 | // rowCount = query.findFutureRowCount();
206 | // }
207 | //
208 | // List list = query.findList();
209 | //
210 | // return buildResponse(request, list, rowCount);
211 | // }
212 | //
213 | // protected QueryResponse buildResponse(QueryRequest request, List list, Future rowCount) {
214 | //
215 | // @SuppressWarnings("unchecked")
216 | // boolean hasNext = ((BeanCollection) list).hasMoreRows();
217 | //
218 | // QueryResponse response = new QueryResponse();
219 | // response.setList(list);
220 | // response.setPageIndex(request.getPageIndex());
221 | // response.setPageSize(request.getPageSize());
222 | // response.setMore(hasNext);
223 | //
224 | // if (rowCount != null) {
225 | // try {
226 | // response.setTotalCount(rowCount.get(60, TimeUnit.SECONDS));
227 | // } catch (Exception e) {
228 | // log.error("Error trying to fetch total Row count", e);
229 | // }
230 | // }
231 | //
232 | // return response;
233 | // }
234 |
235 | }
236 |
--------------------------------------------------------------------------------
/src/main/java/org/example/web/api/CountryResource.kt:
--------------------------------------------------------------------------------
1 | package org.example.web.api
2 |
3 | import com.avaje.ebean.EbeanServer
4 | import org.example.domain.Country
5 | import org.example.domain.Customer
6 | import javax.inject.Inject
7 | import javax.inject.Singleton
8 | import javax.ws.rs.*
9 | import javax.ws.rs.core.MediaType
10 |
11 | /**
12 | * Customer web resource.
13 | */
14 | @Singleton
15 | @Path("/country")
16 | @Consumes(MediaType.APPLICATION_JSON)
17 | @Produces(MediaType.APPLICATION_JSON)
18 | class CountryResource : BaseResource {
19 |
20 | @Inject
21 | constructor(server: EbeanServer) : super(server, Country::class.java){}
22 |
23 | @GET
24 | @Path("/{id}")
25 | override fun getById(@PathParam("id") id: String): Country? {
26 | return super.getById(id)
27 | }
28 |
29 | @GET
30 | @Path("/all")
31 | fun asBean(): String {
32 |
33 | log.debug("all ...")
34 | val all = Country.all()
35 |
36 | return Country.db().json().toJson(all);
37 | }
38 |
39 | @GET
40 | @Path("/queryCache")
41 | fun queryCache(): String {
42 |
43 | log.debug("queryCache ...")
44 | val all = Country
45 | .where()
46 | .setUseQueryCache(true)
47 | .name.asc()
48 | .findList()
49 |
50 | return Country.db().json().toJson(all);
51 | }
52 |
53 | @GET
54 | @Path("index/{id}")
55 | fun indexGetById(@PathParam("id") id: String): Country? {
56 |
57 | return Country
58 | .where().setId(id)
59 | .setUseDocStore(true)
60 | .findUnique();
61 | }
62 |
63 | @GET
64 | @Path("/indexAll")
65 | fun indexAll(): String {
66 |
67 | Country.db().docStore().indexAll(Country::class.java);
68 |
69 | Customer.db().docStore().indexAll(Customer::class.java);
70 |
71 | return "indexed";
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/org/example/web/api/CustomerResource.kt:
--------------------------------------------------------------------------------
1 | package org.example.web.api
2 |
3 | import com.avaje.ebean.EbeanServer
4 | import org.example.domain.Customer
5 | import org.example.service.LoadExampleData
6 | import javax.inject.Inject
7 | import javax.inject.Singleton
8 | import javax.ws.rs.*
9 | import javax.ws.rs.core.MediaType
10 |
11 | /**
12 | * Customer web resource.
13 | */
14 | @Singleton
15 | @Path("/customer")
16 | @Consumes(MediaType.APPLICATION_JSON)
17 | @Produces(MediaType.APPLICATION_JSON)
18 | class CustomerResource : BaseResource {
19 |
20 | @Inject
21 | constructor(server: EbeanServer) : super(server, Customer::class.java){}
22 |
23 | @GET
24 | @Path("/{id}")
25 | override fun getById(@PathParam("id") id: String): Customer? {
26 | return super.getById(id)
27 | }
28 |
29 | @GET
30 | @Path("/all")
31 | fun asBean(): String {
32 |
33 | log.debug("all ...")
34 | val all = Customer.find.all()
35 |
36 | return Customer.db().json().toJson(all);
37 | }
38 |
39 | @GET
40 | @Path("/queryCache")
41 | fun queryCache(): String {
42 |
43 | log.debug("queryCache ...")
44 | val all = Customer.find
45 | .where()
46 | .setUseQueryCache(true)
47 | .name.icontains("fiona")
48 | .order()
49 | .name.asc()
50 | .findList()
51 |
52 | return Customer.db().json().toJson(all);
53 | }
54 |
55 | @GET
56 | @Path("index/{id}")
57 | fun indexGetById(@PathParam("id") id: String): Customer? {
58 |
59 | return Customer
60 | .where().setId(id)
61 | .setUseDocStore(true)
62 | .setUseCache(false)
63 | .findUnique();
64 | }
65 |
66 | @GET
67 | @Path("/init")
68 | fun useData(): String {
69 |
70 | LoadExampleData().load()
71 |
72 | return "loaded"
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/org/example/web/api/HelloResource.kt:
--------------------------------------------------------------------------------
1 | package org.example.web.api
2 |
3 | import org.example.domain.Customer
4 | import org.example.extension.loggerFor
5 | import org.example.service.LoadExampleData
6 | import javax.inject.Singleton
7 | import javax.ws.rs.Consumes
8 | import javax.ws.rs.GET
9 | import javax.ws.rs.Path
10 | import javax.ws.rs.Produces
11 | import javax.ws.rs.core.MediaType
12 |
13 | /**
14 | * Customer web resource.
15 | */
16 | @Singleton
17 | @Path("/customerRes")
18 | @Consumes(MediaType.APPLICATION_JSON)
19 | @Produces(MediaType.APPLICATION_JSON)
20 | open class HelloResource {
21 |
22 | private val logger = loggerFor(javaClass)
23 |
24 | //@Inject
25 | constructor() {
26 | }
27 |
28 |
29 | @Produces(MediaType.TEXT_PLAIN)
30 | @GET
31 | fun hello(): String {
32 |
33 | logger.debug("plain boring hello ...")
34 | return "Hello"
35 | }
36 |
37 | @GET
38 | @Path("/all")
39 | fun asBean(): String {
40 |
41 | logger.debug("all ...")
42 | val all = Customer.find.all()
43 |
44 | return Customer.db().json().toJson(all);
45 | }
46 |
47 | @GET
48 | @Path("/init")
49 | fun useData(): String {
50 |
51 | LoadExampleData().load()
52 |
53 | return "loaded"
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/example/web/module/WebModule.kt:
--------------------------------------------------------------------------------
1 | package org.example.myapp.web.module
2 |
3 | import com.google.inject.AbstractModule
4 | import org.example.extension.loggerFor
5 | import org.example.module.DbModule
6 | import org.example.web.api.CountryResource
7 | import org.example.web.api.CustomerResource
8 | import org.example.web.api.HelloResource
9 |
10 | /**
11 | * Main module binding the web and lower layers
12 | */
13 | class WebModule : AbstractModule() {
14 |
15 | private val logger = loggerFor(javaClass)
16 |
17 | override fun configure() {
18 |
19 | logger.debug("configuring module ...")
20 |
21 | install(DbModule())
22 | bind(CountryResource::class.java).asEagerSingleton()
23 | bind(CustomerResource::class.java).asEagerSingleton()
24 | bind(HelloResource::class.java).asEagerSingleton()
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/src/main/resources/META-INF/ebean-typequery.mf:
--------------------------------------------------------------------------------
1 | packages: org.example.domain.query
2 |
3 |
--------------------------------------------------------------------------------
/src/main/resources/dbmigration/model/1.0__initial.model.xml:
--------------------------------------------------------------------------------
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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/main/resources/ebean.properties:
--------------------------------------------------------------------------------
1 |
2 | load.properties.override=${user.home}/config/example-kotlin.properties
3 |
4 | #ebean.ddl.generate=true
5 | #ebean.ddl.run=true
6 |
7 | datasource.default=db
8 |
9 | #datasource.db.username=setme
10 | #datasource.db.password=setme
11 | datasource.db.databaseUrl=jdbc:postgresql://127.0.0.1:5432/kt
12 | datasource.db.databaseDriver=org.postgresql.Driver
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/main/resources/elastic-mapping/country_v1.mapping.json:
--------------------------------------------------------------------------------
1 | {
2 | "mappings" : {
3 | "country" : {
4 | "properties" : {
5 | "name": { "type": "string" }
6 | }
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/main/resources/elastic-mapping/customer_v1.mapping.json:
--------------------------------------------------------------------------------
1 | {
2 | "mappings" : {
3 | "customer" : {
4 | "properties" : {
5 | "name": { "type": "string" },
6 | "registered": { "type": "date" },
7 | "comments": { "type": "string" },
8 | "version": { "type": "long" },
9 | "whenCreated": { "type": "date" },
10 | "whenModified": { "type": "date" },
11 | "deleted": { "type": "boolean" }
12 | }
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/resources/elastic-mapping/order_v1.mapping.json:
--------------------------------------------------------------------------------
1 | {
2 | "mappings" : {
3 | "order" : {
4 | "properties" : {
5 | "status": { "type": "string", "index": "not_analyzed" },
6 | "orderDate": { "type": "date" },
7 | "shipDate": { "type": "date" },
8 | "customer" : {
9 | "properties" : {
10 | "id": { "type": "long" },
11 | "name": { "type": "string" }
12 | }
13 | },
14 | "details" : {
15 | "type" : "nested",
16 | "properties" : {
17 | "id": { "type": "long" },
18 | "orderQty": { "type": "integer" },
19 | "shipQty": { "type": "integer" },
20 | "unitPrice": { "type": "double" },
21 | "product" : {
22 | "properties" : {
23 | "id": { "type": "long" },
24 | "sku": { "type": "string" },
25 | "name": { "type": "string" }
26 | }
27 | },
28 | "version": { "type": "long" },
29 | "whenCreated": { "type": "date" },
30 | "whenModified": { "type": "date" }
31 | }
32 | },
33 | "version": { "type": "long" },
34 | "whenCreated": { "type": "date" },
35 | "whenModified": { "type": "date" }
36 | }
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/src/main/resources/elastic-mapping/product_v1.mapping.json:
--------------------------------------------------------------------------------
1 | {
2 | "mappings" : {
3 | "product" : {
4 | "properties" : {
5 | "sku": { "type": "string" },
6 | "name": { "type": "string" },
7 | "version": { "type": "long" },
8 | "whenCreated": { "type": "date" },
9 | "whenModified": { "type": "date" }
10 | }
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | resteasy.guice.modules
7 | org.example.myapp.web.module.WebModule
8 |
9 |
10 | resteasy.providers
11 | org.example.web.ObjectMapperResolver
12 |
13 |
14 |
15 |
16 |
17 | org.avaje.resteasy.Bootstrap
18 |
19 |
20 |
21 |
22 |
23 | RestFilter
24 | org.avaje.resteasy.RestFilter
25 |
26 | ignore
27 | (/favicon.ico|/(assets|images|fonts|css|js|res)/.*)
28 |
29 |
30 |
31 |
32 | RestFilter
33 | /*
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/main/webapp/assets/placeholder.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | placeholder
4 |
5 |
--------------------------------------------------------------------------------
/src/main/webapp/metric-listen.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Metrics Request timing
5 |
51 |
52 | Metric Request Timing Listener:
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/main/webapp/websocket-test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WebSocket Test
5 |
62 |
63 | WebSocket Test
64 |
65 |
66 |
67 |
68 | send
69 | close
70 |
71 |
--------------------------------------------------------------------------------
/src/test/java/main/JavaMain.java:
--------------------------------------------------------------------------------
1 | package main;
2 |
3 | import com.avaje.ebean.Ebean;
4 |
5 | public class JavaMain {
6 |
7 | public static void main(String[] args) throws Exception {
8 |
9 | System.currentTimeMillis();
10 | try {
11 | Ebean.getDefaultServer();
12 | } catch (Throwable e) {
13 | e.printStackTrace();
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/test/java/main/MainDbMigration.kt:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import com.avaje.ebean.config.dbplatform.DbPlatformName
4 | import com.avaje.ebean.dbmigration.DbMigration
5 | import java.io.IOException
6 |
7 |
8 | object MainDbMigration {
9 |
10 | @Throws(IOException::class)
11 | @JvmStatic fun main(args: Array) {
12 |
13 |
14 | //System.setProperty("ddl.migration.version", "1.1");
15 | //System.setProperty("ddl.migration.name", "support end dating");
16 |
17 | val dbMigration = DbMigration()
18 | dbMigration.setPlatform(DbPlatformName.POSTGRES);
19 | dbMigration.generateMigration();
20 | }
21 | }
--------------------------------------------------------------------------------
/src/test/java/main/MainQueryBeanGenerator.kt:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import org.avaje.ebean.typequery.generator.Generator
4 | import org.avaje.ebean.typequery.generator.GeneratorConfig
5 | import java.io.IOException
6 |
7 |
8 | object MainQueryBeanGenerator {
9 |
10 | @Throws(IOException::class)
11 | @JvmStatic fun main(args: Array) {
12 |
13 | val config = GeneratorConfig()
14 | //config.setClassesDirectory("./target/classes");
15 | //config.setDestDirectory("./src/main/java");
16 | //config.setDestResourceDirectory("./src/main/resources");
17 |
18 | config.entityBeanPackage = "org.example.domain"
19 | //config.setDestPackage("org.example.domain.query");
20 |
21 | //config.setOverwriteExistingFinders(true);
22 |
23 | val generator = Generator(config)
24 | generator.generateQueryBeans()
25 | generator.generateFinders();
26 | generator.modifyEntityBeansAddFinderField();
27 | }
28 | }
--------------------------------------------------------------------------------
/src/test/java/main/RunApp.kt:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import org.avaje.jettyrunner.JettyRun
4 | import java.io.IOException
5 |
6 | object RunApp {
7 |
8 | @Throws(IOException::class)
9 | @JvmStatic fun main(args: Array) {
10 |
11 | System.setProperty("disableTestProperties", "true");
12 |
13 | val jetty = JettyRun()
14 | jetty.httpPort = 9090
15 | jetty.runServer()
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/test/java/main/RunLoad.kt:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import com.avaje.ebean.Ebean
4 | import com.avaje.ebean.FetchConfig
5 | import org.example.domain.Order
6 | import org.example.domain.Product
7 | import java.io.IOException
8 | import java.time.LocalDate
9 | import java.util.*
10 |
11 | object RunLoad {
12 |
13 | @Throws(Exception::class)
14 | @JvmStatic fun main(args: Array) {
15 |
16 | // go into Postgres DB rather than H2 which we are using to run unit tests
17 | System.setProperty("disableTestProperties", "true");
18 |
19 | val start = System.currentTimeMillis()
20 |
21 | runSomeQueries(2,2)
22 | runSomeQueries(8,10)
23 | System.out.println("---")
24 | System.out.println("---")
25 | runSomeQueries(30,10)
26 |
27 | //runSomeQueries(20,100)
28 | //runLoad()
29 |
30 | val exe = System.currentTimeMillis() - start
31 | System.out.println("done "+exe)
32 |
33 | Ebean.getDefaultServer().shutdown(true, false)
34 | }
35 |
36 | private fun runLoad() {
37 | //val load = BigLoad()
38 | //load.loadProducts()
39 | //load.loadCustomers();
40 | //load.loadOrders()
41 |
42 | //Product.db().docStore().indexAll(Product::class.java)
43 | //Product.db().docStore().indexAll(Customer::class.java)
44 | val query = Order.find.where()
45 | .id.greaterOrEqualTo(600000)
46 | .id.lessThan(700000)
47 | .query()
48 |
49 | Product.db().docStore().indexByQuery(query, 500)
50 | }
51 |
52 | private fun runSomeQueries(runCount:Int, queryCount:Int) {
53 |
54 | for (i in 0..runCount) {
55 | val asDocStore = (i % 2) == 0
56 | runQuerySet(queryCount, asDocStore)
57 | }
58 |
59 | }
60 |
61 |
62 | private fun runQuerySet(count: Int, asDocStore: Boolean) {
63 |
64 | val random = Random()
65 | val asDate = LocalDate.of(2015, 12, 1)
66 | //val asDate = LocalDate.of(2015, 1, 1)
67 |
68 | for (i in 0..count) {
69 |
70 | val days = random.nextInt(25)
71 | val useDate = asDate.plusDays(days.toLong());
72 |
73 | val start = System.currentTimeMillis()
74 | val hits = findNewOrdersForCustomer(asDocStore, useDate)
75 | val exe = System.currentTimeMillis() - start
76 |
77 | val storeType = if (asDocStore) "es" else "db"
78 | val millis = padMillis(exe)
79 | System.out.println("" + millis + " ," + storeType)
80 | //System.out.println("exe: " + millis + " " + storeType + " hits:" + hits + " useDate:" + useDate)
81 | }
82 | }
83 |
84 | private fun padMillis(exe: Long): String {
85 |
86 | if (exe > 100) return exe.toString()
87 | if (exe > 9) return " " + exe
88 | return " " + exe
89 | }
90 |
91 | private fun findNewOrdersForCustomer(asDocStore: Boolean, useDate: LocalDate): Int {
92 |
93 | val query = Order.find.where()
94 | .status.`in`(Order.Status.NEW)
95 | .orderDate.after(useDate)
96 | .order()
97 | .orderDate.desc()
98 | //.customer.id.desc()
99 |
100 | .setMaxRows(100)
101 | .setLazyLoadBatchSize(100)
102 | .setUseDocStore(asDocStore)
103 | .query()
104 |
105 | // if (!asDocStore) {
106 | // query
107 | // .fetch("customer", "id,name")
108 | // .fetch("details", FetchConfig().query())
109 | // .fetch("details.product","id,sku,name")
110 | // }
111 |
112 | val orders = query.findList()
113 | for (order in orders) {
114 | order.details.size
115 | }
116 | return orders.size
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/src/test/java/org/example/domain/BigLoad.kt:
--------------------------------------------------------------------------------
1 | package org.example.domain
2 |
3 | import com.avaje.ebean.annotation.Transactional
4 | import java.time.LocalDate
5 | import java.util.*
6 |
7 | /**
8 | * Loads lots of customers and orders.
9 | */
10 | class BigLoad {
11 |
12 | val random = Random()
13 |
14 | @Transactional(batchSize = 100)
15 | fun loadOrders() {
16 | for (i in 0..100000) {
17 | loadOrder();
18 | }
19 | }
20 |
21 | private fun loadOrder() {
22 |
23 | val order = Order()
24 | order.status = orderStatus()
25 | order.customer = orderCustomer()
26 | order.orderDate = orderDate()
27 | order.shipDate = shipDate(order.orderDate)
28 | val orderLines = random.nextInt(20)
29 | for (i in 0..orderLines) {
30 | addDetail(order.details)
31 | }
32 |
33 | order.save()
34 | }
35 |
36 | private fun addDetail(details: MutableList) {
37 |
38 | val product = Product.ref(1 + random.nextInt(30000).toLong())
39 | val quantity = 1 + random.nextInt(20)
40 | val price = 1 + random.nextInt(100)
41 |
42 | details.add(OrderDetail(product, quantity, price.toDouble()))
43 | }
44 |
45 | private fun shipDate(orderDate: LocalDate?): LocalDate? {
46 |
47 | val plusDays = 1 + random.nextInt(12);
48 | return orderDate?.plusDays(plusDays.toLong());
49 | }
50 |
51 | private fun orderDate(): LocalDate {
52 |
53 | val month = 1 + random.nextInt(12);
54 | val day = 1 + random.nextInt(28);
55 |
56 | return LocalDate.of(2015, month, day)
57 | }
58 |
59 | private fun orderCustomer(): Customer {
60 |
61 | val idx = 1 + random.nextInt(100000);
62 | return Customer.ref(idx.toLong())
63 | }
64 |
65 | private fun orderStatus(): Order.Status {
66 |
67 | val idx = random.nextInt(4);
68 | when (idx) {
69 | 0 -> return Order.Status.NEW
70 | 1 -> return Order.Status.APPROVED
71 | 2 -> return Order.Status.SHIPPED
72 | }
73 | return Order.Status.COMPLETE
74 | }
75 |
76 | @Transactional(batchSize = 500)
77 | fun loadProducts() {
78 | val start = System.currentTimeMillis()
79 | val letters = arrayOf("A","B","C","D","E","F","G","H","I","J")
80 | for (letter in letters) {
81 | for (pos in 3001..3100) {
82 | loadProduct(letter, pos)
83 | }
84 | }
85 | val exe = System.currentTimeMillis() - start
86 | System.out.println("products loaded in millis: "+exe)
87 | }
88 |
89 | private fun loadProduct(letter: String, pos: Int) {
90 |
91 | val sku = letter + pos
92 | val name = sku
93 |
94 | Product(sku, name).save()
95 | }
96 |
97 | @Transactional(batchSize = 500)
98 | fun loadCustomers() {
99 |
100 | val start = System.currentTimeMillis()
101 | for (i in 100000..100020) {
102 | loadCustomer(i)
103 | }
104 | val exe = System.currentTimeMillis() - start
105 | System.out.println("exe: "+exe)
106 | }
107 |
108 | fun loadCustomer(pos:Int) {
109 |
110 | val name = "big "+pos
111 |
112 | val customer = Customer(name)
113 | customer.save()
114 | }
115 |
116 | }
--------------------------------------------------------------------------------
/src/test/java/org/example/service/LoadExampleDataTest.kt:
--------------------------------------------------------------------------------
1 | package org.example.service
2 |
3 | import org.assertj.core.api.Assertions
4 | import org.example.domain.Customer
5 | import org.testng.Assert
6 | import org.testng.annotations.Test
7 |
8 | class LoadExampleDataTest {
9 |
10 | @Test
11 | fun load() {
12 |
13 | LoadExampleData().load()
14 |
15 | val all = Customer.all()
16 | Assert.assertTrue(!all.isEmpty())
17 | }
18 |
19 | @Test(dependsOnMethods = arrayOf("load"))
20 | fun query() {
21 |
22 | val customers =
23 | Customer.find.where()
24 | .name.istartsWith("rob")
25 | .findList()
26 |
27 | Assertions.assertThat(customers).isNotEmpty()
28 | }
29 | }
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
6 |
7 |
8 |
9 |
10 |
12 | log/application.log
13 |
14 | log/application.%d{yyyy-MM-dd}.log
15 | 90
16 |
17 |
18 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/test/resources/test-ebean.properties:
--------------------------------------------------------------------------------
1 |
2 | ebean.ddl.generate=true
3 | ebean.ddl.run=true
4 |
5 | #datasource.default=db
6 |
7 | ebean.disableL2Cache=true
8 |
9 | datasource.db.username=sa
10 | datasource.db.password=
11 | datasource.db.databaseUrl=jdbc:h2:mem:tests
12 | datasource.db.databaseDriver=org.h2.Driver
13 |
14 | #datasource.db.username=kt
15 | #datasource.db.password=kt
16 | #datasource.db.databaseUrl=jdbc:postgresql://127.0.0.1:5432/kt
17 | #datasource.db.databaseDriver=org.postgresql.Driver
18 |
19 |
20 | #ebean.docstore.url=http://127.0.0.1:9200
21 | #ebean.docstore.active=true
22 | #ebean.docstore.generateMapping=true
23 | #ebean.docstore.dropCreate=true
24 | #ebean.docstore.create=true
25 | #ebean.docstore.pathToResources=src/test/resources
26 |
--------------------------------------------------------------------------------
/start1.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | java -Dwebapp.http.port=8081 -Dlogback.configurationFile=logback1.xml -Debean.props.file=node1-ebean.properties -jar target/example-kotlin-web-1.1-SNAPSHOT.war
3 |
--------------------------------------------------------------------------------
/start2.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | java -Dwebapp.http.port=8082 -Dlogback.configurationFile=logback2.xml -Debean.props.file=node2-ebean.properties -jar target/example-kotlin-web-1.1-SNAPSHOT.war
3 |
--------------------------------------------------------------------------------