├── .gitignore
├── LICENSE
├── README.md
├── benchmark
├── README
├── pom.xml
├── src
│ └── main
│ │ └── java
│ │ └── org
│ │ └── restexpress
│ │ └── example
│ │ └── benchmark
│ │ └── Main.java
└── zip-with-dependencies.xml
├── blogging
├── README
├── config
│ └── dev
│ │ └── environment.properties
├── pom.xml
├── src
│ └── main
│ │ └── java
│ │ └── org
│ │ └── restexpress
│ │ └── example
│ │ └── blogging
│ │ ├── Configuration.java
│ │ ├── Constants.java
│ │ ├── Main.java
│ │ ├── Relationships.java
│ │ ├── Routes.java
│ │ ├── controller
│ │ ├── BlogController.java
│ │ ├── BlogEntryController.java
│ │ └── CommentController.java
│ │ ├── domain
│ │ ├── AbstractEntity.java
│ │ ├── Blog.java
│ │ ├── BlogEntry.java
│ │ ├── Comment.java
│ │ └── event
│ │ │ ├── BlogDeletedEvent.java
│ │ │ ├── BlogEntryDeletedEvent.java
│ │ │ ├── CommentDeletedEvent.java
│ │ │ ├── ObjectCreatedEvent.java
│ │ │ ├── ObjectDeletedEvent.java
│ │ │ ├── ObjectUpdatedEvent.java
│ │ │ └── StateChangeEvent.java
│ │ ├── event
│ │ ├── BlogCascadeDeleteHandler.java
│ │ └── BlogEntryCascadeDeleteHandler.java
│ │ ├── persistence
│ │ ├── BaseBloggingRepository.java
│ │ ├── BlogEntryRepository.java
│ │ ├── BlogRepository.java
│ │ ├── CommentRepository.java
│ │ └── StateChangeEventingObserver.java
│ │ ├── postprocessor
│ │ └── LastModifiedHeaderPostprocessor.java
│ │ └── serialization
│ │ ├── JsonSerializationProcessor.java
│ │ ├── SerializationProvider.java
│ │ ├── UuidFormatter.java
│ │ ├── XmlSerializationProcessor.java
│ │ └── XstreamObjectIdConverter.java
└── zip-with-dependencies.xml
├── echo
├── README.md
├── config
│ └── dev
│ │ └── environment.properties
├── pom.xml
├── src
│ ├── jmeter
│ │ └── RestExpress Test Plan.jmx
│ └── main
│ │ └── java
│ │ └── org
│ │ └── restexpress
│ │ └── example
│ │ └── echo
│ │ ├── Configuration.java
│ │ ├── Main.java
│ │ ├── controller
│ │ ├── AbstractDelayingController.java
│ │ ├── DelayResponse.java
│ │ ├── EchoController.java
│ │ ├── StatusController.java
│ │ └── SuccessController.java
│ │ └── serialization
│ │ ├── JsonSerializationProcessor.java
│ │ ├── SerializationProvider.java
│ │ └── XmlSerializationProcessor.java
└── zip-with-dependencies.xml
├── pom.xml
└── vs-jersey
├── jersey
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── example
│ │ ├── Main.java
│ │ └── MyResource.java
│ └── test
│ └── java
│ └── com
│ └── example
│ └── MyResourceTest.java
└── restexpress
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── example
│ ├── Main.java
│ └── MyResource.java
└── test
└── java
└── com
└── example
└── MyResourceTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | target/
4 | .settings/
5 | *.iml
6 |
--------------------------------------------------------------------------------
/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 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | RestExpress Examples
2 | ====================
3 |
4 | A few examples to illustrate how RestExpress works.
5 |
6 | * echo - An echo service with no database back-end.
7 | * blogging - A blogging service with a MongoDB back-end.
8 | * benchmark - ?
--------------------------------------------------------------------------------
/benchmark/README:
--------------------------------------------------------------------------------
1 | This kickstart project illustrates how to create a simple RestExpress project. Complete with Ant
2 | build, it contains a skeleton main() class, RestServer, and an empty, but functional service.
3 |
4 | Alternatively, there is a kickstart zip file generated in the release process. Simply:
5 |
6 | 1) Unzip the file.
7 | 2) Run ant to build it.
8 | 3) 'ant run' to run it.
9 |
10 | Then:
11 |
12 | 1) Change the Routes.java file to match your URL requirements using the using the RouteBuilder DSL.
13 | 2) Implement the functionality for those URLs in a service class, much like KickstartService.java
14 | does.
15 | 3) Impress your superiors with the speed at which you've completed your tasks.
16 |
--------------------------------------------------------------------------------
/benchmark/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | RestExpress-Benchmark-Example
6 |
12 | A RestExpress Benchmark Server
13 | https://github.com/RestExpress/RestExpress-Examples
14 | org.restexpress.examples
15 | restexpress-benchmark-example
16 | 0.1-SNAPSHOT
17 | jar
18 |
19 |
20 |
21 | com.strategicgains
22 | RestExpress
23 | 0.11.3
24 |
25 |
26 | junit
27 | junit
28 | 4.11
29 | jar
30 | test
31 | true
32 |
33 |
34 |
35 |
36 | package
37 |
38 |
39 |
40 | org.apache.maven.plugins
41 | maven-compiler-plugin
42 | 3.0
43 |
44 | 1.7
45 | 1.7
46 | UTF-8
47 |
48 |
49 |
50 | org.codehaus.mojo
51 | exec-maven-plugin
52 | 1.2.1
53 |
54 | org.restexpress.scaffold.minimal.Main
55 |
56 |
57 |
58 | org.apache.maven.plugins
59 | maven-jar-plugin
60 | 2.4
61 |
62 |
63 | false
64 |
65 | true
66 | ./lib/
67 | org.restexpress.scaffold.minimal.Main
68 |
69 |
70 |
71 |
72 |
73 | org.apache.maven.plugins
74 | maven-assembly-plugin
75 | 2.4
76 |
77 |
78 | zip-with-dependencies.xml
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | org.codehaus.mojo
89 | versions-maven-plugin
90 | 2.0
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/benchmark/src/main/java/org/restexpress/example/benchmark/Main.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.benchmark;
2 |
3 | import io.netty.handler.codec.http.HttpMethod;
4 | import org.restexpress.Request;
5 | import org.restexpress.Response;
6 | import org.restexpress.RestExpress;
7 |
8 | public class Main
9 | {
10 | public static void main(String[] args)
11 | {
12 | RestExpress server = new RestExpress()
13 | .setName("Echo");
14 |
15 | server.uri("/echo", new Object()
16 | {
17 | @SuppressWarnings("unused")
18 | public String read(Request req, Response res)
19 | {
20 | String value = req.getHeader("echo");
21 | res.setContentType("text/xml");
22 |
23 | if (value == null)
24 | {
25 | return "no value specified";
26 | }
27 | else
28 | {
29 | return String.format("%s", value);
30 | }
31 | }
32 | })
33 | .method(HttpMethod.GET)
34 | .noSerialization();
35 |
36 | server.bind(8000);
37 | server.awaitShutdown();
38 | }}
39 |
--------------------------------------------------------------------------------
/benchmark/zip-with-dependencies.xml:
--------------------------------------------------------------------------------
1 |
5 | zip-with-dependencies
6 |
7 | zip
8 |
9 |
10 |
11 | ${project.basedir}
12 | /
13 |
14 | README*
15 | LICENSE*
16 | NOTICE*
17 | config/**/*
18 |
19 |
20 |
21 | ${project.build.directory}
22 | /
23 |
24 | *.jar
25 |
26 |
27 |
28 |
29 |
30 | lib
31 | false
32 |
33 |
34 |
--------------------------------------------------------------------------------
/blogging/README:
--------------------------------------------------------------------------------
1 | ====================================================================================================
2 | BLOGGING EXAMPLE APPLICATION
3 | ----------------------------------------------------------------------------------------------------
4 | This application supports the concept of a blog, blog entry, and blog entry comment, in hierarchical
5 | fashion. Which is roughly the concepts that a blogging system like WordPress supports. One could
6 | use these RESTful services to create a blogging system.
7 |
8 | This is a fully functional RestExpress application that utilizes the sub-projects, Syntaxe and
9 | RepoExpress for domain validation and object persistence, respectively. It also utilizes the
10 | MongoDB ObjectId as the ID for the persisted objects, which illustrates how to install your own
11 | object ID converters for persistence and XML and JSON marshaling.
12 |
13 | Additionally, the project illustrates how to map exceptions that are non-runtime exceptions
14 | (checked exceptions) into ServiceExceptions that RestExpress knows how to translate into an HTTP
15 | response.
16 |
17 | To run it, install and start MongoDB, then type 'mvn clean package exec:java'.
18 |
19 | The URL '/console/routes' will show you the routes available in the application
20 | (e.g. curl -i localhost:8081/console/routes.xml). Or simply look in the Routes.java file.
21 |
--------------------------------------------------------------------------------
/blogging/config/dev/environment.properties:
--------------------------------------------------------------------------------
1 | # Default is 8081
2 | #port = 3339
3 |
4 | thread.pool.size = 100
5 |
6 | # The base URL, used as a prefix for links returned in data.
7 | # default is http://localhost:
8 | #base.url = http://localhost:8081
9 |
10 | # A MongoDB URI/Connection string
11 | # see: http://docs.mongodb.org/manual/reference/connection-string/
12 | mongodb.uri = mongodb://localhost:27017/blogging_example
13 |
14 | #Configuration for the MetricsPlugin/Graphite
15 | metrics.isEnabled = true
16 | #metrics.machineName =
17 | metrics.prefix = web1.example.com
18 | metrics.graphite.isEnabled = false
19 | metrics.graphite.host = graphite.example.com
20 | metrics.graphite.port = 2003
21 | metrics.graphite.publishSeconds = 60
--------------------------------------------------------------------------------
/blogging/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | RestExpress-Blogging-Example
6 |
22 | A Basic, MongoDB-backed Blogging Service Suite
23 | https://github.com/RestExpress/RestExpress
24 | com.strategicgains.example
25 | restexpress-blogging-example
26 | 0.1-SNAPSHOT
27 | jar
28 |
29 |
30 |
31 | com.strategicgains
32 | RestExpress
33 | 0.11.3
34 |
35 |
36 | com.strategicgains
37 | HyperExpressPlugin
38 | 2.6
39 |
40 |
41 | com.strategicgains.plugin-express
42 | CacheControlPlugin
43 | 0.3.3
44 |
45 |
46 | com.strategicgains.plugin-express
47 | SwaggerPlugin
48 | 0.3.3
49 |
50 |
51 | com.strategicgains.plugin-express
52 | MetricsPlugin
53 | 0.3.3
54 |
55 |
56 | com.strategicgains.plugin-express
57 | CORSPlugin
58 | 0.3.3
59 |
60 |
61 | com.strategicgains
62 | Syntaxe
63 | 1.0
64 |
65 |
66 | com.strategicgains.repoexpress
67 | repoexpress-mongodb
68 | 0.4.8
69 |
70 |
71 | com.strategicgains.domain-eventing
72 | domain-eventing-core
73 | 1.0
74 |
75 |
76 | io.dropwizard.metrics
77 | metrics-graphite
78 | 3.1.2
79 |
80 |
81 | junit
82 | junit
83 | 4.11
84 | jar
85 | test
86 | true
87 |
88 |
89 |
90 |
91 | compile
92 |
93 |
94 | org.apache.maven.plugins
95 | maven-compiler-plugin
96 | 3.0
97 |
98 | 1.7
99 | 1.7
100 | UTF-8
101 |
102 |
103 |
104 | org.codehaus.mojo
105 | exec-maven-plugin
106 | 1.2.1
107 |
108 | org.restexpress.example.blogging.Main
109 |
110 |
111 |
112 | org.apache.maven.plugins
113 | maven-jar-plugin
114 | 2.4
115 |
116 |
117 | false
118 |
119 | true
120 | ./lib/
121 | org.restexpress.example.blogging.Main
122 |
123 |
124 |
125 |
126 |
127 | org.apache.maven.plugins
128 | maven-assembly-plugin
129 | 2.4
130 |
131 |
132 | zip-with-dependencies.xml
133 |
134 |
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/Configuration.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging;
2 |
3 | import java.util.Properties;
4 |
5 | import org.restexpress.RestExpress;
6 | import org.restexpress.example.blogging.controller.BlogController;
7 | import org.restexpress.example.blogging.controller.BlogEntryController;
8 | import org.restexpress.example.blogging.controller.CommentController;
9 | import org.restexpress.example.blogging.persistence.BlogEntryRepository;
10 | import org.restexpress.example.blogging.persistence.BlogRepository;
11 | import org.restexpress.example.blogging.persistence.CommentRepository;
12 | import org.restexpress.util.Environment;
13 |
14 | import com.strategicgains.repoexpress.mongodb.MongoConfig;
15 | import com.strategicgains.restexpress.plugin.metrics.MetricsConfig;
16 |
17 | public class Configuration
18 | extends Environment
19 | {
20 | private static final String DEFAULT_EXECUTOR_THREAD_POOL_SIZE = "20";
21 |
22 | private static final String PORT_PROPERTY = "port";
23 | private static final String BASE_URL_PROPERTY = "base.url";
24 | private static final String EXECUTOR_THREAD_POOL_SIZE = "thread.pool.size";
25 |
26 | private int port;
27 | private String baseUrl;
28 | private int executorThreadPoolSize;
29 | private MetricsConfig metricsSettings;
30 |
31 | private BlogEntryRepository blogEntryRepository;
32 | private CommentRepository commentRepository;
33 |
34 | private BlogController blogController;
35 | private BlogEntryController blogEntryController;
36 | private CommentController commentController;
37 |
38 | @Override
39 | protected void fillValues(Properties p)
40 | {
41 | this.port = Integer.parseInt(p.getProperty(PORT_PROPERTY, String.valueOf(RestExpress.DEFAULT_PORT)));
42 | this.baseUrl = p.getProperty(BASE_URL_PROPERTY, "http://localhost:" + String.valueOf(port));
43 | this.executorThreadPoolSize = Integer.parseInt(p.getProperty(EXECUTOR_THREAD_POOL_SIZE, DEFAULT_EXECUTOR_THREAD_POOL_SIZE));
44 | this.metricsSettings = new MetricsConfig(p);
45 | MongoConfig mongo = new MongoConfig(p);
46 | initialize(mongo);
47 | }
48 |
49 | private void initialize(MongoConfig mongo)
50 | {
51 | BlogRepository blogRepository = new BlogRepository(mongo.getClient(), mongo.getDbName());
52 | blogEntryRepository = new BlogEntryRepository(mongo.getClient(), mongo.getDbName());
53 | commentRepository = new CommentRepository(mongo.getClient(), mongo.getDbName());
54 |
55 | blogController = new BlogController(blogRepository);
56 | blogEntryController = new BlogEntryController(blogEntryRepository, blogRepository);
57 | commentController = new CommentController(commentRepository, blogEntryRepository, blogRepository);
58 | }
59 |
60 |
61 | // SECTION: ACCESSORS - PUBLIC
62 |
63 | public String getBaseUrl()
64 | {
65 | return baseUrl;
66 | }
67 |
68 | public int getPort()
69 | {
70 | return port;
71 | }
72 |
73 | public BlogController getBlogController()
74 | {
75 | return blogController;
76 | }
77 |
78 | public BlogEntryController getBlogEntryController()
79 | {
80 | return blogEntryController;
81 | }
82 |
83 | public CommentController getCommentController()
84 | {
85 | return commentController;
86 | }
87 |
88 | public int getExecutorThreadPoolSize()
89 | {
90 | return executorThreadPoolSize;
91 | }
92 |
93 | public MetricsConfig getMetricsConfig()
94 | {
95 | return metricsSettings;
96 | }
97 |
98 | public BlogEntryRepository getBlogEntryRepository()
99 | {
100 | return blogEntryRepository;
101 | }
102 |
103 | public CommentRepository getCommentRepository()
104 | {
105 | return commentRepository;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/Constants.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging;
2 |
3 | public class Constants
4 | {
5 | public class Routes
6 | {
7 | public static final String BLOGS_READ_ROUTE = "blog.read.collection.route";
8 | public static final String BLOG_READ_ROUTE = "blog.read.route";
9 | public static final String BLOG_ENTRY_READ_ROUTE = "blog-entry.read.route";
10 | public static final String BLOG_ENTRIES_READ_ROUTE = "blog-entry.read.collection.route";
11 | public static final String COMMENT_READ_ROUTE = "comment.read.route";
12 | public static final String COMMENTS_READ_ROUTE = "comment.read.collection.route";
13 | };
14 |
15 | public class Url
16 | {
17 | public static final String BLOG_ID_PARAMETER = "blogId";
18 | public static final String BLOG_ENTRY_ID_PARAMETER = "entryId";
19 | public static final String COMMENT_ID_PARAMETER = "commentId";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/Main.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging;
2 |
3 | import static io.netty.handler.codec.http.HttpHeaders.Names.ACCEPT;
4 | import static io.netty.handler.codec.http.HttpHeaders.Names.AUTHORIZATION;
5 | import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
6 | import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION;
7 | import static io.netty.handler.codec.http.HttpHeaders.Names.REFERER;
8 | import static org.restexpress.Flags.Auth.PUBLIC_ROUTE;
9 |
10 | import java.net.InetSocketAddress;
11 | import java.util.concurrent.TimeUnit;
12 |
13 | import org.restexpress.Flags;
14 | import org.restexpress.RestExpress;
15 | import org.restexpress.example.blogging.event.BlogCascadeDeleteHandler;
16 | import org.restexpress.example.blogging.event.BlogEntryCascadeDeleteHandler;
17 | import org.restexpress.example.blogging.postprocessor.LastModifiedHeaderPostprocessor;
18 | import org.restexpress.example.blogging.serialization.SerializationProvider;
19 | import org.restexpress.exception.BadRequestException;
20 | import org.restexpress.exception.ConflictException;
21 | import org.restexpress.exception.NotFoundException;
22 | import org.restexpress.pipeline.SimpleConsoleLogMessageObserver;
23 | import org.restexpress.plugin.hyperexpress.HyperExpressPlugin;
24 | import org.restexpress.plugin.hyperexpress.Linkable;
25 | import org.restexpress.util.Environment;
26 | import org.slf4j.Logger;
27 | import org.slf4j.LoggerFactory;
28 |
29 | import com.codahale.metrics.MetricFilter;
30 | import com.codahale.metrics.MetricRegistry;
31 | import com.codahale.metrics.graphite.Graphite;
32 | import com.codahale.metrics.graphite.GraphiteReporter;
33 | import com.strategicgains.eventing.DomainEvents;
34 | import com.strategicgains.eventing.EventBus;
35 | import com.strategicgains.eventing.local.LocalEventBusBuilder;
36 | import com.strategicgains.repoexpress.exception.DuplicateItemException;
37 | import com.strategicgains.repoexpress.exception.InvalidObjectIdException;
38 | import com.strategicgains.repoexpress.exception.ItemNotFoundException;
39 | import com.strategicgains.restexpress.plugin.cache.CacheControlPlugin;
40 | import com.strategicgains.restexpress.plugin.cors.CorsHeaderPlugin;
41 | import com.strategicgains.restexpress.plugin.metrics.MetricsConfig;
42 | import com.strategicgains.restexpress.plugin.metrics.MetricsPlugin;
43 | import com.strategicgains.restexpress.plugin.swagger.SwaggerPlugin;
44 | import com.strategicgains.syntaxe.ValidationException;
45 |
46 | public class Main
47 | {
48 | private static final String SERVICE_NAME = "Blogging Example";
49 | private static final Logger LOG = LoggerFactory.getLogger(SERVICE_NAME);
50 |
51 | public static void main(String[] args) throws Exception
52 | {
53 | RestExpress.setSerializationProvider(new SerializationProvider());
54 |
55 | Configuration config = Environment.load(args, Configuration.class);
56 | RestExpress server = new RestExpress()
57 | .setName(SERVICE_NAME)
58 | .setBaseUrl(config.getBaseUrl())
59 | .setExecutorThreadCount(config.getExecutorThreadPoolSize())
60 | .addPostprocessor(new LastModifiedHeaderPostprocessor())
61 | .addMessageObserver(new SimpleConsoleLogMessageObserver());
62 |
63 | Routes.define(config, server);
64 | Relationships.define(server);
65 | configurePlugins(config, server);
66 | mapExceptions(server);
67 | registerDomainEvents(server, config);
68 | server.bind(config.getPort());
69 | server.awaitShutdown();
70 | }
71 |
72 | private static void configurePlugins(Configuration config, RestExpress server)
73 | {
74 | configureMetrics(config, server);
75 |
76 | new SwaggerPlugin()
77 | .flag(Flags.Auth.PUBLIC_ROUTE)
78 | .register(server);
79 |
80 | new CacheControlPlugin() // Support caching headers.
81 | .register(server);
82 |
83 | new HyperExpressPlugin(Linkable.class)
84 | .register(server);
85 |
86 | new CorsHeaderPlugin("*")
87 | .flag(PUBLIC_ROUTE)
88 | .allowHeaders(CONTENT_TYPE, ACCEPT, AUTHORIZATION, REFERER, LOCATION)
89 | .exposeHeaders(LOCATION)
90 | .register(server);
91 | }
92 |
93 | private static void configureMetrics(Configuration config, RestExpress server)
94 | {
95 | MetricsConfig mc = config.getMetricsConfig();
96 |
97 | if (mc.isEnabled())
98 | {
99 | MetricRegistry registry = new MetricRegistry();
100 | new MetricsPlugin(registry)
101 | .register(server);
102 |
103 | if (mc.isGraphiteEnabled())
104 | {
105 | final Graphite graphite = new Graphite(new InetSocketAddress(mc.getGraphiteHost(), mc.getGraphitePort()));
106 | final GraphiteReporter reporter = GraphiteReporter.forRegistry(registry)
107 | .prefixedWith(mc.getPrefix())
108 | .convertRatesTo(TimeUnit.SECONDS)
109 | .convertDurationsTo(TimeUnit.MILLISECONDS)
110 | .filter(MetricFilter.ALL)
111 | .build(graphite);
112 | reporter.start(mc.getPublishSeconds(), TimeUnit.SECONDS);
113 | }
114 | else
115 | {
116 | LOG.warn("*** Graphite Metrics Publishing is Disabled ***");
117 | }
118 | }
119 | else
120 | {
121 | LOG.warn("*** Metrics Generation is Disabled ***");
122 | }
123 | }
124 |
125 | /**
126 | * @param server
127 | */
128 | private static void mapExceptions(RestExpress server)
129 | {
130 | server
131 | .mapException(ItemNotFoundException.class, NotFoundException.class)
132 | .mapException(DuplicateItemException.class, ConflictException.class)
133 | .mapException(ValidationException.class, BadRequestException.class)
134 | .mapException(InvalidObjectIdException.class, NotFoundException.class)
135 | .mapException(org.mongodb.morphia.query.ValidationException.class, BadRequestException.class);
136 | }
137 |
138 | private static void registerDomainEvents(RestExpress server, Configuration config)
139 | {
140 | EventBus localBus = new LocalEventBusBuilder()
141 | .subscribe(new BlogCascadeDeleteHandler(config.getBlogEntryRepository(), config.getCommentRepository()))
142 | .subscribe(new BlogEntryCascadeDeleteHandler(config.getCommentRepository()))
143 | .build();
144 | DomainEvents.addBus("local", localBus);
145 |
146 | Runtime.getRuntime().addShutdownHook(new Thread()
147 | {
148 | @Override
149 | public void run()
150 | {
151 | DomainEvents.shutdown();
152 | }
153 | });
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/Relationships.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging;
2 |
3 | import java.util.Map;
4 |
5 | import org.restexpress.RestExpress;
6 | import org.restexpress.example.blogging.domain.Blog;
7 | import org.restexpress.example.blogging.domain.BlogEntry;
8 | import org.restexpress.example.blogging.domain.Comment;
9 |
10 | import com.strategicgains.hyperexpress.HyperExpress;
11 | import com.strategicgains.hyperexpress.RelTypes;
12 |
13 | public abstract class Relationships
14 | {
15 | public static void define(RestExpress server)
16 | {
17 | Map routes = server.getRouteUrlsByName();
18 |
19 | HyperExpress.relationships()
20 | .forCollectionOf(Blog.class)
21 | .rel(RelTypes.SELF, routes.get(Constants.Routes.BLOGS_READ_ROUTE))
22 |
23 | .forClass(Blog.class)
24 | .rel(RelTypes.SELF, routes.get(Constants.Routes.BLOG_READ_ROUTE))
25 | .rel("entries", routes.get(Constants.Routes.BLOG_ENTRIES_READ_ROUTE))
26 |
27 | .forCollectionOf(BlogEntry.class)
28 | .asRel("entries")
29 | .rel(RelTypes.SELF, routes.get(Constants.Routes.BLOG_ENTRIES_READ_ROUTE))
30 | .withQuery("filter={filter}")
31 | .withQuery("limit={limit}")
32 | .withQuery("offset={offset}")
33 | .rel(RelTypes.NEXT, routes.get(Constants.Routes.BLOG_ENTRIES_READ_ROUTE) + "?offset={nextOffset}")
34 | .withQuery("filter={filter}")
35 | .withQuery("limit={limit}")
36 | .optional()
37 | .rel(RelTypes.PREV, routes.get(Constants.Routes.BLOG_ENTRIES_READ_ROUTE) + "?offset={prevOffset}")
38 | .withQuery("filter={filter}")
39 | .withQuery("limit={limit}")
40 | .optional()
41 | .rel(RelTypes.UP, routes.get(Constants.Routes.BLOG_READ_ROUTE))
42 |
43 | .forClass(BlogEntry.class)
44 | .rel(RelTypes.SELF, routes.get(Constants.Routes.BLOG_ENTRY_READ_ROUTE))
45 | .rel(RelTypes.UP, routes.get(Constants.Routes.BLOG_ENTRIES_READ_ROUTE))
46 | .rel("comments", routes.get(Constants.Routes.COMMENTS_READ_ROUTE))
47 |
48 | .forCollectionOf(Comment.class)
49 | .rel(RelTypes.SELF, routes.get(Constants.Routes.COMMENTS_READ_ROUTE))
50 | .withQuery("filter={filter}")
51 | .withQuery("limit={limit}")
52 | .withQuery("offset={offset}")
53 | .rel(RelTypes.NEXT, routes.get(Constants.Routes.COMMENTS_READ_ROUTE) + "?offset={nextOffset}")
54 | .withQuery("filter={filter}")
55 | .withQuery("limit={limit}")
56 | .optional()
57 | .rel(RelTypes.PREV, routes.get(Constants.Routes.COMMENTS_READ_ROUTE) + "?offset={prevOffset}")
58 | .withQuery("filter={filter}")
59 | .withQuery("limit={limit}")
60 | .optional()
61 | .rel(RelTypes.UP, routes.get(Constants.Routes.COMMENT_READ_ROUTE))
62 |
63 | .forClass(Comment.class)
64 | .rel(RelTypes.SELF, routes.get(Constants.Routes.COMMENT_READ_ROUTE))
65 | .rel(RelTypes.UP, routes.get(Constants.Routes.COMMENTS_READ_ROUTE));
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/Routes.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging;
2 |
3 | import io.netty.handler.codec.http.HttpMethod;
4 |
5 | import org.restexpress.RestExpress;
6 |
7 | public abstract class Routes
8 | {
9 | public static void define(Configuration config, RestExpress server)
10 | {
11 | server.uri("/blogs.{format}", config.getBlogController())
12 | .action("readAll", HttpMethod.GET)
13 | .method(HttpMethod.POST)
14 | .name(Constants.Routes.BLOGS_READ_ROUTE);
15 |
16 | server.uri("/blogs/{blogId}.{format}", config.getBlogController())
17 | .method(HttpMethod.GET, HttpMethod.PUT, HttpMethod.DELETE)
18 | .name(Constants.Routes.BLOG_READ_ROUTE);
19 |
20 | server.uri("/blogs/{blogId}/entries.{format}", config.getBlogEntryController())
21 | .action("readAll", HttpMethod.GET)
22 | .method(HttpMethod.POST)
23 | .name(Constants.Routes.BLOG_ENTRIES_READ_ROUTE);
24 |
25 | server.uri("/blogs/{blogId}/entries/{entryId}.{format}", config.getBlogEntryController())
26 | .method(HttpMethod.GET, HttpMethod.PUT, HttpMethod.DELETE)
27 | .name(Constants.Routes.BLOG_ENTRY_READ_ROUTE);
28 |
29 | server.uri("/blogs/{blogId}/entries/{entryId}/comments.{format}", config.getCommentController())
30 | .action("readAll", HttpMethod.GET)
31 | .method(HttpMethod.POST)
32 | .name(Constants.Routes.COMMENTS_READ_ROUTE);
33 |
34 | server.uri("/blogs/{blogId}/entries/{entryId}/comments/{commentId}.{format}", config.getCommentController())
35 | .method(HttpMethod.GET, HttpMethod.PUT, HttpMethod.DELETE)
36 | .name(Constants.Routes.COMMENT_READ_ROUTE);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/controller/BlogController.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.controller;
2 |
3 | import static com.strategicgains.repoexpress.adapter.Identifiers.UUID;
4 |
5 | import java.util.List;
6 |
7 | import org.restexpress.Request;
8 | import org.restexpress.Response;
9 | import org.restexpress.common.query.QueryFilter;
10 | import org.restexpress.common.query.QueryOrder;
11 | import org.restexpress.common.query.QueryRange;
12 | import org.restexpress.example.blogging.Constants;
13 | import org.restexpress.example.blogging.domain.Blog;
14 | import org.restexpress.example.blogging.persistence.BlogRepository;
15 | import org.restexpress.query.QueryFilters;
16 | import org.restexpress.query.QueryOrders;
17 | import org.restexpress.query.QueryRanges;
18 |
19 | import com.strategicgains.hyperexpress.builder.DefaultTokenResolver;
20 | import com.strategicgains.hyperexpress.builder.DefaultUrlBuilder;
21 | import com.strategicgains.hyperexpress.builder.UrlBuilder;
22 | import com.strategicgains.syntaxe.ValidationEngine;
23 |
24 | import io.netty.handler.codec.http.HttpMethod;
25 |
26 | public class BlogController
27 | {
28 | private static final UrlBuilder LOCATION_BUILDER = new DefaultUrlBuilder();
29 | private BlogRepository blogs;
30 |
31 | public BlogController(BlogRepository blogRepository)
32 | {
33 | super();
34 | this.blogs = blogRepository;
35 | }
36 |
37 | public Blog create(Request request, Response response)
38 | {
39 | Blog blog = request.getBodyAs(Blog.class, "Blog details not provided");
40 | ValidationEngine.validateAndThrow(blog);
41 | Blog saved = blogs.create(blog);
42 |
43 | // Construct the response for create...
44 | response.setResponseCreated();
45 |
46 | // Include the Location header...
47 | String locationPattern = request.getNamedUrl(HttpMethod.GET, Constants.Routes.BLOG_ENTRY_READ_ROUTE);
48 | response.addLocationHeader(LOCATION_BUILDER.build(locationPattern, new DefaultTokenResolver()));
49 |
50 | // Return the newly-created item...
51 | return saved;
52 | }
53 |
54 | public Blog read(Request request, Response response)
55 | {
56 | String id = request.getHeader(Constants.Url.BLOG_ID_PARAMETER, "No Blog ID supplied");
57 | Blog entity = blogs.read(UUID.parse(id));
58 |
59 | return entity;
60 | }
61 |
62 | public List readAll(Request request, Response response)
63 | {
64 | QueryFilter filter = QueryFilters.parseFrom(request);
65 | QueryOrder order = QueryOrders.parseFrom(request);
66 | QueryRange range = QueryRanges.parseFrom(request, 20);
67 | List entities = blogs.readAll(filter, range, order);
68 | response.setCollectionResponse(range, entities.size(), blogs.count(filter));
69 |
70 | return entities;
71 | }
72 |
73 | public void update(Request request, Response response)
74 | {
75 | String id = request.getHeader(Constants.Url.BLOG_ID_PARAMETER);
76 | Blog blog = request.getBodyAs(Blog.class, "Blog details not provided");
77 |
78 | // Can't change the blod ID via update.
79 | blog.setId(UUID.parse(id));
80 |
81 | ValidationEngine.validateAndThrow(blog);
82 | blogs.update(blog);
83 | response.setResponseNoContent();
84 | }
85 |
86 | public void delete(Request request, Response response)
87 | {
88 | String id = request.getHeader(Constants.Url.BLOG_ID_PARAMETER, "No Blog ID supplied");
89 | blogs.delete(UUID.parse(id));
90 | response.setResponseNoContent();
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/controller/BlogEntryController.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.controller;
2 |
3 | import static com.strategicgains.repoexpress.adapter.Identifiers.UUID;
4 |
5 | import java.util.List;
6 |
7 | import org.restexpress.Request;
8 | import org.restexpress.Response;
9 | import org.restexpress.common.query.FilterOperator;
10 | import org.restexpress.common.query.QueryFilter;
11 | import org.restexpress.common.query.QueryOrder;
12 | import org.restexpress.common.query.QueryRange;
13 | import org.restexpress.example.blogging.Constants;
14 | import org.restexpress.example.blogging.domain.Blog;
15 | import org.restexpress.example.blogging.domain.BlogEntry;
16 | import org.restexpress.example.blogging.persistence.BlogEntryRepository;
17 | import org.restexpress.example.blogging.persistence.BlogRepository;
18 | import org.restexpress.query.QueryFilters;
19 | import org.restexpress.query.QueryOrders;
20 | import org.restexpress.query.QueryRanges;
21 |
22 | import com.strategicgains.hyperexpress.builder.DefaultTokenResolver;
23 | import com.strategicgains.hyperexpress.builder.DefaultUrlBuilder;
24 | import com.strategicgains.hyperexpress.builder.UrlBuilder;
25 | import com.strategicgains.repoexpress.util.UuidConverter;
26 | import com.strategicgains.syntaxe.ValidationEngine;
27 |
28 | import io.netty.handler.codec.http.HttpMethod;
29 |
30 | public class BlogEntryController
31 | {
32 | private static final UrlBuilder LOCATION_BUILDER = new DefaultUrlBuilder();
33 | private BlogEntryRepository blogEntries;
34 | private BlogRepository blogs;
35 |
36 | public BlogEntryController(BlogEntryRepository blogEntryRepository, BlogRepository blogRepository)
37 | {
38 | super();
39 | this.blogEntries = blogEntryRepository;
40 | this.blogs = blogRepository;
41 | }
42 |
43 | public BlogEntry create(Request request, Response response)
44 | {
45 | String blogId = request.getHeader(Constants.Url.BLOG_ID_PARAMETER, "No Blog ID provided");
46 | BlogEntry blogEntry = request.getBodyAs(BlogEntry.class, "BlogEntry details not provided");
47 | Blog blog = blogs.read(UUID.parse(blogId));
48 | blogEntry.setBlogId(blog.getUuid());
49 | ValidationEngine.validateAndThrow(blogEntry);
50 | BlogEntry saved = blogEntries.create(blogEntry);
51 |
52 | // Construct the response for create...
53 | response.setResponseCreated();
54 |
55 | // Include the Location header...
56 | String locationPattern = request.getNamedUrl(HttpMethod.GET, Constants.Routes.BLOG_ENTRY_READ_ROUTE);
57 | response.addLocationHeader(LOCATION_BUILDER.build(locationPattern, new DefaultTokenResolver()));
58 |
59 | // Return the newly-created item...
60 | return saved;
61 | }
62 |
63 | public BlogEntry read(Request request, Response response)
64 | {
65 | String id = request.getHeader(Constants.Url.BLOG_ENTRY_ID_PARAMETER, "No BlogEntry ID supplied");
66 | BlogEntry entity = blogEntries.read(UUID.parse(id));
67 | return entity;
68 | }
69 |
70 | public List readAll(Request request, Response response)
71 | {
72 | String blogId = request.getHeader(Constants.Url.BLOG_ID_PARAMETER, "Blog ID not provided");
73 | QueryFilter filter = QueryFilters.parseFrom(request);
74 | QueryOrder order = QueryOrders.parseFrom(request);
75 | QueryRange range = QueryRanges.parseFrom(request, 20);
76 |
77 | filter.addCriteria("blogId", FilterOperator.EQUALS, UuidConverter.parse(blogId));
78 | List results = blogEntries.readAll(filter, range, order);
79 | response.setCollectionResponse(range, results.size(), blogEntries.count(filter));
80 |
81 | return results;
82 | }
83 |
84 | public void update(Request request, Response response)
85 | {
86 | String blogId = request.getHeader(Constants.Url.BLOG_ID_PARAMETER, "Blog ID not provided");
87 | String id = request.getHeader(Constants.Url.BLOG_ENTRY_ID_PARAMETER);
88 | BlogEntry blogEntry = request.getBodyAs(BlogEntry.class, "BlogEntry details not provided");
89 |
90 | // Cannot change the blog, blog entry IDs via update.
91 | Blog blog = blogs.read(UUID.parse(blogId));
92 | blogEntry.setBlogId(blog.getUuid());
93 | blogEntry.setId(UUID.parse(id));
94 |
95 | ValidationEngine.validateAndThrow(blogEntry);
96 | blogEntries.update(blogEntry);
97 | response.setResponseNoContent();
98 | }
99 |
100 | public void delete(Request request, Response response)
101 | {
102 | String id = request.getHeader(Constants.Url.BLOG_ENTRY_ID_PARAMETER, "No BlogEntry ID supplied");
103 | blogEntries.delete(UUID.parse(id));
104 | response.setResponseNoContent();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/controller/CommentController.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.controller;
2 |
3 | import static com.strategicgains.repoexpress.adapter.Identifiers.UUID;
4 |
5 | import java.util.List;
6 |
7 | import org.restexpress.Request;
8 | import org.restexpress.Response;
9 | import org.restexpress.common.query.FilterOperator;
10 | import org.restexpress.common.query.QueryFilter;
11 | import org.restexpress.common.query.QueryOrder;
12 | import org.restexpress.common.query.QueryRange;
13 | import org.restexpress.example.blogging.Constants;
14 | import org.restexpress.example.blogging.domain.Blog;
15 | import org.restexpress.example.blogging.domain.BlogEntry;
16 | import org.restexpress.example.blogging.domain.Comment;
17 | import org.restexpress.example.blogging.persistence.BlogEntryRepository;
18 | import org.restexpress.example.blogging.persistence.BlogRepository;
19 | import org.restexpress.example.blogging.persistence.CommentRepository;
20 | import org.restexpress.query.QueryFilters;
21 | import org.restexpress.query.QueryOrders;
22 | import org.restexpress.query.QueryRanges;
23 |
24 | import com.strategicgains.hyperexpress.HyperExpress;
25 | import com.strategicgains.hyperexpress.builder.DefaultUrlBuilder;
26 | import com.strategicgains.hyperexpress.builder.TokenBinder;
27 | import com.strategicgains.hyperexpress.builder.TokenResolver;
28 | import com.strategicgains.hyperexpress.builder.UrlBuilder;
29 | import com.strategicgains.repoexpress.util.UuidConverter;
30 | import com.strategicgains.syntaxe.ValidationEngine;
31 |
32 | import io.netty.handler.codec.http.HttpMethod;
33 |
34 | public class CommentController
35 | {
36 | private static final UrlBuilder LOCATION_BUILDER = new DefaultUrlBuilder();
37 | private CommentRepository comments;
38 | private BlogEntryRepository entries;
39 | private BlogRepository blogs;
40 |
41 | public CommentController(CommentRepository commentRepository, BlogEntryRepository blogEntryRepository, BlogRepository blogRepository)
42 | {
43 | super();
44 | this.comments = commentRepository;
45 | this.entries = blogEntryRepository;
46 | this.blogs = blogRepository;
47 | }
48 |
49 | public Comment create(Request request, Response response)
50 | {
51 | Comment comment = request.getBodyAs(Comment.class, "Comment details not provided");
52 | String blogId = request.getHeader(Constants.Url.BLOG_ID_PARAMETER, "Blog ID not provided");
53 | String blogEntryId = request.getHeader(Constants.Url.BLOG_ENTRY_ID_PARAMETER, "Blog Entry ID not provided");
54 | Blog blog = blogs.read(UUID.parse(blogId));
55 | BlogEntry entry = entries.read(UUID.parse(blogEntryId));
56 | comment.setBlogEntryId(entry.getUuid());
57 | ValidationEngine.validateAndThrow(comment);
58 | Comment saved = comments.create(comment);
59 |
60 | // Construct the response for create...
61 | response.setResponseCreated();
62 |
63 | // Bind the resource with link URL tokens, etc. here...
64 | TokenResolver resolver = HyperExpress.bind(Constants.Url.BLOG_ID_PARAMETER, UUID.format(blog.getUuid()));
65 |
66 | // Include the Location header...
67 | String locationPattern = request.getNamedUrl(HttpMethod.GET, Constants.Routes.COMMENT_READ_ROUTE);
68 | response.addLocationHeader(LOCATION_BUILDER.build(locationPattern, resolver));
69 |
70 | // Return the newly-created item...
71 | return saved;
72 | }
73 |
74 | public Comment read(Request request, Response response)
75 | {
76 | String id = request.getHeader(Constants.Url.COMMENT_ID_PARAMETER, "No Comment ID supplied");
77 | String blogId = request.getHeader(Constants.Url.BLOG_ID_PARAMETER, "Blog ID not provided");
78 | String blogEntryId = request.getHeader(Constants.Url.BLOG_ENTRY_ID_PARAMETER, "Blog Entry ID not provided");
79 | Blog blog = blogs.read(UUID.parse(blogId));
80 | entries.read(UUID.parse(blogEntryId));
81 | Comment entity = comments.read(UUID.parse(id));
82 |
83 | // Bind the resource with link URL tokens, etc. here...
84 | HyperExpress.bind(Constants.Url.BLOG_ID_PARAMETER, UUID.format(blog.getUuid()));
85 |
86 | return entity;
87 | }
88 |
89 | public List readAll(Request request, Response response)
90 | {
91 | String blogId = request.getHeader(Constants.Url.BLOG_ID_PARAMETER, "No Blog ID supplied");
92 | String blogEntryId = request.getHeader(Constants.Url.BLOG_ENTRY_ID_PARAMETER, "No Blog Entry ID supplied");
93 | final Blog blog = blogs.read(UUID.parse(blogId));
94 | entries.read(UUID.parse(blogEntryId));
95 |
96 | QueryFilter filter = QueryFilters.parseFrom(request);
97 | QueryOrder order = QueryOrders.parseFrom(request);
98 | QueryRange range = QueryRanges.parseFrom(request, 20);
99 |
100 | filter.addCriteria("blogEntryId", FilterOperator.EQUALS, UuidConverter.parse(blogEntryId));
101 | List entities = comments.readAll(filter, range, order);
102 | response.setCollectionResponse(range, entities.size(), comments.count(filter));
103 |
104 | // Bind the resources in the collection with link URL tokens, etc. here...
105 | HyperExpress.tokenBinder(new TokenBinder()
106 | {
107 | @Override
108 | public void bind(Comment entity, TokenResolver resolver)
109 | {
110 | resolver.bind(Constants.Url.BLOG_ID_PARAMETER, UUID.format(blog.getUuid()));
111 | }
112 | });
113 |
114 | return entities;
115 | }
116 |
117 | public void update(Request request, Response response)
118 | {
119 | String id = request.getHeader(Constants.Url.COMMENT_ID_PARAMETER, "No Comment ID supplied");
120 | String blogEntryId = request.getHeader(Constants.Url.BLOG_ENTRY_ID_PARAMETER, "Blog Entry ID not provided");
121 | Comment comment = request.getBodyAs(Comment.class, "Comment details not provided");
122 | BlogEntry entry = entries.read(UUID.parse(blogEntryId));
123 |
124 | // Cannot change entry, comment IDs on update.
125 | comment.setId(UUID.parse(id));
126 | comment.setBlogEntryId(entry.getUuid());
127 | ValidationEngine.validateAndThrow(comment);
128 | comments.update(comment);
129 | response.setResponseNoContent();
130 | }
131 |
132 | public void delete(Request request, Response response)
133 | {
134 | String id = request.getHeader(Constants.Url.COMMENT_ID_PARAMETER, "No Comment ID supplied");
135 | comments.delete(UUID.parse(id));
136 | response.setResponseNoContent();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/AbstractEntity.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain;
2 |
3 | import org.restexpress.plugin.hyperexpress.Linkable;
4 |
5 | import com.strategicgains.repoexpress.mongodb.AbstractUuidMongodbEntity;
6 |
7 | public class AbstractEntity
8 | extends AbstractUuidMongodbEntity
9 | implements Linkable
10 | {
11 | }
12 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/Blog.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain;
2 |
3 | import org.mongodb.morphia.annotations.Entity;
4 | import org.restexpress.example.blogging.Constants;
5 | import org.restexpress.example.blogging.serialization.UuidFormatter;
6 |
7 | import com.strategicgains.hyperexpress.annotation.BindToken;
8 | import com.strategicgains.hyperexpress.annotation.TokenBindings;
9 | import com.strategicgains.syntaxe.annotation.StringValidation;
10 |
11 | @Entity("blogs")
12 | @TokenBindings({
13 | @BindToken(value=Constants.Url.BLOG_ID_PARAMETER, field="id", formatter=UuidFormatter.class)
14 | })
15 | public class Blog
16 | extends AbstractEntity
17 | {
18 | @StringValidation(name = "Blog Title", required = true)
19 | private String title;
20 | private String description;
21 |
22 | public String getTitle()
23 | {
24 | return title;
25 | }
26 |
27 | public void setTitle(String title)
28 | {
29 | this.title = title;
30 | }
31 |
32 | public String getDescription()
33 | {
34 | return description;
35 | }
36 |
37 | public void setDescription(String description)
38 | {
39 | this.description = description;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/BlogEntry.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain;
2 |
3 | import java.util.UUID;
4 |
5 | import org.mongodb.morphia.annotations.Entity;
6 | import org.mongodb.morphia.annotations.Indexed;
7 | import org.restexpress.example.blogging.Constants;
8 | import org.restexpress.example.blogging.serialization.UuidFormatter;
9 |
10 | import com.strategicgains.hyperexpress.annotation.BindToken;
11 | import com.strategicgains.hyperexpress.annotation.TokenBindings;
12 | import com.strategicgains.syntaxe.annotation.Required;
13 | import com.strategicgains.syntaxe.annotation.StringValidation;
14 |
15 | @Entity("blog_entries")
16 | @TokenBindings({
17 | @BindToken(value=Constants.Url.BLOG_ENTRY_ID_PARAMETER, field="id", formatter=UuidFormatter.class)
18 | })
19 | public class BlogEntry
20 | extends AbstractEntity
21 | {
22 | @Indexed
23 | @Required("Blog ID")
24 | @BindToken(value=Constants.Url.BLOG_ID_PARAMETER, formatter=UuidFormatter.class)
25 | private UUID blogId;
26 |
27 | @StringValidation(name="Title", required=true)
28 | private String title;
29 |
30 | @StringValidation(name="Entry Content", required=true)
31 | private String content;
32 |
33 | @Indexed
34 | @StringValidation(name="Author", required=true)
35 | private String author;
36 |
37 | public UUID getBlogId()
38 | {
39 | return blogId;
40 | }
41 |
42 | public void setBlogId(UUID blogId)
43 | {
44 | this.blogId = blogId;
45 | }
46 |
47 | public String getTitle()
48 | {
49 | return title;
50 | }
51 |
52 | public void setTitle(String title)
53 | {
54 | this.title = title;
55 | }
56 |
57 | public String getContent()
58 | {
59 | return content;
60 | }
61 |
62 | public void setContent(String content)
63 | {
64 | this.content = content;
65 | }
66 |
67 | public String getAuthor()
68 | {
69 | return author;
70 | }
71 |
72 | public void setAuthor(String author)
73 | {
74 | this.author = author;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/Comment.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain;
2 |
3 | import java.util.UUID;
4 |
5 | import org.mongodb.morphia.annotations.Entity;
6 | import org.mongodb.morphia.annotations.Index;
7 | import org.mongodb.morphia.annotations.Indexed;
8 | import org.mongodb.morphia.annotations.Indexes;
9 | import org.restexpress.example.blogging.Constants;
10 | import org.restexpress.example.blogging.serialization.UuidFormatter;
11 |
12 | import com.strategicgains.hyperexpress.annotation.BindToken;
13 | import com.strategicgains.hyperexpress.annotation.TokenBindings;
14 | import com.strategicgains.syntaxe.annotation.Required;
15 | import com.strategicgains.syntaxe.annotation.StringValidation;
16 |
17 | @Entity("comments")
18 | @Indexes({
19 | @Index("createdAt")
20 | })
21 | @TokenBindings({
22 | @BindToken(value=Constants.Url.COMMENT_ID_PARAMETER, field="id", formatter=UuidFormatter.class)
23 | })
24 | public class Comment
25 | extends AbstractEntity
26 | {
27 | @Indexed
28 | @Required("Blog Entry ID")
29 | @BindToken(value=Constants.Url.BLOG_ENTRY_ID_PARAMETER, formatter=UuidFormatter.class)
30 | private UUID blogEntryId;
31 |
32 | @StringValidation(name="Author", required=true)
33 | private String author;
34 |
35 | @StringValidation(name="Comment Content", required=true)
36 | private String content;
37 |
38 | public UUID getBlogEntryId()
39 | {
40 | return blogEntryId;
41 | }
42 |
43 | public void setBlogEntryId(UUID blogEntryId)
44 | {
45 | this.blogEntryId = blogEntryId;
46 | }
47 |
48 | public String getAuthor()
49 | {
50 | return author;
51 | }
52 |
53 | public void setAuthor(String author)
54 | {
55 | this.author = author;
56 | }
57 |
58 | public String getContent()
59 | {
60 | return content;
61 | }
62 |
63 | public void setContent(String content)
64 | {
65 | this.content = content;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/event/BlogDeletedEvent.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain.event;
2 |
3 | import java.util.UUID;
4 |
5 | import org.restexpress.example.blogging.domain.Blog;
6 |
7 | public class BlogDeletedEvent
8 | {
9 | public UUID blogId;
10 |
11 | public BlogDeletedEvent(Blog deleted)
12 | {
13 | this.blogId = deleted.getUuid();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/event/BlogEntryDeletedEvent.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain.event;
2 |
3 | import java.util.UUID;
4 |
5 | import org.restexpress.example.blogging.domain.BlogEntry;
6 |
7 | public class BlogEntryDeletedEvent
8 | {
9 | public UUID blogEntryId;
10 |
11 | public BlogEntryDeletedEvent(BlogEntry deleted)
12 | {
13 | this.blogEntryId = deleted.getUuid();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/event/CommentDeletedEvent.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain.event;
2 |
3 | import java.util.UUID;
4 |
5 | import org.restexpress.example.blogging.domain.Comment;
6 |
7 | public class CommentDeletedEvent
8 | {
9 | public UUID commentId;
10 |
11 | public CommentDeletedEvent(Comment deleted)
12 | {
13 | this.commentId = deleted.getUuid();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/event/ObjectCreatedEvent.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain.event;
2 |
3 | public class ObjectCreatedEvent extends StateChangeEvent
4 | {
5 | public ObjectCreatedEvent(Object data)
6 | {
7 | super("created", data);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/event/ObjectDeletedEvent.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain.event;
2 |
3 | public class ObjectDeletedEvent extends StateChangeEvent
4 | {
5 | public ObjectDeletedEvent(Object data)
6 | {
7 | super("deleted", data);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/event/ObjectUpdatedEvent.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain.event;
2 |
3 | public class ObjectUpdatedEvent extends StateChangeEvent
4 | {
5 | public Object after;
6 |
7 | public ObjectUpdatedEvent(Object before, Object after)
8 | {
9 | super("updated", before);
10 | this.after = after;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/domain/event/StateChangeEvent.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.domain.event;
2 |
3 | public class StateChangeEvent
4 | {
5 | public Object data;
6 | public String changeType;
7 |
8 | public StateChangeEvent(String changeType, Object data)
9 | {
10 | this.data = data;
11 | this.changeType = changeType;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/event/BlogCascadeDeleteHandler.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.event;
2 |
3 | import java.util.UUID;
4 |
5 | import org.restexpress.example.blogging.domain.event.BlogDeletedEvent;
6 | import org.restexpress.example.blogging.persistence.BlogEntryRepository;
7 | import org.restexpress.example.blogging.persistence.CommentRepository;
8 |
9 | import com.strategicgains.eventing.EventHandler;
10 |
11 | public class BlogCascadeDeleteHandler
12 | implements EventHandler
13 | {
14 | private BlogEntryRepository blogEntries;
15 | private CommentRepository comments;
16 |
17 | public BlogCascadeDeleteHandler(BlogEntryRepository blogEntryRepo, CommentRepository commentRepo)
18 | {
19 | this.blogEntries = blogEntryRepo;
20 | this.comments = commentRepo;
21 | }
22 |
23 | @Override
24 | public void handle(Object event)
25 | throws Exception
26 | {
27 | System.out.println("Cascade-deleting blog...");
28 | UUID blogId = ((BlogDeletedEvent) event).blogId;
29 |
30 | // Delete the comments for every blog entry within this blog.
31 | comments.deleteByBlogEntryIds(blogEntries.findIdsByBlogId(blogId));
32 |
33 | // Now delete all the blog entries in this blog.
34 | blogEntries.deleteByBlogId(blogId);
35 | }
36 |
37 | @Override
38 | public boolean handles(Class> type)
39 | {
40 | return BlogDeletedEvent.class.isAssignableFrom(type);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/event/BlogEntryCascadeDeleteHandler.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.event;
2 |
3 | import java.util.UUID;
4 |
5 | import org.restexpress.example.blogging.domain.event.BlogEntryDeletedEvent;
6 | import org.restexpress.example.blogging.persistence.CommentRepository;
7 |
8 | import com.strategicgains.eventing.EventHandler;
9 |
10 | public class BlogEntryCascadeDeleteHandler
11 | implements EventHandler
12 | {
13 | private CommentRepository comments;
14 |
15 | public BlogEntryCascadeDeleteHandler(CommentRepository service)
16 | {
17 | this.comments = service;
18 | }
19 |
20 | @Override
21 | public void handle(Object event)
22 | throws Exception
23 | {
24 | System.out.println("Cascade-deleting a blog entry...");
25 | UUID blogEntryId = ((BlogEntryDeletedEvent) event).blogEntryId;
26 |
27 | // "Cascade-delete" the comments for this blog entry.
28 | comments.deleteByBlogEntryId(blogEntryId);
29 | }
30 |
31 | @Override
32 | public boolean handles(Class> type)
33 | {
34 | return BlogEntryDeletedEvent.class.isAssignableFrom(type);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/persistence/BaseBloggingRepository.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.persistence;
2 |
3 | import com.mongodb.MongoClient;
4 | import com.strategicgains.repoexpress.mongodb.AbstractUuidMongodbEntity;
5 | import com.strategicgains.repoexpress.mongodb.MongodbUuidEntityRepository;
6 |
7 | public class BaseBloggingRepository
8 | extends MongodbUuidEntityRepository
9 | {
10 | public BaseBloggingRepository(MongoClient mongo, String databaseName, Class... types)
11 | {
12 | super(mongo, databaseName, types);
13 | }
14 |
15 | @Override
16 | protected void initializeObservers()
17 | {
18 | super.initializeObservers();
19 | addObserver(new StateChangeEventingObserver(this));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/persistence/BlogEntryRepository.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.persistence;
2 |
3 | import java.util.UUID;
4 |
5 | import org.mongodb.morphia.query.Query;
6 | import org.restexpress.example.blogging.domain.BlogEntry;
7 |
8 | import com.mongodb.MongoClient;
9 | import com.strategicgains.repoexpress.domain.Identifier;
10 | import com.strategicgains.repoexpress.util.IdentifiableIterable;
11 |
12 | public class BlogEntryRepository
13 | extends BaseBloggingRepository
14 | {
15 | @SuppressWarnings("unchecked")
16 | public BlogEntryRepository(MongoClient mongo, String databaseName)
17 | {
18 | super(mongo, databaseName, BlogEntry.class);
19 | }
20 |
21 | public Iterable findIdsByBlogId(UUID blogId)
22 | {
23 | Query blogEntries = getDataStore().createQuery(BlogEntry.class).field("blogId").equal(blogId).retrievedFields(true, "_id");
24 | return new IdentifiableIterable(blogEntries.fetch());
25 | }
26 |
27 | public void deleteByBlogId(UUID blogId)
28 | {
29 | Query blogEntries = getDataStore().createQuery(BlogEntry.class).field("blogId").equal(blogId);
30 | getDataStore().delete(blogEntries);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/persistence/BlogRepository.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.persistence;
2 |
3 | import org.restexpress.example.blogging.domain.Blog;
4 |
5 | import com.mongodb.MongoClient;
6 |
7 | public class BlogRepository
8 | extends BaseBloggingRepository
9 | {
10 | @SuppressWarnings("unchecked")
11 | public BlogRepository(MongoClient mongo, String databaseName)
12 | {
13 | super(mongo, databaseName, Blog.class);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/persistence/CommentRepository.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.persistence;
2 |
3 | import java.util.UUID;
4 |
5 | import org.mongodb.morphia.query.Query;
6 | import org.restexpress.example.blogging.domain.Comment;
7 |
8 | import com.mongodb.MongoClient;
9 | import com.strategicgains.repoexpress.domain.Identifier;
10 |
11 | public class CommentRepository
12 | extends BaseBloggingRepository
13 | {
14 | @SuppressWarnings("unchecked")
15 | public CommentRepository(MongoClient mongo, String databaseName)
16 | {
17 | super(mongo, databaseName, Comment.class);
18 | }
19 |
20 | public void deleteByBlogEntryId(UUID blogEntryId)
21 | {
22 | Query comments = getDataStore().createQuery(Comment.class).field("blogEntryId").equal(blogEntryId);
23 | getDataStore().delete(comments);
24 | }
25 |
26 | public void deleteByBlogEntryIds(Iterable blogEntryIds)
27 | {
28 | if (blogEntryIds.iterator().hasNext())
29 | {
30 | Query comments = getDataStore().createQuery(Comment.class).field("blogEntryId").in(blogEntryIds);
31 | getDataStore().delete(comments);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/persistence/StateChangeEventingObserver.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.persistence;
2 |
3 | import org.restexpress.example.blogging.domain.Blog;
4 | import org.restexpress.example.blogging.domain.BlogEntry;
5 | import org.restexpress.example.blogging.domain.event.BlogDeletedEvent;
6 | import org.restexpress.example.blogging.domain.event.BlogEntryDeletedEvent;
7 | import org.restexpress.example.blogging.domain.event.ObjectCreatedEvent;
8 | import org.restexpress.example.blogging.domain.event.ObjectDeletedEvent;
9 | import org.restexpress.example.blogging.domain.event.ObjectUpdatedEvent;
10 |
11 | import com.strategicgains.eventing.DomainEvents;
12 | import com.strategicgains.repoexpress.Repository;
13 | import com.strategicgains.repoexpress.domain.TimestampedIdentifiable;
14 | import com.strategicgains.repoexpress.event.AbstractRepositoryObserver;
15 |
16 | public class StateChangeEventingObserver
17 | extends AbstractRepositoryObserver
18 | {
19 | private Repository repo;
20 |
21 | public StateChangeEventingObserver(Repository repo)
22 | {
23 | super();
24 | this.repo = repo;
25 | }
26 |
27 | @Override
28 | public void afterCreate(T object)
29 | {
30 | DomainEvents.publish(new ObjectCreatedEvent(object));
31 | }
32 |
33 | @Override
34 | public void beforeDelete(T object)
35 | {
36 | DomainEvents.publish(new ObjectDeletedEvent(object));
37 |
38 | if (Blog.class.isAssignableFrom(object.getClass()))
39 | {
40 | DomainEvents.publish(new BlogDeletedEvent((Blog) object));
41 | }
42 | else if (BlogEntry.class.isAssignableFrom(object.getClass()))
43 | {
44 | DomainEvents.publish(new BlogEntryDeletedEvent((BlogEntry) object));
45 | }
46 | }
47 |
48 | @Override
49 | public void beforeUpdate(T object)
50 | {
51 | T previous = repo.read(object.getId());
52 | DomainEvents.publish(new ObjectUpdatedEvent(previous, object));
53 | }
54 | }
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/postprocessor/LastModifiedHeaderPostprocessor.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.postprocessor;
2 |
3 | import static io.netty.handler.codec.http.HttpHeaders.Names.LAST_MODIFIED;
4 |
5 | import com.strategicgains.repoexpress.domain.Timestamped;
6 | import org.restexpress.Request;
7 | import org.restexpress.Response;
8 | import org.restexpress.pipeline.Postprocessor;
9 | import com.strategicgains.util.date.DateAdapter;
10 | import com.strategicgains.util.date.HttpHeaderTimestampAdapter;
11 |
12 | /**
13 | * Assigns the Last-Modified HTTP header on the response for GET responses, if applicable.
14 | *
15 | * @author toddf
16 | * @since May 15, 2012
17 | */
18 | public class LastModifiedHeaderPostprocessor
19 | implements Postprocessor
20 | {
21 | DateAdapter fmt = new HttpHeaderTimestampAdapter();
22 |
23 | @Override
24 | public void process(Request request, Response response)
25 | {
26 | if (!request.isMethodGet()) return;
27 | if (!response.hasBody()) return;
28 |
29 | Object body = response.getBody();
30 |
31 | if (!response.hasHeader(LAST_MODIFIED) && body.getClass().isAssignableFrom(Timestamped.class))
32 | {
33 | response.addHeader(LAST_MODIFIED, fmt.format(((Timestamped) body).getUpdatedAt()));
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/serialization/JsonSerializationProcessor.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.serialization;
2 |
3 | import org.restexpress.ContentType;
4 | import org.restexpress.serialization.json.JacksonJsonProcessor;
5 |
6 | import com.fasterxml.jackson.databind.MapperFeature;
7 | import com.fasterxml.jackson.databind.ObjectMapper;
8 | import com.fasterxml.jackson.databind.PropertyNamingStrategy;
9 | import com.fasterxml.jackson.databind.module.SimpleModule;
10 | import com.strategicgains.hyperexpress.domain.hal.HalResource;
11 | import com.strategicgains.hyperexpress.serialization.jackson.HalResourceDeserializer;
12 | import com.strategicgains.hyperexpress.serialization.jackson.HalResourceSerializer;
13 |
14 | public class JsonSerializationProcessor
15 | extends JacksonJsonProcessor
16 | {
17 |
18 | public JsonSerializationProcessor()
19 | {
20 | super();
21 | addSupportedMediaTypes(ContentType.HAL_JSON);
22 | }
23 |
24 | @Override
25 | protected void initializeModule(SimpleModule module)
26 | {
27 | super.initializeModule(module);
28 |
29 | // Support HalResource (de)serialization.
30 | module.addDeserializer(HalResource.class, new HalResourceDeserializer());
31 | module.addSerializer(HalResource.class, new HalResourceSerializer());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/serialization/SerializationProvider.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.serialization;
2 |
3 | import org.restexpress.response.ErrorResponseWrapper;
4 | import org.restexpress.response.ResponseWrapper;
5 | import org.restexpress.serialization.AbstractSerializationProvider;
6 | import org.restexpress.serialization.SerializationProcessor;
7 |
8 | /**
9 | * A factory to create ResponseProcessors for serialization and wrapping of responses.
10 | *
11 | * @author toddf
12 | * @since May 15, 2012
13 | */
14 | public class SerializationProvider
15 | extends AbstractSerializationProvider
16 | {
17 | // SECTION: CONSTANTS
18 |
19 | private static final SerializationProcessor JSON_SERIALIZER = new JsonSerializationProcessor();
20 | private static final SerializationProcessor XML_SERIALIZER = new XmlSerializationProcessor();
21 | private static final ResponseWrapper RESPONSE_WRAPPER = new ErrorResponseWrapper();
22 |
23 | public SerializationProvider()
24 | {
25 | super();
26 | add(JSON_SERIALIZER, RESPONSE_WRAPPER, true);
27 | add(XML_SERIALIZER, RESPONSE_WRAPPER);
28 | }
29 |
30 |
31 | // SECTION: FACTORY
32 |
33 | public static SerializationProcessor json()
34 | {
35 | return JSON_SERIALIZER;
36 | }
37 |
38 | public static SerializationProcessor xml()
39 | {
40 | return XML_SERIALIZER;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/serialization/UuidFormatter.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.serialization;
2 |
3 | import java.util.UUID;
4 |
5 | import com.strategicgains.hyperexpress.annotation.TokenFormatter;
6 | import com.strategicgains.repoexpress.util.UuidConverter;
7 |
8 | public class UuidFormatter
9 | implements TokenFormatter
10 | {
11 | @Override
12 | public String format(Object field)
13 | {
14 | return UuidConverter.format((UUID) field);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/serialization/XmlSerializationProcessor.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.serialization;
2 |
3 | import org.restexpress.example.blogging.domain.Blog;
4 | import org.restexpress.example.blogging.domain.BlogEntry;
5 | import org.restexpress.example.blogging.domain.Comment;
6 | import org.restexpress.serialization.xml.XstreamXmlProcessor;
7 |
8 | public class XmlSerializationProcessor
9 | extends XstreamXmlProcessor
10 | {
11 | public XmlSerializationProcessor()
12 | {
13 | super();
14 | alias("blog", Blog.class);
15 | alias("blog_entry", BlogEntry.class);
16 | alias("comment", Comment.class);
17 | registerConverter(new XstreamObjectIdConverter());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/blogging/src/main/java/org/restexpress/example/blogging/serialization/XstreamObjectIdConverter.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.blogging.serialization;
2 |
3 | import org.bson.types.ObjectId;
4 |
5 | import com.thoughtworks.xstream.converters.SingleValueConverter;
6 |
7 |
8 | /**
9 | * @author toddf
10 | * @since Feb 16, 2011
11 | */
12 | public class XstreamObjectIdConverter
13 | implements SingleValueConverter
14 | {
15 | @SuppressWarnings("rawtypes")
16 | @Override
17 | public boolean canConvert(Class aClass)
18 | {
19 | return ObjectId.class.isAssignableFrom(aClass);
20 | }
21 |
22 | @Override
23 | public Object fromString(String value)
24 | {
25 | return new ObjectId(value);
26 | }
27 |
28 | @Override
29 | public String toString(Object objectId)
30 | {
31 | return ((ObjectId) objectId).toString();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/blogging/zip-with-dependencies.xml:
--------------------------------------------------------------------------------
1 |
5 | zip-with-dependencies
6 |
7 | zip
8 |
9 |
10 |
11 | ${project.basedir}
12 | /
13 |
14 | README*
15 | LICENSE*
16 | NOTICE*
17 | config/**/*
18 |
19 |
20 |
21 | ${project.build.directory}
22 | /
23 |
24 | *.jar
25 |
26 |
27 |
28 |
29 |
30 | lib
31 | false
32 |
33 |
34 |
--------------------------------------------------------------------------------
/echo/README.md:
--------------------------------------------------------------------------------
1 | Echo Example
2 | ============
3 |
4 | This project is a simple RestExpress server that support echo functionality with optional delays. The delays can be used to test consumer libraries with slow responses. Note that the delay DOES actually block the thread for the specified number of milliseconds. A delay of 0 (zero) milliseconds will not delay.
5 |
6 | The service suite supports the following functionality.
7 |
8 | Echo
9 | ====
10 |
11 | This URL simply sends back the same string that is sent in on the 'echo' query-string parameter. There is no serialization involved in the response. The body is not parsed.
12 |
13 | URL: /echo/{delay_ms}
14 | Methods: GET, PUT, POST, DELETE
15 |
16 | Success
17 | =======
18 |
19 | This URL responds with a JSON payload indicating the action that was performed (e.g. 'read', 'create', 'update', 'delete'), the delay that was passed in and the message that was on the 'echo' query-string parameter (if present). This response involves serialization. Every HTTP method will always return a status code 200 (OK).
20 |
21 | URL: /success/{delay_ms}
22 | Methods: GET, PUT, POST, DELETE
23 |
24 | Sample Response:
25 | ```
26 | curl -i localhost:9000/success/0?echo=the+buck+stops+here
27 |
28 | HTTP/1.1 200 OK
29 | Content-Type: application/json; charset=UTF-8
30 | Content-Length: 61
31 |
32 | {"action":"read","delayMs":0,"message":"the buck stops here"}
33 | ```
34 |
35 | Status
36 | ======
37 |
38 | This URL responds with the same payload as the /success URL, with the added ability to vary the HTTP status code returned. Note that response codes vary how RestExpress responds to clients. For example, returning status code 204 (No Content) will cause RestExpress to not include a body in the response. A 404 (Not Found) will return an error response, etc.
39 |
40 | URL: /status/{delay_ms}/{http_response_code}
41 | Methods: GET, PUT, POST, DELETE
42 |
43 | Sample Response:
44 | ```
45 | curl -i localhost:9000/status/0/201?echo=the+buck+stops+here
46 | HTTP/1.1 201 Created
47 | Content-Type: application/json; charset=UTF-8
48 | Content-Length: 61
49 |
50 | {"action":"read","delayMs":0,"message":"the buck stops here"}
51 | ```
52 |
53 | Sample Error Response:
54 | ```
55 | curl -i localhost:9000/status/0/404?echo=the+buck+stops+here
56 | HTTP/1.1 404 Not Found
57 | Content-Type: application/json; charset=UTF-8
58 | Content-Length: 67
59 |
60 | {"errorId":"4d067a25-6004-4ba5-8e94-73fd6ab53bb4","httpStatus":404}
61 | ```
62 |
--------------------------------------------------------------------------------
/echo/config/dev/environment.properties:
--------------------------------------------------------------------------------
1 | # Default is 8081
2 | port = 9000
3 |
4 | # The name of the service suite
5 | name = Echo Demo
6 |
7 | # Any value above zero will be used to set the number of NIO worker threads:
8 | # Default is 0 => 2 x #cores
9 | # This controls the number of concurrent connections the app can handle.
10 | workerCount = 20
11 |
12 | # This controls the number of concurrent requests that the app can process.
13 | executorThreadCount = 20
14 |
--------------------------------------------------------------------------------
/echo/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | RestExpress-Echo-Example
6 |
12 | A RestExpress Echo Server
13 | https://github.com/RestExpress/RestExpress-Examples
14 | org.restexpress.examples
15 | restexpress-echo-example
16 | 0.1-SNAPSHOT
17 | jar
18 |
19 |
20 |
21 | com.strategicgains
22 | RestExpress
23 | 0.11.3
24 |
25 |
26 |
27 |
28 |
29 |
30 | org.apache.maven.plugins
31 | maven-compiler-plugin
32 | 3.0
33 |
34 | 1.7
35 | 1.7
36 | UTF-8
37 |
38 |
39 |
40 | org.codehaus.mojo
41 | exec-maven-plugin
42 | 1.2.1
43 |
44 | org.restexpress.example.echo.Main
45 |
46 |
47 |
48 | org.apache.maven.plugins
49 | maven-jar-plugin
50 | 2.4
51 |
52 |
53 | false
54 |
55 | true
56 | ./lib/
57 | org.restexpress.example.echo.Main
58 |
59 |
60 |
61 |
62 |
63 | org.apache.maven.plugins
64 | maven-assembly-plugin
65 | 2.4
66 |
67 |
68 | zip-with-dependencies.xml
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | org.codehaus.mojo
79 | versions-maven-plugin
80 | 2.0
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/echo/src/jmeter/ RestExpress Test Plan.jmx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Test RestExpress performance via the Echo example.
6 | false
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | false
16 |
17 | saveConfig
18 |
19 |
20 | true
21 | true
22 | true
23 |
24 | true
25 | true
26 | true
27 | true
28 | false
29 | true
30 | true
31 | false
32 | false
33 | false
34 | false
35 | false
36 | false
37 | false
38 | false
39 | 0
40 | true
41 | true
42 |
43 |
44 |
45 |
46 |
47 |
48 | Warm up the Echo JVM
49 | continue
50 |
51 | false
52 | 20
53 |
54 | 5
55 | 1
56 | 1415830212000
57 | 1415830212000
58 | false
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | false
68 | anechovaluegoesheresowecantestthisthing
69 | =
70 | true
71 | echo
72 |
73 |
74 |
75 | localhost
76 | 9000
77 |
78 |
79 |
80 |
81 | /echo/0
82 | GET
83 | false
84 | false
85 | true
86 | false
87 | HttpClient4
88 | false
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | false
97 | anechovaluegoesheresowecantestthisthing
98 | =
99 | true
100 | echo
101 |
102 |
103 |
104 | localhost
105 | 9000
106 |
107 |
108 |
109 |
110 | /success/0
111 | GET
112 | false
113 | false
114 | true
115 | false
116 | HttpClient4
117 | false
118 |
119 |
120 |
121 |
122 |
123 | continue
124 |
125 | false
126 | 10000
127 |
128 | 500
129 | 30
130 | 1415838408000
131 | 1415838408000
132 | false
133 |
134 |
135 | true
136 |
137 |
138 |
139 |
140 |
141 |
142 | true
143 | this is a test of the emergency broadcast system
144 | =
145 | true
146 | echo
147 |
148 |
149 |
150 | localhost
151 | 9000
152 |
153 |
154 |
155 |
156 | /success/0
157 | GET
158 | false
159 | false
160 | true
161 | false
162 | HttpClient4
163 | false
164 |
165 |
166 |
167 |
168 |
169 | continue
170 |
171 | false
172 | 10000
173 |
174 | 500
175 | 30
176 | 1415828153000
177 | 1415828153000
178 | false
179 |
180 |
181 | true
182 |
183 |
184 |
185 |
186 |
187 |
188 | false
189 | anechovaluegoesheresowecantestthisthing
190 | =
191 | true
192 | echo
193 |
194 |
195 |
196 | localhost
197 | 9000
198 |
199 |
200 |
201 |
202 | /echo/0
203 | GET
204 | false
205 | false
206 | true
207 | false
208 | HttpClient4
209 | false
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/Configuration.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2011, Strategic Gains, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package org.restexpress.example.echo;
17 |
18 | import java.util.Properties;
19 |
20 | import org.restexpress.Format;
21 | import org.restexpress.RestExpress;
22 | import org.restexpress.example.echo.controller.EchoController;
23 | import org.restexpress.example.echo.controller.StatusController;
24 | import org.restexpress.example.echo.controller.SuccessController;
25 | import org.restexpress.util.Environment;
26 |
27 | /**
28 | * @author toddf
29 | * @since Feb 10, 2011
30 | */
31 | public class Configuration
32 | extends Environment
33 | {
34 | private static final String NAME_PROPERTY = "name";
35 | private static final String PORT_PROPERTY = "port";
36 | private static final String DEFAULT_FORMAT_PROPERTY = "defaultFormat";
37 | private static final String WORKER_COUNT_PROPERTY = "workerCount";
38 | private static final String EXECUTOR_THREAD_COUNT_PROPERTY = "executorThreadCount";
39 |
40 | private static final int DEFAULT_WORKER_COUNT = 0;
41 | private static final int DEFAULT_EXECUTOR_THREAD_COUNT = 0;
42 |
43 | private int port;
44 | private String name;
45 | private String defaultFormat;
46 | private int workerCount;
47 | private int executorThreadCount;
48 |
49 | private EchoController echoController = new EchoController();
50 | private SuccessController successController = new SuccessController();
51 | private StatusController statusController = new StatusController();
52 |
53 | @Override
54 | protected void fillValues(Properties p)
55 | {
56 | this.name = p.getProperty(NAME_PROPERTY, RestExpress.DEFAULT_NAME);
57 | this.port = Integer.parseInt(p.getProperty(PORT_PROPERTY, String.valueOf(RestExpress.DEFAULT_PORT)));
58 | this.defaultFormat = p.getProperty(DEFAULT_FORMAT_PROPERTY, Format.JSON);
59 | this.workerCount = Integer.parseInt(p.getProperty(WORKER_COUNT_PROPERTY, String.valueOf(DEFAULT_WORKER_COUNT)));
60 | this.executorThreadCount = Integer.parseInt(p.getProperty(EXECUTOR_THREAD_COUNT_PROPERTY, String.valueOf(DEFAULT_EXECUTOR_THREAD_COUNT)));
61 | }
62 |
63 | public String getDefaultFormat()
64 | {
65 | return defaultFormat;
66 | }
67 |
68 | public int getPort()
69 | {
70 | return port;
71 | }
72 |
73 | public String getName()
74 | {
75 | return name;
76 | }
77 |
78 | public int getWorkerCount()
79 | {
80 | return workerCount;
81 | }
82 |
83 | public int getExecutorThreadCount()
84 | {
85 | return executorThreadCount;
86 | }
87 |
88 | public EchoController getEchoController()
89 | {
90 | return echoController;
91 | }
92 |
93 | public SuccessController getSuccessController()
94 | {
95 | return successController;
96 | }
97 |
98 | public StatusController getStatusController()
99 | {
100 | return statusController;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/Main.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.echo;
2 |
3 | import org.restexpress.RestExpress;
4 | import org.restexpress.example.echo.serialization.SerializationProvider;
5 | import org.restexpress.util.Environment;
6 |
7 | /**
8 | * The main entry-point into the RestExpress Echo example services.
9 | *
10 | * @author toddf
11 | * @since Aug 31, 2009
12 | */
13 | public class Main
14 | {
15 | public static void main(String[] args) throws Exception
16 | {
17 | RestExpress.setSerializationProvider(new SerializationProvider());
18 | Configuration config = Environment.load(args, Configuration.class);
19 | RestExpress server = new RestExpress()
20 | .setName(config.getName())
21 | .setPort(config.getPort());
22 |
23 | defineRoutes(server, config);
24 |
25 | if (config.getWorkerCount() > 0)
26 | {
27 | server.setIoThreadCount(config.getWorkerCount());
28 | }
29 |
30 | if (config.getExecutorThreadCount() > 0)
31 | {
32 | server.setExecutorThreadCount(config.getExecutorThreadCount());
33 | }
34 |
35 | mapExceptions(server);
36 | server.bind();
37 | server.awaitShutdown();
38 | }
39 |
40 | /**
41 | * @param server
42 | * @param config
43 | */
44 | private static void defineRoutes(RestExpress server, Configuration config)
45 | {
46 | // This route supports GET, POST, PUT, DELETE echoing the 'echo' query-string parameter in the response.
47 | // GET and DELETE are also supported but require an 'echo' header or query-string parameter.
48 | server.uri("/echo/{delay_ms}", config.getEchoController())
49 | .noSerialization();
50 |
51 | // Waits the delay_ms number of milliseconds and responds with a 200.
52 | // Supports GET, PUT, POST, DELETE methods.
53 | server.uri("/success/{delay_ms}.{format}", config.getSuccessController());
54 |
55 | // Waits the delay_ms number of milliseconds and responds with the
56 | // specified HTTP response code.
57 | // Supports GET, PUT, POST, DELETE methods.
58 | server.uri("/status/{delay_ms}/{http_response_code}.{format}", config.getStatusController());
59 | }
60 |
61 | /**
62 | * @param server
63 | */
64 | private static void mapExceptions(RestExpress server)
65 | {
66 | // server
67 | // .mapException(ItemNotFoundException.class, NotFoundException.class)
68 | // .mapException(DuplicateItemException.class, ConflictException.class)
69 | // .mapException(ValidationException.class, BadRequestException.class);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/controller/AbstractDelayingController.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2012, Strategic Gains, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package org.restexpress.example.echo.controller;
17 |
18 | import org.restexpress.Request;
19 | import org.restexpress.exception.BadRequestException;
20 |
21 | /**
22 | * @author toddf
23 | * @since Jan 11, 2012
24 | */
25 | public abstract class AbstractDelayingController
26 | {
27 | private static final String TIMEOUT_MILLIS_HEADER = "delay_ms";
28 |
29 | protected long delay(Request request)
30 | {
31 | long millis = 0l;
32 |
33 | try
34 | {
35 | millis = Long.valueOf(request.getHeader(TIMEOUT_MILLIS_HEADER));
36 | }
37 | catch (NumberFormatException e)
38 | {
39 | throw new BadRequestException(e.getMessage());
40 | }
41 |
42 | if (millis == 0l) return 0l;
43 |
44 | try
45 | {
46 | Thread.sleep(millis);
47 | }
48 | catch (InterruptedException e)
49 | {
50 | e.printStackTrace();
51 | }
52 | return millis;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/controller/DelayResponse.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2011, Strategic Gains, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package org.restexpress.example.echo.controller;
17 |
18 | /**
19 | * @author toddf
20 | * @since Dec 20, 2011
21 | */
22 | public class DelayResponse
23 | {
24 | @SuppressWarnings("unused")
25 | private String action;
26 | @SuppressWarnings("unused")
27 | private long delayMs;
28 | @SuppressWarnings("unused")
29 | private String message;
30 |
31 | public DelayResponse(String action, long delayMs, String message)
32 | {
33 | super();
34 | this.action = action;
35 | this.delayMs = delayMs;
36 | this.message = message;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/controller/EchoController.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.echo.controller;
2 |
3 | import io.netty.buffer.ByteBuf;
4 |
5 | import org.restexpress.Request;
6 | import org.restexpress.Response;
7 |
8 | /**
9 | * @author toddf
10 | * @since Aug 31, 2010
11 | */
12 | public class EchoController
13 | extends AbstractDelayingController
14 | {
15 | private static final String ECHO_PARAMETER_NOT_FOUND = "'echo' header or query-string parameter not found";
16 | private static final String ECHO_HEADER = "echo";
17 |
18 | public ByteBuf create(Request request, Response response)
19 | {
20 | delay(request);
21 | response.setResponseCreated();
22 | return request.getBody();
23 | }
24 |
25 | public String delete(Request request, Response response)
26 | {
27 | delay(request);
28 | return request.getHeader(ECHO_HEADER, ECHO_PARAMETER_NOT_FOUND);
29 | }
30 |
31 | public String read(Request request, Response response)
32 | {
33 | System.out.println(request.getRemoteAddress());
34 | delay(request);
35 | String echo = request.getHeader(ECHO_HEADER);
36 |
37 | if (echo == null)
38 | {
39 | return "Please set query-string parameter 'echo' (e.g. ?echo=value)";
40 | }
41 |
42 | return echo;
43 | }
44 |
45 | public ByteBuf update(Request request, Response response)
46 | {
47 | delay(request);
48 | return request.getBody();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/controller/StatusController.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.echo.controller;
2 |
3 | import org.restexpress.Request;
4 | import org.restexpress.Response;
5 |
6 | /**
7 | * @author toddf
8 | * @since Aug 31, 2010
9 | */
10 | public class StatusController
11 | extends AbstractDelayingController
12 | {
13 | private static final String STATUS_RESPONSE_HEADER = "http_response_code";
14 |
15 | public Object create(Request request, Response response)
16 | {
17 | long delayms = delay(request);
18 | int status = Integer.valueOf(request.getHeader(STATUS_RESPONSE_HEADER));
19 | response.setResponseCode(status);
20 | String message = request.getHeader("echo");
21 | return new DelayResponse("create", delayms, message);
22 | }
23 |
24 | public Object read(Request request, Response response)
25 | {
26 | long delayms = delay(request);
27 | int status = Integer.valueOf(request.getHeader(STATUS_RESPONSE_HEADER));
28 | response.setResponseCode(status);
29 | String message = request.getHeader("echo");
30 | return new DelayResponse("read", delayms, message);
31 | }
32 |
33 | public Object update(Request request, Response response)
34 | {
35 | long delayms = delay(request);
36 | int status = Integer.valueOf(request.getHeader(STATUS_RESPONSE_HEADER));
37 | response.setResponseCode(status);
38 | String message = request.getHeader("echo");
39 | return new DelayResponse("update", delayms, message);
40 | }
41 |
42 | public Object delete(Request request, Response response)
43 | {
44 | long delayms = delay(request);
45 | int status = Integer.valueOf(request.getHeader(STATUS_RESPONSE_HEADER));
46 | response.setResponseCode(status);
47 | String message = request.getHeader("echo");
48 | return new DelayResponse("delete", delayms, message);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/controller/SuccessController.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.echo.controller;
2 |
3 | import org.restexpress.Request;
4 | import org.restexpress.Response;
5 |
6 | /**
7 | * @author toddf
8 | * @since Aug 31, 2010
9 | */
10 | public class SuccessController
11 | extends AbstractDelayingController
12 | {
13 | public Object create(Request request, Response response)
14 | {
15 | long delayms = delay(request);
16 | response.setResponseCreated();
17 | String message = request.getHeader("echo");
18 | return new DelayResponse("create", delayms, message);
19 | }
20 |
21 | public Object read(Request request, Response response)
22 | {
23 | long delayms = delay(request);
24 | String message = request.getHeader("echo");
25 | return new DelayResponse("read", delayms, message);
26 | }
27 |
28 | public Object update(Request request, Response response)
29 | {
30 | long delayms = delay(request);
31 | String message = request.getHeader("echo");
32 | return new DelayResponse("update", delayms, message);
33 | }
34 |
35 | public Object delete(Request request, Response response)
36 | {
37 | long delayms = delay(request);
38 | String message = request.getHeader("echo");
39 | return new DelayResponse("delete", delayms, message);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/serialization/JsonSerializationProcessor.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.echo.serialization;
2 |
3 | import org.restexpress.serialization.json.JacksonJsonProcessor;
4 |
5 | /**
6 | * @author toddf
7 | * @since Oct 10, 2011
8 | */
9 | public class JsonSerializationProcessor
10 | extends JacksonJsonProcessor
11 | {
12 |
13 | public JsonSerializationProcessor()
14 | {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/serialization/SerializationProvider.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.echo.serialization;
2 |
3 | import org.restexpress.response.ErrorResponseWrapper;
4 | import org.restexpress.response.ResponseWrapper;
5 | import org.restexpress.serialization.AbstractSerializationProvider;
6 | import org.restexpress.serialization.SerializationProcessor;
7 |
8 | public class SerializationProvider
9 | extends AbstractSerializationProvider
10 | {
11 | // SECTION: CONSTANTS
12 |
13 | private static final SerializationProcessor JSON_SERIALIZER = new JsonSerializationProcessor();
14 | private static final SerializationProcessor XML_SERIALIZER = new XmlSerializationProcessor();
15 | private static final ResponseWrapper RESPONSE_WRAPPER = new ErrorResponseWrapper();
16 |
17 | public SerializationProvider()
18 | {
19 | super();
20 | add(JSON_SERIALIZER, RESPONSE_WRAPPER, true);
21 | add(XML_SERIALIZER, RESPONSE_WRAPPER);
22 | }
23 |
24 | public static SerializationProcessor json()
25 | {
26 | return JSON_SERIALIZER;
27 | }
28 |
29 | public static SerializationProcessor xml()
30 | {
31 | return XML_SERIALIZER;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/echo/src/main/java/org/restexpress/example/echo/serialization/XmlSerializationProcessor.java:
--------------------------------------------------------------------------------
1 | package org.restexpress.example.echo.serialization;
2 |
3 | import org.restexpress.example.echo.controller.DelayResponse;
4 | import org.restexpress.serialization.xml.XstreamXmlProcessor;
5 |
6 | /**
7 | * @author toddf
8 | * @since Feb 16, 2011
9 | */
10 | public class XmlSerializationProcessor
11 | extends XstreamXmlProcessor
12 | {
13 | public XmlSerializationProcessor()
14 | {
15 | super();
16 | alias("delay_response", DelayResponse.class);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/echo/zip-with-dependencies.xml:
--------------------------------------------------------------------------------
1 |
5 | zip-with-dependencies
6 |
7 | zip
8 |
9 |
10 |
11 | ${project.basedir}
12 | /
13 |
14 | README*
15 | LICENSE*
16 | NOTICE*
17 | config/**/*
18 |
19 |
20 |
21 | ${project.build.directory}
22 | /
23 |
24 | *.jar
25 |
26 |
27 |
28 |
29 |
30 | lib
31 | false
32 |
33 |
34 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | RestExpress-Examples
5 | RestExpress examples
6 | https://github.com/RestExpress/RestExpress-Examples
7 | com.strategicgains
8 | restexpress-examples
9 | 0.1-SNAPSHOT
10 | pom
11 |
12 |
13 | echo
14 | benchmark
15 | blogging
16 |
17 |
18 |
19 |
20 | junit
21 | junit
22 | 4.11
23 | jar
24 | test
25 | true
26 |
27 |
28 |
29 |
30 | org.sonatype.oss
31 | oss-parent
32 | 7
33 |
34 |
35 |
36 |
37 | The Apache Software License, Version 2.0
38 | http://www.apache.org/licenses/LICENSE-2.0.txt
39 | repo
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.apache.maven.plugins
47 | maven-compiler-plugin
48 | 3.0
49 |
50 | 1.7
51 | 1.7
52 |
53 |
54 |
55 | org.apache.maven.plugins
56 | maven-source-plugin
57 | 2.2.1
58 |
59 |
60 | attach-sources
61 |
62 | jar
63 |
64 |
65 |
66 |
67 |
68 | org.apache.maven.plugins
69 | maven-javadoc-plugin
70 | 2.9
71 |
72 |
73 | attach-javadocs
74 |
75 | jar
76 |
77 |
78 |
79 |
80 |
81 | org.apache.maven.plugins
82 | maven-release-plugin
83 |
84 |
85 | org.apache.maven.plugins
86 | maven-gpg-plugin
87 | 3.0.1
88 |
89 |
90 | sign-artifacts
91 | verify
92 |
93 | sign
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | GitHub.com
103 | https://github.com/RestExpress/RestExpress-Examples/issues
104 |
105 |
106 |
107 | git@github.com:RestExpress/RestExpress-Examples.git
108 | scm:git:git@github.com:RestExpress/RestExpress-Examples.git
109 | scm:git:git@github.com:RestExpress/RestExpress-Examples.git
110 | HEAD
111 |
112 |
113 |
114 |
115 | tfredrich
116 | Todd Fredrich
117 | tfredrich@gmail.com
118 |
119 |
120 |
121 |
122 |
123 |
124 | org.codehaus.mojo
125 | versions-maven-plugin
126 | 2.0
127 |
128 |
129 |
130 | dependency-updates-report
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/vs-jersey/jersey/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | 4.0.0
5 |
6 | com.example
7 | jersey-service
8 | jar
9 | 1.0-SNAPSHOT
10 | jersey-service
11 |
12 |
13 |
14 |
15 | org.glassfish.jersey
16 | jersey-bom
17 | ${jersey.version}
18 | pom
19 | import
20 |
21 |
22 |
23 |
24 |
25 |
26 | org.glassfish.jersey.containers
27 | jersey-container-grizzly2-http
28 |
29 |
35 |
36 | junit
37 | junit
38 | 4.9
39 | test
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.apache.maven.plugins
47 | maven-compiler-plugin
48 | 2.5.1
49 | true
50 |
51 | 1.7
52 | 1.7
53 |
54 |
55 |
56 | org.codehaus.mojo
57 | exec-maven-plugin
58 | 1.2.1
59 |
60 |
61 |
62 | java
63 |
64 |
65 |
66 |
67 | com.example.Main
68 |
69 |
70 |
71 |
72 |
73 |
74 | 2.15
75 | UTF-8
76 |
77 |
78 |
--------------------------------------------------------------------------------
/vs-jersey/jersey/src/main/java/com/example/Main.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import org.glassfish.grizzly.http.server.HttpServer;
4 | import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
5 | import org.glassfish.jersey.server.ResourceConfig;
6 |
7 | import java.io.IOException;
8 | import java.net.URI;
9 |
10 | public class Main
11 | {
12 | public static final String BASE_URI = "http://localhost:8080/myapp/";
13 |
14 | public static HttpServer startServer()
15 | {
16 | final ResourceConfig rc = new ResourceConfig().packages("com.example");
17 | return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
18 | }
19 |
20 | public static void main(String[] args) throws IOException
21 | {
22 | final HttpServer server = startServer();
23 | System.out.println(String.format(
24 | "Jersey app started with WADL available at "
25 | + "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
26 | System.in.read();
27 | server.stop();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/vs-jersey/jersey/src/main/java/com/example/MyResource.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import java.util.UUID;
4 |
5 | import javax.ws.rs.GET;
6 | import javax.ws.rs.POST;
7 | import javax.ws.rs.Path;
8 | import javax.ws.rs.Produces;
9 | import javax.ws.rs.core.MediaType;
10 |
11 | @Path("myresource")
12 | public class MyResource
13 | {
14 | @GET
15 | @Produces(MediaType.TEXT_PLAIN)
16 | public String getIt()
17 | {
18 | // throw new RuntimeException("message goes here");
19 | return "Got it!";
20 | }
21 |
22 | @POST
23 | @Produces(MediaType.APPLICATION_JSON)
24 | public Model postIt()
25 | {
26 | return new Model("todd", "http://www.toddfredrich.com/");
27 | }
28 |
29 | public class Model
30 | {
31 | private UUID id = UUID.randomUUID();
32 | private String name;
33 | private String href;
34 |
35 | public Model(String name, String href)
36 | {
37 | super();
38 | this.name = name;
39 | this.href = href;
40 | }
41 |
42 | public UUID getId()
43 | {
44 | return id;
45 | }
46 |
47 | public String getName()
48 | {
49 | return name;
50 | }
51 |
52 | public String getHref()
53 | {
54 | return href;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/vs-jersey/jersey/src/test/java/com/example/MyResourceTest.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import javax.ws.rs.client.Client;
7 | import javax.ws.rs.client.ClientBuilder;
8 | import javax.ws.rs.client.WebTarget;
9 | import javax.ws.rs.core.Response;
10 |
11 | import org.glassfish.grizzly.http.server.HttpServer;
12 | import org.junit.After;
13 | import org.junit.Before;
14 | import org.junit.Test;
15 |
16 | public class MyResourceTest {
17 |
18 | private HttpServer server;
19 | private WebTarget target;
20 |
21 | @Before
22 | public void setUp() throws Exception {
23 | server = Main.startServer();
24 | Client c = ClientBuilder.newClient();
25 | target = c.target(Main.BASE_URI);
26 | }
27 |
28 | @After
29 | public void tearDown() throws Exception {
30 | server.stop();
31 | }
32 |
33 | @Test
34 | public void testGetIt() {
35 | Response response = target.path("myresource").request().get();
36 | assertEquals(200, response.getStatus());
37 | assertEquals("Got it!", response.readEntity(String.class));
38 | }
39 |
40 | @Test
41 | public void testPostIt() {
42 | Response response = target.path("myresource").request().post(null);
43 | assertEquals(200, response.getStatus());
44 | MyResource.Model model = response.readEntity(MyResource.Model.class);
45 | assertEquals("todd", model.getName());
46 | assertEquals("http://www.toddfredrich.com/", model.getHref());
47 | assertNotNull(model.getId());
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/vs-jersey/restexpress/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | restexpress-service
6 | A Minimal RestExpress Server
7 | com.example
8 | restexpress-service
9 | 1.0-SNAPSHOT
10 | jar
11 |
12 |
13 |
14 | com.strategicgains
15 | RestExpress
16 | 0.11.3
17 |
18 |
19 | junit
20 | junit
21 | 4.11
22 | jar
23 | test
24 | true
25 |
26 |
27 | com.jayway.restassured
28 | rest-assured
29 | 2.8.0
30 | test
31 |
32 |
33 |
34 |
35 | package
36 |
37 |
38 |
39 | maven-shade-plugin
40 | 1.7
41 |
42 |
43 | package
44 |
45 | shade
46 |
47 |
48 | true
49 |
50 |
51 |
52 | com.example.Main
53 |
54 |
55 |
56 |
57 |
58 | *:*
59 |
60 | META-INF/*.SF
61 | META-INF/*.DSA
62 | META-INF/*.RSA
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | org.apache.maven.plugins
72 | maven-compiler-plugin
73 | 3.0
74 |
75 | 1.7
76 | 1.7
77 | UTF-8
78 |
79 |
80 |
81 | org.codehaus.mojo
82 | exec-maven-plugin
83 | 1.2.1
84 |
85 | com.example.Main
86 |
87 |
88 |
89 | org.apache.maven.plugins
90 | maven-jar-plugin
91 | 2.4
92 |
93 |
94 |
95 | true
96 | com.example.Main
97 |
98 |
99 |
100 |
101 |
102 | org.apache.maven.plugins
103 | maven-assembly-plugin
104 | 2.4
105 |
106 |
107 | zip-with-dependencies.xml
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | org.codehaus.mojo
118 | versions-maven-plugin
119 | 2.0
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/vs-jersey/restexpress/src/main/java/com/example/Main.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import java.io.IOException;
4 |
5 | import io.netty.handler.codec.http.HttpMethod;
6 | import org.restexpress.RestExpress;
7 |
8 | public class Main
9 | {
10 | public static RestExpress startServer(String[] args) throws IOException
11 | {
12 | RestExpress server = new RestExpress();
13 | MyResource r = new MyResource();
14 |
15 | server.uri("/myapp/myresource", r)
16 | .method(HttpMethod.GET)
17 | .noSerialization();
18 |
19 | server.uri("/myapp/myresource", r)
20 | .method(HttpMethod.POST);
21 |
22 | server.bind(8080);
23 | return server;
24 | }
25 |
26 | public static void main(String[] args) throws Exception
27 | {
28 | RestExpress server = startServer(args);
29 | System.out.println("Hit enter to stop it...");
30 | System.in.read();
31 | server.shutdown();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/vs-jersey/restexpress/src/main/java/com/example/MyResource.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import java.util.UUID;
4 |
5 | import org.restexpress.Request;
6 | import org.restexpress.Response;
7 |
8 | public class MyResource
9 | {
10 | public String read(Request request, Response response)
11 | {
12 | // throw new RuntimeException("message goes here");
13 | return "Got it!";
14 | }
15 |
16 | public Model create(Request request, Response response)
17 | {
18 | return new Model("todd", "http://www.toddfredrich.com/");
19 | }
20 |
21 | public class Model
22 | {
23 | private UUID id = UUID.randomUUID();
24 | private String name;
25 | private String href;
26 |
27 | public Model(String name, String href)
28 | {
29 | super();
30 | this.name = name;
31 | this.href = href;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/vs-jersey/restexpress/src/test/java/com/example/MyResourceTest.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import static com.jayway.restassured.RestAssured.get;
4 | import static com.jayway.restassured.RestAssured.post;
5 | import static org.hamcrest.Matchers.*;
6 |
7 | import org.junit.AfterClass;
8 | import org.junit.BeforeClass;
9 | import org.junit.Test;
10 | import org.restexpress.RestExpress;
11 |
12 | import com.example.Main;
13 | import com.jayway.restassured.response.ValidatableResponse;
14 |
15 | public class MyResourceTest
16 | {
17 | private static RestExpress server;
18 | private static final String BASE_URL = "http://localhost:8080/myapp";
19 |
20 | @BeforeClass
21 | public static void beforeClass() throws Exception
22 | {
23 | String[] env =
24 | {
25 | "dev"
26 | };
27 | server = Main.startServer(env);
28 | }
29 |
30 | @AfterClass
31 | public static void afterClass()
32 | {
33 | server.shutdown();
34 | }
35 |
36 | @Test
37 | public void testRead()
38 | {
39 | ValidatableResponse response = get(BASE_URL + "/myresource").then();
40 | response.assertThat().statusCode(200);
41 | response.assertThat().body(equalTo("Got it!"));
42 | }
43 |
44 | @Test
45 | public void testCreate()
46 | {
47 | ValidatableResponse response = post(BASE_URL + "/myresource").then();
48 | response.statusCode(200);
49 | response.body("name", equalTo("todd"));
50 | response.body("href", equalTo("http://www.toddfredrich.com/"));
51 | response.body("id", not(equalTo(null)));
52 | }
53 | }
54 |
--------------------------------------------------------------------------------