├── .gitignore
├── .travis.yml
├── README.md
├── jersey-netty-example
├── pom.xml
└── src
│ └── main
│ └── java
│ └── net
│ └── javaforge
│ └── netty
│ ├── App.java
│ └── jersey
│ ├── HelloWorldResource.java
│ └── MyApplication.java
├── netty-servlet-bridge
├── LICENSE.txt
├── README.md
├── pom.xml
└── src
│ └── main
│ └── java
│ └── net
│ └── javaforge
│ └── netty
│ └── servlet
│ └── bridge
│ ├── ChannelThreadLocal.java
│ ├── HttpSessionThreadLocal.java
│ ├── ServletBridgeChannelPipelineFactory.java
│ ├── ServletBridgeException.java
│ ├── ServletBridgeHandler.java
│ ├── ServletBridgeInterceptor.java
│ ├── ServletBridgeRuntimeException.java
│ ├── config
│ ├── FilterConfiguration.java
│ ├── HttpComponentConfigurationAdapter.java
│ ├── ServletConfiguration.java
│ ├── ServletContextListenerConfiguration.java
│ └── WebappConfiguration.java
│ ├── impl
│ ├── ConfigAdapter.java
│ ├── FilterChainImpl.java
│ ├── FilterConfigImpl.java
│ ├── HttpServletRequestImpl.java
│ ├── HttpServletResponseImpl.java
│ ├── HttpSessionImpl.java
│ ├── PrintWriterImpl.java
│ ├── RequestDispatcherImpl.java
│ ├── ServletBridgeWebapp.java
│ ├── ServletConfigImpl.java
│ ├── ServletContextImpl.java
│ ├── ServletInputStreamImpl.java
│ ├── ServletOutputStreamImpl.java
│ └── URIParser.java
│ ├── interceptor
│ ├── ChannelInterceptor.java
│ └── HttpSessionInterceptor.java
│ ├── session
│ ├── DefaultServletBridgeHttpSessionStore.java
│ └── ServletBridgeHttpSessionStore.java
│ └── util
│ └── Utils.java
└── vaadin-netty-example
├── pom.xml
└── src
└── main
└── java
└── net
└── javaforge
└── netty
├── App.java
└── vaadin
└── AddressbookUI.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.ipr
3 | *.iws
4 | .idea
5 | target/
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | before_install: cd netty-servlet-bridge
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This project provides a Servlet API implementation for Netty.IO framework (http://netty.io/).
2 |
3 | Netty Servlet Bridge allows integration of existing Servlet API based web-applications
4 | into the Netty-backed infrastructure.
5 |
6 | Simple usage example:
7 |
8 |
9 | ```java
10 | // Configure netty server.
11 | final ServerBootstrap bootstrap = new ServerBootstrap(
12 | new NioServerSocketChannelFactory(
13 | Executors.newCachedThreadPool(), Executors.newCachedThreadPool()
14 | )
15 | );
16 |
17 | // configure web-app
18 | WebappConfiguration webapp = new WebappConfiguration()
19 | .addContextParameter("name1", "value1")
20 | .addContextParameter("name2", "value2")
21 | .addServletConfigurations(
22 | new ServletConfiguration(MyHttpServlet.class, "/servlet1"),
23 | new ServletConfiguration(MyAnotherHttpServlet.class, "/servlet2"),
24 | .addInitParameter("initpram1", "value1")
25 | .addInitParameter("initpram2", "value2")
26 |
27 | )
28 | .addFilterConfigurations (
29 | new FilterConfiguration(MyServletFilter.class, "/*"),
30 | );
31 |
32 |
33 | // Set up the event pipeline factory.
34 | bootstrap.setPipelineFactory(new ServletBridgeChannelPipelineFactory(webapp));
35 |
36 | // Bind and start to accept incoming connections.
37 | final Channel serverChannel = bootstrap.bind(new InetSocketAddress(8080));
38 |
39 | ```
40 |
41 | Please consult example projects demonstrating the library usage.
42 |
43 | Jersey Integration Example: https://github.com/bigpuritz/netty-servlet-bridge/tree/master/jersey-netty-example
44 | Vaadin Integration Example: https://github.com/bigpuritz/netty-servlet-bridge/tree/master/vaadin-netty-example
45 |
--------------------------------------------------------------------------------
/jersey-netty-example/pom.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 | 4.0.0
20 |
21 | net.javaforge.netty
22 | jersey-netty-example
23 | 1.0-SNAPSHOT
24 | jar
25 |
26 | jersey-example
27 | http://maven.apache.org
28 |
29 |
30 | UTF-8
31 |
32 |
33 |
34 |
35 |
36 | io.netty
37 | netty
38 | 3.6.2.Final
39 |
40 |
41 | net.javaforge.netty
42 | netty-servlet-bridge
43 | 1.0.0-SNAPSHOT
44 |
45 |
46 | com.sun.jersey
47 | jersey-servlet
48 | 1.17
49 |
50 |
51 | com.sun.jersey
52 | jersey-json
53 | 1.17
54 |
55 |
56 | org.slf4j
57 | slf4j-simple
58 | 1.7.2
59 |
60 |
61 | junit
62 | junit
63 | 4.11
64 | test
65 |
66 |
67 |
68 |
69 |
70 |
71 | org.apache.maven.plugins
72 | maven-eclipse-plugin
73 | 2.9
74 |
75 | true
76 | true
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/jersey-netty-example/src/main/java/net/javaforge/netty/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty;
18 |
19 | import com.sun.jersey.spi.container.servlet.ServletContainer;
20 | import net.javaforge.netty.jersey.MyApplication;
21 | import net.javaforge.netty.servlet.bridge.ServletBridgeChannelPipelineFactory;
22 | import net.javaforge.netty.servlet.bridge.config.ServletConfiguration;
23 | import net.javaforge.netty.servlet.bridge.config.WebappConfiguration;
24 | import org.jboss.netty.bootstrap.ServerBootstrap;
25 | import org.jboss.netty.channel.Channel;
26 | import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 |
30 | import java.net.InetSocketAddress;
31 | import java.util.concurrent.Executors;
32 |
33 | /**
34 | * Hello world!
35 | */
36 | public class App {
37 |
38 | private static final Logger log = LoggerFactory.getLogger(App.class);
39 |
40 | public static void main(String[] args) {
41 |
42 | long start = System.currentTimeMillis();
43 |
44 | // Configure the server.
45 | final ServerBootstrap bootstrap = new ServerBootstrap(
46 | new NioServerSocketChannelFactory(Executors
47 | .newCachedThreadPool(), Executors.newCachedThreadPool()));
48 |
49 | WebappConfiguration webapp = new WebappConfiguration()
50 | .addServletConfigurations(new ServletConfiguration(
51 | ServletContainer.class, "/*").addInitParameter(
52 | "javax.ws.rs.Application", MyApplication.class
53 | .getName()));
54 |
55 | // Set up the event pipeline factory.
56 | final ServletBridgeChannelPipelineFactory servletBridge = new ServletBridgeChannelPipelineFactory(
57 | webapp);
58 | bootstrap.setPipelineFactory(servletBridge);
59 |
60 | // Bind and start to accept incoming connections.
61 | final Channel serverChannel = bootstrap
62 | .bind(new InetSocketAddress(8080));
63 |
64 | long end = System.currentTimeMillis();
65 |
66 | log.info(">>> Server started in {} ms .... <<< ", (end - start));
67 |
68 | Runtime.getRuntime().addShutdownHook(new Thread() {
69 |
70 | @Override
71 | public void run() {
72 | servletBridge.shutdown();
73 | serverChannel.close().awaitUninterruptibly();
74 | bootstrap.releaseExternalResources();
75 | }
76 | });
77 |
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/jersey-netty-example/src/main/java/net/javaforge/netty/jersey/HelloWorldResource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.jersey;
18 |
19 | import javax.ws.rs.GET;
20 | import javax.ws.rs.Path;
21 | import javax.ws.rs.Produces;
22 |
23 | //The Java class will be hosted at the URI path "/helloworld"
24 | @Path("/helloworld")
25 | public class HelloWorldResource {
26 |
27 | // The Java method will process HTTP GET requests
28 | @GET
29 | // The Java method will produce content identified by the MIME Media
30 | // type "text/plain"
31 | @Produces("text/plain")
32 | public String getClichedMessage() {
33 | // Return some cliched textual content
34 | return "Hello World";
35 | }
36 | }
--------------------------------------------------------------------------------
/jersey-netty-example/src/main/java/net/javaforge/netty/jersey/MyApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.jersey;
18 |
19 | import javax.ws.rs.ApplicationPath;
20 | import javax.ws.rs.core.Application;
21 | import java.util.HashSet;
22 | import java.util.Set;
23 |
24 | @ApplicationPath("/")
25 | public class MyApplication extends Application {
26 |
27 | @Override
28 | public Set> getClasses() {
29 | final Set> classes = new HashSet>();
30 | // register root resource
31 | classes.add(HelloWorldResource.class);
32 | return classes;
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/netty-servlet-bridge/LICENSE.txt:
--------------------------------------------------------------------------------
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, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/bigpuritz/netty-servlet-bridge)
2 |
3 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/pom.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 | 4.0.0
20 | net.javaforge.netty
21 | netty-servlet-bridge
22 | jar
23 | 2.0.0-SNAPSHOT
24 | netty-servlet-bridge
25 | http://maven.apache.org
26 |
27 |
28 |
29 | org.slf4j
30 | slf4j-api
31 | 1.7.2
32 |
33 |
34 | io.netty
35 | netty-all
36 | 4.1.0.Beta3
37 |
38 |
39 | javax.servlet
40 | servlet-api
41 | 2.5
42 |
43 |
44 | org.slf4j
45 | slf4j-simple
46 | 1.7.2
47 | test
48 |
49 |
50 | junit
51 | junit
52 | 4.11
53 | test
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.apache.maven.plugins
61 | maven-eclipse-plugin
62 | 2.9
63 |
64 | true
65 | true
66 |
67 |
68 |
69 | org.apache.maven.plugins
70 | maven-compiler-plugin
71 |
72 | 1.6
73 | 1.6
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/ChannelThreadLocal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge;
18 |
19 | import io.netty.channel.Channel;
20 |
21 | public class ChannelThreadLocal {
22 |
23 | public static final ThreadLocal channelThreadLocal = new ThreadLocal();
24 |
25 | public static void set(Channel channel) {
26 | channelThreadLocal.set(channel);
27 | }
28 |
29 | public static void unset() {
30 | channelThreadLocal.remove();
31 | }
32 |
33 | public static Channel get() {
34 | return channelThreadLocal.get();
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/HttpSessionThreadLocal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge;
18 |
19 | import net.javaforge.netty.servlet.bridge.impl.HttpSessionImpl;
20 | import net.javaforge.netty.servlet.bridge.impl.ServletBridgeWebapp;
21 | import net.javaforge.netty.servlet.bridge.session.DefaultServletBridgeHttpSessionStore;
22 | import net.javaforge.netty.servlet.bridge.session.ServletBridgeHttpSessionStore;
23 |
24 | public class HttpSessionThreadLocal {
25 |
26 | public static final ThreadLocal sessionThreadLocal = new ThreadLocal();
27 |
28 | private static ServletBridgeHttpSessionStore sessionStore;
29 |
30 | public static ServletBridgeHttpSessionStore getSessionStore() {
31 | return sessionStore;
32 | }
33 |
34 | public static void setSessionStore(ServletBridgeHttpSessionStore store) {
35 | sessionStore = store;
36 | }
37 |
38 | public static void set(HttpSessionImpl session) {
39 | sessionThreadLocal.set(session);
40 | }
41 |
42 | public static void unset() {
43 | sessionThreadLocal.remove();
44 | }
45 |
46 | public static HttpSessionImpl get() {
47 | HttpSessionImpl session = sessionThreadLocal.get();
48 | if (session != null)
49 | session.touch();
50 | return session;
51 | }
52 |
53 | public static HttpSessionImpl getOrCreate() {
54 | if (HttpSessionThreadLocal.get() == null) {
55 | if (sessionStore == null) {
56 | sessionStore = new DefaultServletBridgeHttpSessionStore();
57 | }
58 |
59 | HttpSessionImpl newSession = sessionStore.createSession();
60 | newSession.setMaxInactiveInterval(ServletBridgeWebapp.get()
61 | .getWebappConfig().getSessionTimeout());
62 | sessionThreadLocal.set(sessionStore.createSession());
63 | }
64 | return get();
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/ServletBridgeChannelPipelineFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge;
18 |
19 | import io.netty.channel.ChannelHandler;
20 | import io.netty.channel.ChannelPipeline;
21 | import io.netty.channel.group.ChannelGroup;
22 | import io.netty.channel.group.DefaultChannelGroup;
23 | import io.netty.handler.codec.http.HttpContentCompressor;
24 | import io.netty.handler.codec.http.HttpRequestDecoder;
25 | import io.netty.handler.codec.http.HttpResponseEncoder;
26 | import io.netty.handler.timeout.IdleStateHandler;
27 | import io.netty.util.HashedWheelTimer;
28 | import io.netty.util.Timer;
29 | import io.netty.util.concurrent.DefaultEventExecutor;
30 | import net.javaforge.netty.servlet.bridge.config.WebappConfiguration;
31 | import net.javaforge.netty.servlet.bridge.impl.ServletBridgeWebapp;
32 | import net.javaforge.netty.servlet.bridge.interceptor.ChannelInterceptor;
33 | import net.javaforge.netty.servlet.bridge.interceptor.HttpSessionInterceptor;
34 | import net.javaforge.netty.servlet.bridge.session.DefaultServletBridgeHttpSessionStore;
35 | import net.javaforge.netty.servlet.bridge.session.ServletBridgeHttpSessionStore;
36 |
37 | //import io.netty.channel.ChannelPipelineFactory;
38 | //import io.netty.handler.codec.http.HttpChunkAggregator;
39 |
40 | //TODO Just fix the compilation error. not right implementation
41 | public class ServletBridgeChannelPipelineFactory {
42 | // implements
43 | // ChannelPipelineFactory {
44 |
45 | private DefaultEventExecutor eventExecutor = new DefaultEventExecutor();
46 |
47 | private ChannelGroup allChannels = new DefaultChannelGroup(eventExecutor);
48 |
49 | private HttpSessionWatchdog watchdog;
50 |
51 | private final ChannelHandler idleStateHandler;
52 |
53 | private Timer timer;
54 |
55 | public ServletBridgeChannelPipelineFactory(WebappConfiguration config) {
56 |
57 | this.timer = new HashedWheelTimer();
58 | this.idleStateHandler = new IdleStateHandler(60, 30, 0); // timer
59 | // must
60 | // be
61 | // shared.
62 |
63 | ServletBridgeWebapp webapp = ServletBridgeWebapp.get();
64 | webapp.init(config, allChannels);
65 |
66 | new Thread(this.watchdog = new HttpSessionWatchdog()).start();
67 | }
68 |
69 | public void shutdown() {
70 | this.watchdog.stopWatching();
71 | ServletBridgeWebapp.get().destroy();
72 | this.timer.stop();
73 | this.allChannels.close().awaitUninterruptibly();
74 | }
75 |
76 | // @Override
77 | public final ChannelPipeline pipeline() {
78 | ChannelPipeline pipeline = getDefaulHttpChannelPipeline();
79 | pipeline.addLast("handler", getServletBridgeHandler());
80 | return pipeline;
81 | }
82 |
83 | protected ServletBridgeHttpSessionStore getHttpSessionStore() {
84 | return new DefaultServletBridgeHttpSessionStore();
85 | }
86 |
87 | protected ServletBridgeHandler getServletBridgeHandler() {
88 |
89 | ServletBridgeHandler bridge = new ServletBridgeHandler();
90 | bridge.addInterceptor(new ChannelInterceptor());
91 | bridge.addInterceptor(new HttpSessionInterceptor(
92 | getHttpSessionStore()));
93 | return bridge;
94 | }
95 |
96 | protected ChannelPipeline getDefaulHttpChannelPipeline() {
97 |
98 | // Create a default pipeline implementation.
99 | ChannelPipeline pipeline = pipeline();
100 |
101 | pipeline.addLast("decoder", new HttpRequestDecoder());
102 | // pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
103 | pipeline.addLast("encoder", new HttpResponseEncoder());
104 |
105 | // Remove the following line if you don't want automatic content
106 | // compression.
107 | pipeline.addLast("deflater", new HttpContentCompressor());
108 | pipeline.addLast("idle", this.idleStateHandler);
109 |
110 | return pipeline;
111 | }
112 |
113 | private class HttpSessionWatchdog implements Runnable {
114 |
115 | private boolean shouldStopWatching = false;
116 |
117 | @Override
118 | public void run() {
119 |
120 | while (!shouldStopWatching) {
121 |
122 | try {
123 | ServletBridgeHttpSessionStore store = getHttpSessionStore();
124 | if (store != null) {
125 | store.destroyInactiveSessions();
126 | }
127 | Thread.sleep(5000);
128 |
129 | } catch (InterruptedException e) {
130 | return;
131 | }
132 |
133 | }
134 |
135 | }
136 |
137 | public void stopWatching() {
138 | this.shouldStopWatching = true;
139 | }
140 |
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/ServletBridgeException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge;
18 |
19 | public class ServletBridgeException extends Exception {
20 |
21 | private static final long serialVersionUID = 1L;
22 |
23 | public ServletBridgeException(String message, Throwable cause) {
24 | super(message, cause);
25 | }
26 |
27 | public ServletBridgeException(String message) {
28 | super(message);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/ServletBridgeHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge;
18 |
19 | import io.netty.buffer.ByteBuf;
20 | import io.netty.buffer.Unpooled;
21 | import io.netty.channel.*;
22 | import io.netty.handler.codec.TooLongFrameException;
23 | import io.netty.handler.codec.http.*;
24 | import io.netty.handler.ssl.SslHandler;
25 | import io.netty.handler.stream.ChunkedFile;
26 | import io.netty.handler.timeout.IdleStateEvent;
27 | import io.netty.handler.timeout.IdleStateHandler;
28 | import net.javaforge.netty.servlet.bridge.impl.FilterChainImpl;
29 | import net.javaforge.netty.servlet.bridge.impl.HttpServletRequestImpl;
30 | import net.javaforge.netty.servlet.bridge.impl.HttpServletResponseImpl;
31 | import net.javaforge.netty.servlet.bridge.impl.ServletBridgeWebapp;
32 | import net.javaforge.netty.servlet.bridge.util.Utils;
33 | import org.slf4j.Logger;
34 | import org.slf4j.LoggerFactory;
35 |
36 | import java.io.File;
37 | import java.io.FileNotFoundException;
38 | import java.io.RandomAccessFile;
39 | import java.io.UnsupportedEncodingException;
40 | import java.util.ArrayList;
41 | import java.util.List;
42 |
43 | import static io.netty.handler.codec.http.HttpHeaders.Names.*;
44 | import static io.netty.handler.codec.http.HttpHeaders.setContentLength;
45 | import static io.netty.handler.codec.http.HttpMethod.GET;
46 | import static io.netty.handler.codec.http.HttpResponseStatus.*;
47 | import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
48 |
49 | @ChannelHandler.Sharable
50 | public class ServletBridgeHandler extends IdleStateHandler {
51 |
52 |
53 | private static final Logger log = LoggerFactory
54 | .getLogger(ServletBridgeHandler.class);
55 |
56 | private List interceptors;
57 |
58 |
59 | /**
60 | * Which uri should be passed into this servlet container
61 | */
62 | private String uriPrefix = "/";
63 |
64 | public ServletBridgeHandler() {
65 | this("/");
66 | }
67 |
68 | public ServletBridgeHandler(String uriPrefix) {
69 | super(20000, 20000, 20000);
70 | this.uriPrefix = uriPrefix;
71 | }
72 |
73 | public ServletBridgeHandler addInterceptor(
74 | ServletBridgeInterceptor interceptor) {
75 |
76 | if (interceptors == null)
77 | interceptors = new ArrayList();
78 |
79 | interceptors.add(interceptor);
80 | return this;
81 | }
82 |
83 | @Override
84 | public void channelActive(ChannelHandlerContext ctx)
85 | throws Exception {
86 | log.debug("Opening new channel: {}", ctx.channel().id());
87 | ServletBridgeWebapp.get().getSharedChannelGroup().add(ctx.channel());
88 |
89 | ctx.fireChannelActive();
90 | }
91 |
92 | @Override
93 | public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) {
94 | log.debug("Closing idle channel: {}", ctx.channel().id());
95 | ctx.channel().close();
96 | }
97 |
98 | @Override
99 | public void channelRead(ChannelHandlerContext ctx, Object e)
100 | throws Exception {
101 |
102 | if (e instanceof HttpRequest) {
103 | HttpRequest request = (HttpRequest) e;
104 |
105 | String uri = request.uri();
106 |
107 | if (uri.startsWith(uriPrefix)) {
108 | if (HttpHeaders.is100ContinueExpected(request)) {
109 | ctx.channel().write(new DefaultHttpResponse(HTTP_1_1, CONTINUE));
110 | }
111 |
112 |
113 | FilterChainImpl chain = ServletBridgeWebapp.get().initializeChain(uri);
114 |
115 | if (chain.isValid()) {
116 | handleHttpServletRequest(ctx, request, chain);
117 | } else if (ServletBridgeWebapp.get().getStaticResourcesFolder() != null) {
118 | handleStaticResourceRequest(ctx, request);
119 | } else {
120 | throw new ServletBridgeRuntimeException(
121 | "No handler found for uri: " + request.getUri());
122 | }
123 | } else {
124 | ctx.fireChannelRead(e);
125 | }
126 | } else {
127 | ctx.fireChannelRead(e);
128 | }
129 | }
130 |
131 | protected void handleHttpServletRequest(ChannelHandlerContext ctx,
132 | HttpRequest request, FilterChainImpl chain) throws Exception {
133 |
134 | interceptOnRequestReceived(ctx, request);
135 |
136 | DefaultFullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK);
137 |
138 | HttpServletResponseImpl resp = buildHttpServletResponse(response);
139 | HttpServletRequestImpl req = buildHttpServletRequest(request, chain);
140 |
141 |
142 | chain.doFilter(req, resp);
143 |
144 | interceptOnRequestSuccessed(ctx, request, response);
145 |
146 | resp.getWriter().flush();
147 |
148 | boolean keepAlive = HttpHeaders.isKeepAlive(request);
149 |
150 | if (keepAlive) {
151 |
152 | // Add 'Content-Length' header only for a keep-alive connection.
153 | response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
154 | // Add keep alive header as per:
155 | // -
156 | // http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
157 | response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
158 | }
159 |
160 | // write response...
161 | ChannelFuture future = ctx.channel().writeAndFlush(response);
162 |
163 | if (!keepAlive) {
164 | future.addListener(ChannelFutureListener.CLOSE);
165 | }
166 |
167 | }
168 |
169 | protected void handleStaticResourceRequest(ChannelHandlerContext ctx,
170 | HttpRequest request) throws Exception {
171 | if (request.method() != GET) {
172 | sendError(ctx, METHOD_NOT_ALLOWED);
173 | return;
174 | }
175 |
176 | String uri = Utils.sanitizeUri(request.uri());
177 | final String path = (uri != null ? ServletBridgeWebapp.get()
178 | .getStaticResourcesFolder().getAbsolutePath()
179 | + File.separator + uri : null);
180 |
181 | if (path == null) {
182 | sendError(ctx, FORBIDDEN);
183 | return;
184 | }
185 |
186 | File file = new File(path);
187 | if (file.isHidden() || !file.exists()) {
188 | sendError(ctx, NOT_FOUND);
189 | return;
190 | }
191 | if (!file.isFile()) {
192 | sendError(ctx, FORBIDDEN);
193 | return;
194 | }
195 |
196 | RandomAccessFile raf;
197 | try {
198 | raf = new RandomAccessFile(file, "r");
199 | } catch (FileNotFoundException fnfe) {
200 | sendError(ctx, NOT_FOUND);
201 | return;
202 | }
203 |
204 | long fileLength = raf.length();
205 |
206 | HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
207 | setContentLength(response, fileLength);
208 |
209 | Channel ch = ctx.channel();
210 |
211 | // Write the initial line and the header.
212 | ch.write(response);
213 |
214 | // Write the content.
215 | ChannelFuture writeFuture;
216 | if (isSslChannel(ch)) {
217 | // Cannot use zero-copy with HTTPS.
218 | writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192));
219 | } else {
220 | // No encryption - use zero-copy.
221 | final FileRegion region = new DefaultFileRegion(raf.getChannel(),
222 | 0, fileLength);
223 | writeFuture = ch.write(region);
224 | writeFuture.addListener(new ChannelProgressiveFutureListener() {
225 |
226 | @Override
227 | public void operationProgressed(ChannelProgressiveFuture channelProgressiveFuture, long current, long total) throws Exception {
228 | System.out.printf("%s: %d / %d (+%d)%n", path, current,
229 | total, total);
230 | }
231 |
232 | @Override
233 | public void operationComplete(ChannelProgressiveFuture channelProgressiveFuture) throws Exception {
234 | region.release();
235 | }
236 | });
237 | }
238 |
239 | }
240 |
241 | @Override
242 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
243 | log.error("Unexpected exception from downstream.", cause);
244 |
245 | Channel ch = ctx.channel();
246 | if (cause instanceof IllegalArgumentException) {
247 | ch.close();
248 | } else {
249 | if (cause instanceof TooLongFrameException) {
250 | sendError(ctx, BAD_REQUEST);
251 | return;
252 | }
253 |
254 | if (ch.isActive()) {
255 | sendError(ctx, INTERNAL_SERVER_ERROR);
256 | }
257 |
258 | }
259 |
260 | }
261 |
262 | private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
263 | String text = "Failure: " + status.toString() + "\r\n";
264 | ByteBuf byteBuf = Unpooled.buffer();
265 | byte[] bytes = null;
266 | try {
267 | bytes = text.getBytes("utf-8");
268 | byteBuf.writeBytes(bytes);
269 | } catch (UnsupportedEncodingException e) {
270 | }
271 |
272 | FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, byteBuf);
273 | HttpHeaders headers = response.headers();
274 |
275 | headers.add(CONTENT_TYPE, "text/plain;charset=utf-8");
276 | headers.add(CACHE_CONTROL, "no-cache");
277 | headers.add(PRAGMA, "No-cache");
278 | headers.add(SERVER, "eBay Server");
279 | headers.add(CONTENT_LENGTH, byteBuf.readableBytes());
280 | ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
281 | }
282 |
283 | private void interceptOnRequestReceived(ChannelHandlerContext ctx,
284 | HttpRequest request) {
285 | if (interceptors != null) {
286 | for (ServletBridgeInterceptor interceptor : interceptors) {
287 | interceptor.onRequestReceived(ctx, request);
288 | }
289 | }
290 |
291 | }
292 |
293 | private void interceptOnRequestSuccessed(ChannelHandlerContext ctx,
294 | HttpRequest request, HttpResponse response) {
295 | if (interceptors != null) {
296 | for (ServletBridgeInterceptor interceptor : interceptors) {
297 | interceptor.onRequestSuccessed(ctx, request, response);
298 | }
299 | }
300 |
301 | }
302 |
303 | // private void interceptOnRequestFailed(ChannelHandlerContext ctx,
304 | // ExceptionEvent e, HttpResponse response) {
305 | // if (this.interceptors != null) {
306 | // for (ServletBridgeInterceptor interceptor : this.interceptors) {
307 | // interceptor.onRequestFailed(ctx, e, response);
308 | // }
309 | // }
310 | //
311 | // }
312 |
313 | protected HttpServletResponseImpl buildHttpServletResponse(
314 | FullHttpResponse response) {
315 | return new HttpServletResponseImpl(response);
316 | }
317 |
318 | protected HttpServletRequestImpl buildHttpServletRequest(
319 | HttpRequest request, FilterChainImpl chain) {
320 | return new HttpServletRequestImpl(request, chain);
321 | }
322 |
323 | private boolean isSslChannel(Channel ch) {
324 | return ch.pipeline().get(SslHandler.class) != null;
325 | }
326 |
327 | public String getUriPrefix() {
328 | return uriPrefix;
329 | }
330 |
331 | public void setUriPrefix(String uriPrefix) {
332 | this.uriPrefix = uriPrefix;
333 | }
334 | }
335 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/ServletBridgeInterceptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge;
18 |
19 | import io.netty.channel.ChannelHandlerContext;
20 | import io.netty.handler.codec.http.HttpRequest;
21 | import io.netty.handler.codec.http.HttpResponse;
22 |
23 | public interface ServletBridgeInterceptor {
24 |
25 | void onRequestReceived(ChannelHandlerContext ctx, HttpRequest e);
26 |
27 | void onRequestSuccessed(ChannelHandlerContext ctx, HttpRequest e,
28 | HttpResponse response);
29 |
30 | void onRequestFailed(ChannelHandlerContext ctx, Throwable e,
31 | HttpResponse response);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/ServletBridgeRuntimeException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge;
18 |
19 | public class ServletBridgeRuntimeException extends RuntimeException {
20 |
21 | private static final long serialVersionUID = 1L;
22 |
23 | public ServletBridgeRuntimeException(String message, Throwable cause) {
24 | super(message, cause);
25 | }
26 |
27 | public ServletBridgeRuntimeException(String message) {
28 | super(message);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/config/FilterConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.config;
18 |
19 | import net.javaforge.netty.servlet.bridge.impl.FilterConfigImpl;
20 |
21 | import javax.servlet.Filter;
22 | import javax.servlet.ServletException;
23 |
24 | public class FilterConfiguration extends
25 | HttpComponentConfigurationAdapter {
26 |
27 | public FilterConfiguration(Class extends Filter> servletClazz,
28 | String... urlPatterns) {
29 | super(servletClazz, urlPatterns);
30 | }
31 |
32 | public FilterConfiguration(Class extends Filter> componentClazz) {
33 | super(componentClazz);
34 | }
35 |
36 | public FilterConfiguration(Filter component, String... urlPatterns) {
37 | super(component, urlPatterns);
38 | }
39 |
40 | public FilterConfiguration(Filter servlet) {
41 | super(servlet);
42 | }
43 |
44 | @Override
45 | protected void doInit() throws ServletException {
46 | this.component.init(this.config);
47 | }
48 |
49 | @Override
50 | protected void doDestroy() throws ServletException {
51 | this.component.destroy();
52 | }
53 |
54 | @Override
55 | protected FilterConfigImpl newConfigInstance(
56 | Class extends Filter> componentClazz) {
57 | return new FilterConfigImpl(componentClazz.getName());
58 | }
59 |
60 | public FilterConfiguration addInitParameter(String name, String value) {
61 | super.addConfigInitParameter(name, value);
62 | return this;
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/config/HttpComponentConfigurationAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.config;
18 |
19 | import net.javaforge.netty.servlet.bridge.impl.ConfigAdapter;
20 | import net.javaforge.netty.servlet.bridge.util.Utils;
21 | import org.slf4j.Logger;
22 | import org.slf4j.LoggerFactory;
23 |
24 | import javax.servlet.ServletException;
25 | import java.util.regex.Pattern;
26 |
27 | public abstract class HttpComponentConfigurationAdapter {
28 |
29 | private static final Logger log = LoggerFactory
30 | .getLogger(HttpComponentConfigurationAdapter.class);
31 |
32 | private static final String DEFAULT_URL_PATTERN = "/*";
33 |
34 | private String[] sanitizedUrlPatterns;
35 |
36 | private Pattern[] regexPatterns;
37 |
38 | protected COMP component;
39 |
40 | protected CONFIG config;
41 |
42 | private boolean initialized = false;
43 |
44 | public HttpComponentConfigurationAdapter(
45 | Class extends COMP> componentClazz) {
46 | this(Utils.newInstance(componentClazz), DEFAULT_URL_PATTERN);
47 | }
48 |
49 | public HttpComponentConfigurationAdapter(
50 | Class extends COMP> servletClazz, String... urlPatterns) {
51 | this(Utils.newInstance(servletClazz), urlPatterns);
52 | }
53 |
54 | public HttpComponentConfigurationAdapter(COMP servlet) {
55 | this(servlet, DEFAULT_URL_PATTERN);
56 | }
57 |
58 | @SuppressWarnings("unchecked")
59 | public HttpComponentConfigurationAdapter(COMP component,
60 | String... urlPatterns) {
61 | if (urlPatterns == null || urlPatterns.length == 0)
62 | throw new IllegalStateException(
63 | "No url patterns were assigned to http component: "
64 | + component);
65 |
66 | this.regexPatterns = new Pattern[urlPatterns.length];
67 | this.sanitizedUrlPatterns = new String[urlPatterns.length];
68 |
69 | for (int i = 0; i < urlPatterns.length; i++) {
70 | String regex = urlPatterns[i].replaceAll("\\*", ".*");
71 | this.regexPatterns[i] = Pattern.compile(regex);
72 | this.sanitizedUrlPatterns[i] = urlPatterns[i].replaceAll("\\*", "");
73 | if (this.sanitizedUrlPatterns[i].endsWith("/"))
74 | this.sanitizedUrlPatterns[i] = this.sanitizedUrlPatterns[i]
75 | .substring(0, this.sanitizedUrlPatterns[i].length() - 1);
76 | }
77 |
78 | this.component = component;
79 | this.config = newConfigInstance((Class extends COMP>) component
80 | .getClass());
81 | }
82 |
83 | protected abstract CONFIG newConfigInstance(
84 | Class extends COMP> componentClazz);
85 |
86 | public void init() {
87 | try {
88 |
89 | log.debug("Initializing http component: {}", this.component
90 | .getClass());
91 |
92 | this.doInit();
93 | this.initialized = true;
94 |
95 | } catch (ServletException e) {
96 |
97 | this.initialized = false;
98 | log.error("Http component '" + this.component.getClass()
99 | + "' was not initialized!", e);
100 | }
101 | }
102 |
103 | public void destroy() {
104 | try {
105 |
106 | log.debug("Destroying http component: {}", this.component
107 | .getClass());
108 |
109 | this.doDestroy();
110 | this.initialized = false;
111 |
112 | } catch (ServletException e) {
113 |
114 | this.initialized = false;
115 | log.error("Http component '" + this.component.getClass()
116 | + "' was not destroyed!", e);
117 | }
118 | }
119 |
120 | protected abstract void doInit() throws ServletException;
121 |
122 | protected abstract void doDestroy() throws ServletException;
123 |
124 | public boolean matchesUrlPattern(String uri) {
125 | return getMatchingUrlPattern(uri) != null;
126 | }
127 |
128 | public String getMatchingUrlPattern(String uri) {
129 | int indx = uri.indexOf('?');
130 |
131 | String path = indx != -1 ? uri.substring(0, indx) : uri.substring(0);
132 | if (!path.endsWith("/"))
133 | path += "/";
134 |
135 | for (int i = 0; i < regexPatterns.length; i++) {
136 | Pattern pattern = regexPatterns[i];
137 | if (pattern.matcher(path).matches()) {
138 | return sanitizedUrlPatterns[i];
139 | }
140 | }
141 |
142 | return null;
143 |
144 | }
145 |
146 | protected void addConfigInitParameter(String name, String value) {
147 | this.config.addInitParameter(name, value);
148 | }
149 |
150 | public COMP getHttpComponent() {
151 | return this.component;
152 | }
153 |
154 | public CONFIG getConfig() {
155 | return this.config;
156 | }
157 |
158 | public boolean isInitialized() {
159 | return initialized;
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/config/ServletConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.config;
18 |
19 | import net.javaforge.netty.servlet.bridge.impl.ServletConfigImpl;
20 |
21 | import javax.servlet.ServletException;
22 | import javax.servlet.http.HttpServlet;
23 |
24 | public class ServletConfiguration extends
25 | HttpComponentConfigurationAdapter {
26 |
27 | public ServletConfiguration(Class extends HttpServlet> servletClazz,
28 | String... urlPatterns) {
29 | super(servletClazz, urlPatterns);
30 | }
31 |
32 | public ServletConfiguration(Class extends HttpServlet> componentClazz) {
33 | super(componentClazz);
34 | }
35 |
36 | public ServletConfiguration(HttpServlet component, String... urlPatterns) {
37 | super(component, urlPatterns);
38 | }
39 |
40 | public ServletConfiguration(HttpServlet servlet) {
41 | super(servlet);
42 | }
43 |
44 | @Override
45 | protected void doInit() throws ServletException {
46 | this.component.init(this.config);
47 | }
48 |
49 | @Override
50 | protected void doDestroy() throws ServletException {
51 | this.component.destroy();
52 | }
53 |
54 | @Override
55 | protected ServletConfigImpl newConfigInstance(
56 | Class extends HttpServlet> componentClazz) {
57 | return new ServletConfigImpl(this.component.getClass().getName());
58 | }
59 |
60 | public ServletConfiguration addInitParameter(String name, String value) {
61 | super.addConfigInitParameter(name, value);
62 | return this;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/config/ServletContextListenerConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.config;
18 |
19 | import net.javaforge.netty.servlet.bridge.impl.ServletContextImpl;
20 | import net.javaforge.netty.servlet.bridge.util.Utils;
21 | import org.slf4j.Logger;
22 | import org.slf4j.LoggerFactory;
23 |
24 | import javax.servlet.ServletContextEvent;
25 | import javax.servlet.ServletContextListener;
26 |
27 | public class ServletContextListenerConfiguration {
28 |
29 | private static final Logger log = LoggerFactory
30 | .getLogger(ServletContextListenerConfiguration.class);
31 |
32 | private ServletContextListener listener;
33 |
34 | private boolean initialized = false;
35 |
36 | public ServletContextListenerConfiguration(
37 | Class extends ServletContextListener> clazz) {
38 | this(Utils.newInstance(clazz));
39 | }
40 |
41 | public ServletContextListenerConfiguration(ServletContextListener listener) {
42 | this.listener = listener;
43 | }
44 |
45 | public ServletContextListener getListener() {
46 | return listener;
47 | }
48 |
49 | public void init() {
50 | try {
51 |
52 | log.debug("Initializing listener: {}", this.listener.getClass());
53 |
54 | this.listener.contextInitialized(new ServletContextEvent(
55 | ServletContextImpl.get()));
56 | this.initialized = true;
57 |
58 | } catch (Exception e) {
59 |
60 | this.initialized = false;
61 | log.error("Listener '" + this.listener.getClass()
62 | + "' was not initialized!", e);
63 | }
64 | }
65 |
66 | public void destroy() {
67 | try {
68 |
69 | log.debug("Destroying listener: {}", this.listener.getClass());
70 |
71 | this.listener.contextDestroyed(new ServletContextEvent(
72 | ServletContextImpl.get()));
73 | this.initialized = false;
74 |
75 | } catch (Exception e) {
76 |
77 | this.initialized = false;
78 | log.error("Listener '" + this.listener.getClass()
79 | + "' was not destroyed!", e);
80 | }
81 | }
82 |
83 | public boolean isInitialized() {
84 | return initialized;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/config/WebappConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.config;
18 |
19 | import javax.servlet.Filter;
20 | import javax.servlet.ServletContextListener;
21 | import javax.servlet.http.HttpServlet;
22 | import java.io.File;
23 | import java.util.*;
24 |
25 | public class WebappConfiguration {
26 |
27 | private String name;
28 |
29 | private int sessionTimeout = 60 * 60; // 1 hour
30 |
31 | private Map contextParameters;
32 |
33 | private Collection contextListeners;
34 |
35 | private Collection filters;
36 |
37 | private Collection servlets;
38 |
39 | private File staticResourcesFolder;
40 |
41 | public WebappConfiguration addContextParameter(String name, String value) {
42 |
43 | if (this.contextParameters == null)
44 | this.contextParameters = new HashMap();
45 |
46 | this.contextParameters.put(name, value);
47 | return this;
48 | }
49 |
50 | public WebappConfiguration addServletContextListener(
51 | Class extends ServletContextListener> listenerClass) {
52 | return this
53 | .addServletContextListenerConfigurations(new ServletContextListenerConfiguration(
54 | listenerClass));
55 | }
56 |
57 | public WebappConfiguration addServletContextListener(
58 | ServletContextListener listener) {
59 | return this
60 | .addServletContextListenerConfigurations(new ServletContextListenerConfiguration(
61 | listener));
62 | }
63 |
64 | public WebappConfiguration addServletContextListenerConfigurations(
65 | ServletContextListenerConfiguration... configs) {
66 |
67 | if (configs == null || configs.length == 0)
68 | return this;
69 |
70 | return this.addServletContextListenerConfigurations(Arrays
71 | .asList(configs));
72 | }
73 |
74 | public WebappConfiguration addServletContextListenerConfigurations(
75 | List configs) {
76 | if (configs == null || configs.size() == 0)
77 | return this;
78 |
79 | if (this.contextListeners == null)
80 | this.contextListeners = new ArrayList();
81 |
82 | this.contextListeners.addAll(configs);
83 | return this;
84 | }
85 |
86 | public Collection getServletContextListenerConfigurations() {
87 | return this.contextListeners != null ? Collections
88 | .unmodifiableCollection(this.contextListeners) : null;
89 | }
90 |
91 | public Map getContextParameters() {
92 | return this.contextParameters != null ? Collections
93 | .unmodifiableMap(this.contextParameters) : null;
94 | }
95 |
96 | public WebappConfiguration setName(String name) {
97 | this.name = name;
98 | return this;
99 | }
100 |
101 | public String getName() {
102 | return this.name;
103 | }
104 |
105 | public WebappConfiguration setSessionTimeout(int sessionTimeout) {
106 | this.sessionTimeout = sessionTimeout;
107 | return this;
108 | }
109 |
110 | public int getSessionTimeout() {
111 | return sessionTimeout;
112 | }
113 |
114 | public WebappConfiguration addFilter(Filter filter) {
115 | return this.addFilterConfigurations(new FilterConfiguration(filter));
116 | }
117 |
118 | public WebappConfiguration addFilter(Filter filter, String... urlPatterns) {
119 | return this.addFilterConfigurations(new FilterConfiguration(filter,
120 | urlPatterns));
121 | }
122 |
123 | public WebappConfiguration addFilter(Class extends Filter> filterClass) {
124 | return this
125 | .addFilterConfigurations(new FilterConfiguration(filterClass));
126 | }
127 |
128 | public WebappConfiguration addFilter(Class extends Filter> filterClass,
129 | String... urlPatterns) {
130 | return this.addFilterConfigurations(new FilterConfiguration(
131 | filterClass, urlPatterns));
132 | }
133 |
134 | public WebappConfiguration addFilterConfigurations(
135 | FilterConfiguration... filters) {
136 |
137 | if (filters == null || filters.length == 0)
138 | return this;
139 |
140 | return this.addfilterConfigurations(Arrays.asList(filters));
141 | }
142 |
143 | public WebappConfiguration addfilterConfigurations(
144 | Collection configs) {
145 |
146 | if (configs == null || configs.size() == 0)
147 | return this;
148 |
149 | if (this.filters == null)
150 | this.filters = new ArrayList();
151 |
152 | this.filters.addAll(configs);
153 | return this;
154 | }
155 |
156 | public Collection getFilterConfigurations() {
157 | return this.filters != null ? Collections
158 | .unmodifiableCollection(this.filters) : null;
159 | }
160 |
161 | public boolean hasFilterConfigurations() {
162 | return this.filters != null && !this.filters.isEmpty();
163 | }
164 |
165 | public WebappConfiguration addHttpServlet(HttpServlet servlet) {
166 | return this.addServletConfigurations(new ServletConfiguration(servlet));
167 | }
168 |
169 | public WebappConfiguration addHttpServlet(HttpServlet servlet,
170 | String... urlPatterns) {
171 | return this.addServletConfigurations(new ServletConfiguration(servlet,
172 | urlPatterns));
173 | }
174 |
175 | public WebappConfiguration addHttpServlet(
176 | Class extends HttpServlet> servletClass) {
177 | return this.addServletConfigurations(new ServletConfiguration(
178 | servletClass));
179 | }
180 |
181 | public WebappConfiguration addHttpServlet(
182 | Class extends HttpServlet> servletClass, String... urlPatterns) {
183 | return this.addServletConfigurations(new ServletConfiguration(
184 | servletClass, urlPatterns));
185 | }
186 |
187 | public WebappConfiguration addServletConfigurations(
188 | ServletConfiguration... servlets) {
189 |
190 | if (servlets == null || servlets.length == 0)
191 | return this;
192 |
193 | return this.addServletConfigurations(Arrays.asList(servlets));
194 | }
195 |
196 | public WebappConfiguration addServletConfigurations(
197 | Collection configs) {
198 |
199 | if (configs == null || configs.size() == 0)
200 | return this;
201 |
202 | if (this.servlets == null)
203 | this.servlets = new ArrayList();
204 |
205 | this.servlets.addAll(configs);
206 | return this;
207 | }
208 |
209 | public Collection getServletConfigurations() {
210 | return this.servlets != null ? Collections
211 | .unmodifiableCollection(this.servlets) : null;
212 | }
213 |
214 | public boolean hasServletConfigurations() {
215 | return this.servlets != null && !this.servlets.isEmpty();
216 | }
217 |
218 | public WebappConfiguration setStaticResourcesFolder(String folder) {
219 | return this.setStaticResourcesFolder(new File(folder));
220 | }
221 |
222 | public WebappConfiguration setStaticResourcesFolder(File folder) {
223 | if (folder == null)
224 | throw new IllegalArgumentException(
225 | "Static resources folder must be not null!");
226 |
227 | if (!folder.exists())
228 | throw new IllegalArgumentException("Static resources folder '"
229 | + folder.getAbsolutePath() + "' was not found!");
230 |
231 | if (!folder.isDirectory())
232 | throw new IllegalArgumentException("Static resources folder '"
233 | + folder.getAbsolutePath() + "' must be a directory!");
234 |
235 | this.staticResourcesFolder = folder;
236 | return this;
237 | }
238 |
239 | public File getStaticResourcesFolder() {
240 | return staticResourcesFolder;
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/ConfigAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import net.javaforge.netty.servlet.bridge.util.Utils;
20 |
21 | import java.util.Enumeration;
22 | import java.util.HashMap;
23 | import java.util.Map;
24 |
25 | public abstract class ConfigAdapter {
26 |
27 | private String ownerName;
28 |
29 | private Map initParameters;
30 |
31 | public ConfigAdapter(String ownerName) {
32 | this.ownerName = ownerName;
33 | }
34 |
35 | public void addInitParameter(String name, String value) {
36 | if (this.initParameters == null)
37 | this.initParameters = new HashMap();
38 |
39 | this.initParameters.put(name, value);
40 | }
41 |
42 | public String getInitParameter(String name) {
43 | if (this.initParameters == null)
44 | return null;
45 |
46 | return this.initParameters.get(name);
47 | }
48 |
49 | @SuppressWarnings("unchecked")
50 | public Enumeration getInitParameterNames() {
51 | return Utils.enumerationFromKeys(this.initParameters);
52 | }
53 |
54 | String getOwnerName() {
55 | return ownerName;
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/FilterChainImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import net.javaforge.netty.servlet.bridge.config.FilterConfiguration;
20 | import net.javaforge.netty.servlet.bridge.config.ServletConfiguration;
21 |
22 | import javax.servlet.FilterChain;
23 | import javax.servlet.ServletException;
24 | import javax.servlet.ServletRequest;
25 | import javax.servlet.ServletResponse;
26 | import java.io.IOException;
27 | import java.util.LinkedList;
28 |
29 | public class FilterChainImpl implements FilterChain {
30 |
31 | private LinkedList filterConfigurations;
32 |
33 | private ServletConfiguration servletConfiguration;
34 |
35 | public FilterChainImpl(ServletConfiguration servletConfiguration) {
36 | this.servletConfiguration = servletConfiguration;
37 | }
38 |
39 | public void addFilterConfiguration(FilterConfiguration config) {
40 |
41 | if (this.filterConfigurations == null)
42 | this.filterConfigurations = new LinkedList();
43 |
44 | this.filterConfigurations.add(config);
45 | }
46 |
47 | @Override
48 | public void doFilter(ServletRequest request, ServletResponse response)
49 | throws IOException, ServletException {
50 |
51 | FilterConfiguration config = filterConfigurations != null ? filterConfigurations
52 | .poll()
53 | : null;
54 |
55 | if (config != null)
56 | config.getHttpComponent().doFilter(request, response, this);
57 |
58 | else if (this.servletConfiguration != null) {
59 |
60 | this.servletConfiguration.getHttpComponent().service(request,
61 | response);
62 | }
63 | }
64 |
65 | public boolean isValid() {
66 | return this.servletConfiguration != null
67 | || (this.filterConfigurations != null && !this.filterConfigurations
68 | .isEmpty());
69 | }
70 |
71 | public ServletConfiguration getServletConfiguration() {
72 | return servletConfiguration;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/FilterConfigImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import javax.servlet.FilterConfig;
20 | import javax.servlet.ServletContext;
21 |
22 | public class FilterConfigImpl extends ConfigAdapter implements FilterConfig {
23 |
24 | public FilterConfigImpl(String filterName) {
25 | super(filterName);
26 | }
27 |
28 | @Override
29 | public String getFilterName() {
30 | return super.getOwnerName();
31 | }
32 |
33 | @Override
34 | public ServletContext getServletContext() {
35 | return ServletContextImpl.get();
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/HttpServletRequestImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import io.netty.handler.codec.http.*;
20 | import io.netty.handler.codec.http.HttpHeaders.Names;
21 | import io.netty.handler.ssl.SslHandler;
22 | import net.javaforge.netty.servlet.bridge.ChannelThreadLocal;
23 | import net.javaforge.netty.servlet.bridge.HttpSessionThreadLocal;
24 | import net.javaforge.netty.servlet.bridge.util.Utils;
25 |
26 | import javax.servlet.RequestDispatcher;
27 | import javax.servlet.ServletInputStream;
28 | import javax.servlet.http.Cookie;
29 | import javax.servlet.http.HttpServletRequest;
30 | import javax.servlet.http.HttpSession;
31 | import java.io.BufferedReader;
32 | import java.io.IOException;
33 | import java.io.InputStreamReader;
34 | import java.io.UnsupportedEncodingException;
35 | import java.net.InetSocketAddress;
36 | import java.security.Principal;
37 | import java.util.*;
38 |
39 | import static io.netty.handler.codec.http.HttpHeaders.Names.*;
40 |
41 | @SuppressWarnings("unchecked")
42 | public class HttpServletRequestImpl implements HttpServletRequest {
43 |
44 | private static final Locale DEFAULT_LOCALE = Locale.getDefault();
45 |
46 | private URIParser uriParser;
47 |
48 | private HttpRequest originalRequest;
49 |
50 | private ServletInputStreamImpl inputStream;
51 |
52 | private BufferedReader reader;
53 |
54 | private QueryStringDecoder queryStringDecoder;
55 |
56 | private Map attributes;
57 |
58 | private Principal userPrincipal;
59 |
60 | // private ServerCookieDecoder cookieDecoder = new ServerCookieDecoder();
61 |
62 | private String characterEncoding;
63 |
64 | public HttpServletRequestImpl(HttpRequest request, FilterChainImpl chain) {
65 | this.originalRequest = request;
66 |
67 | if (request instanceof FullHttpRequest) {
68 | this.inputStream = new ServletInputStreamImpl((FullHttpRequest) request);
69 | } else {
70 | this.inputStream = new ServletInputStreamImpl(request);
71 | }
72 | this.reader = new BufferedReader(new InputStreamReader(inputStream));
73 | this.queryStringDecoder = new QueryStringDecoder(request.getUri());
74 | this.uriParser = new URIParser(chain);
75 | this.uriParser.parse(request.getUri());
76 | this.characterEncoding = Utils
77 | .getCharsetFromContentType(getContentType());
78 |
79 | }
80 |
81 | public HttpRequest getOriginalRequest() {
82 | return originalRequest;
83 | }
84 |
85 | @Override
86 | public String getContextPath() {
87 | return ServletContextImpl.get().getContextPath();
88 | }
89 |
90 | @Override
91 | public Cookie[] getCookies() {
92 | String cookieString = this.originalRequest.headers().get(COOKIE);
93 | if (cookieString != null) {
94 | Set cookies = CookieDecoder
95 | .decode(cookieString);
96 | if (!cookies.isEmpty()) {
97 | Cookie[] cookiesArray = new Cookie[cookies.size()];
98 | int indx = 0;
99 | for (io.netty.handler.codec.http.Cookie c : cookies) {
100 | Cookie cookie = new Cookie(c.getName(), c.getValue());
101 | cookie.setComment(c.getComment());
102 | cookie.setDomain(c.getDomain());
103 | cookie.setMaxAge((int) c.getMaxAge());
104 | cookie.setPath(c.getPath());
105 | cookie.setSecure(c.isSecure());
106 | cookie.setVersion(c.getVersion());
107 | cookiesArray[indx] = cookie;
108 | indx++;
109 | }
110 | return cookiesArray;
111 |
112 | }
113 | }
114 | return null;
115 | }
116 |
117 | @Override
118 | public long getDateHeader(String name) {
119 | String longVal = getHeader(name);
120 | if (longVal == null)
121 | return -1;
122 |
123 | return Long.parseLong(longVal);
124 | }
125 |
126 | @Override
127 | public String getHeader(String name) {
128 | return HttpHeaders.getHeader(this.originalRequest, name);
129 | }
130 |
131 | @Override
132 | public Enumeration getHeaderNames() {
133 | return Utils.enumeration(this.originalRequest.headers().names());
134 | }
135 |
136 | @Override
137 | public Enumeration getHeaders(String name) {
138 | return Utils.enumeration(this.originalRequest.headers().getAll(name));
139 | }
140 |
141 | @Override
142 | public int getIntHeader(String name) {
143 | return HttpHeaders.getIntHeader(this.originalRequest, name, -1);
144 | }
145 |
146 | @Override
147 | public String getMethod() {
148 | return this.originalRequest.method().name();
149 | }
150 |
151 | @Override
152 | public String getQueryString() {
153 | return this.uriParser.getQueryString();
154 | }
155 |
156 | @Override
157 | public String getRequestURI() {
158 | return this.uriParser.getRequestUri();
159 | }
160 |
161 | @Override
162 | public StringBuffer getRequestURL() {
163 | StringBuffer url = new StringBuffer();
164 | String scheme = this.getScheme();
165 | int port = this.getServerPort();
166 | String urlPath = this.getRequestURI();
167 |
168 | // String servletPath = req.getServletPath ();
169 | // String pathInfo = req.getPathInfo ();
170 |
171 | url.append(scheme); // http, https
172 | url.append("://");
173 | url.append(this.getServerName());
174 | if ((scheme.equals("http") && port != 80)
175 | || (scheme.equals("https") && port != 443)) {
176 | url.append(':');
177 | url.append(this.getServerPort());
178 | }
179 | // if (servletPath != null)
180 | // url.append (servletPath);
181 | // if (pathInfo != null)
182 | // url.append (pathInfo);
183 | url.append(urlPath);
184 | return url;
185 | }
186 |
187 | @Override
188 | public int getContentLength() {
189 | return (int) HttpHeaders.getContentLength(this.originalRequest, -1);
190 | }
191 |
192 | @Override
193 | public String getContentType() {
194 | return HttpHeaders.getHeader(this.originalRequest,
195 | HttpHeaders.Names.CONTENT_TYPE);
196 | }
197 |
198 | @Override
199 | public ServletInputStream getInputStream() throws IOException {
200 | return this.inputStream;
201 | }
202 |
203 | @Override
204 | public String getCharacterEncoding() {
205 | return this.characterEncoding;
206 | }
207 |
208 | @Override
209 | public String getParameter(String name) {
210 | String[] values = getParameterValues(name);
211 | return values != null ? values[0] : null;
212 | }
213 |
214 | @Override
215 | public Map getParameterMap() {
216 | return this.queryStringDecoder.parameters();
217 | }
218 |
219 | @Override
220 | public Enumeration getParameterNames() {
221 | return Utils.enumerationFromKeys(this.queryStringDecoder
222 | .parameters());
223 | }
224 |
225 | @Override
226 | public String[] getParameterValues(String name) {
227 | List values = this.queryStringDecoder.parameters().get(name);
228 | if (values == null || values.isEmpty())
229 | return null;
230 | return values.toArray(new String[values.size()]);
231 | }
232 |
233 | @Override
234 | public String getProtocol() {
235 | return this.originalRequest.getProtocolVersion().toString();
236 | }
237 |
238 | @Override
239 | public Object getAttribute(String name) {
240 | if (attributes != null)
241 | return this.attributes.get(name);
242 |
243 | return null;
244 | }
245 |
246 | @Override
247 | public Enumeration getAttributeNames() {
248 | return Utils.enumerationFromKeys(this.attributes);
249 | }
250 |
251 | @Override
252 | public void removeAttribute(String name) {
253 | if (this.attributes != null)
254 | this.attributes.remove(name);
255 | }
256 |
257 | @Override
258 | public void setAttribute(String name, Object o) {
259 | if (this.attributes == null)
260 | this.attributes = new HashMap();
261 |
262 | this.attributes.put(name, o);
263 | }
264 |
265 | @Override
266 | public BufferedReader getReader() throws IOException {
267 | return this.reader;
268 | }
269 |
270 | @Override
271 | public String getRequestedSessionId() {
272 | HttpSessionImpl session = HttpSessionThreadLocal.get();
273 | return session != null ? session.getId() : null;
274 | }
275 |
276 | @Override
277 | public HttpSession getSession() {
278 | HttpSession s = HttpSessionThreadLocal.getOrCreate();
279 | return s;
280 | }
281 |
282 | @Override
283 | public HttpSession getSession(boolean create) {
284 | HttpSession session = HttpSessionThreadLocal.get();
285 | if (session == null && create) {
286 | session = HttpSessionThreadLocal.getOrCreate();
287 | }
288 | return session;
289 | }
290 |
291 | @Override
292 | public String getPathInfo() {
293 | return this.uriParser.getPathInfo();
294 | }
295 |
296 | @Override
297 | public Locale getLocale() {
298 | String locale = HttpHeaders.getHeader(this.originalRequest,
299 | Names.ACCEPT_LANGUAGE, DEFAULT_LOCALE.toString());
300 | return new Locale(locale);
301 | }
302 |
303 | @Override
304 | public String getRemoteAddr() {
305 | InetSocketAddress addr = (InetSocketAddress) ChannelThreadLocal.get()
306 | .remoteAddress();
307 | return addr.getAddress().getHostAddress();
308 | }
309 |
310 | @Override
311 | public String getRemoteHost() {
312 | InetSocketAddress addr = (InetSocketAddress) ChannelThreadLocal.get()
313 | .remoteAddress();
314 | return addr.getHostName();
315 | }
316 |
317 | @Override
318 | public int getRemotePort() {
319 | InetSocketAddress addr = (InetSocketAddress) ChannelThreadLocal.get()
320 | .remoteAddress();
321 | return addr.getPort();
322 | }
323 |
324 | @Override
325 | public String getServerName() {
326 | InetSocketAddress addr = (InetSocketAddress) ChannelThreadLocal.get()
327 | .localAddress();
328 | return addr.getHostName();
329 | }
330 |
331 | @Override
332 | public int getServerPort() {
333 | InetSocketAddress addr = (InetSocketAddress) ChannelThreadLocal.get()
334 | .localAddress();
335 | return addr.getPort();
336 | }
337 |
338 | @Override
339 | public String getServletPath() {
340 | String servletPath = this.uriParser.getServletPath();
341 | if (servletPath.equals("/"))
342 | return "";
343 |
344 | return servletPath;
345 | }
346 |
347 | @Override
348 | public String getScheme() {
349 | return this.isSecure() ? "https" : "http";
350 | }
351 |
352 | @Override
353 | public boolean isSecure() {
354 | return ChannelThreadLocal.get().pipeline().get(SslHandler.class) != null;
355 | }
356 |
357 | @Override
358 | public boolean isRequestedSessionIdFromCookie() {
359 | return true;
360 | }
361 |
362 | @Override
363 | public String getLocalAddr() {
364 | InetSocketAddress addr = (InetSocketAddress) ChannelThreadLocal.get()
365 | .localAddress();
366 | return addr.getAddress().getHostAddress();
367 | }
368 |
369 | @Override
370 | public String getLocalName() {
371 | return getServerName();
372 | }
373 |
374 | @Override
375 | public int getLocalPort() {
376 | return getServerPort();
377 | }
378 |
379 | @Override
380 | public void setCharacterEncoding(String env)
381 | throws UnsupportedEncodingException {
382 | this.characterEncoding = env;
383 | }
384 |
385 | @Override
386 | public Enumeration getLocales() {
387 | Collection locales = Utils
388 | .parseAcceptLanguageHeader(HttpHeaders
389 | .getHeader(this.originalRequest,
390 | HttpHeaders.Names.ACCEPT_LANGUAGE));
391 |
392 | if (locales == null || locales.isEmpty()) {
393 | locales = new ArrayList();
394 | locales.add(Locale.getDefault());
395 | }
396 | return Utils.enumeration(locales);
397 | }
398 |
399 | @Override
400 | public String getAuthType() {
401 | return getHeader(WWW_AUTHENTICATE);
402 | }
403 |
404 | @Override
405 | public String getPathTranslated() {
406 | throw new IllegalStateException(
407 | "Method 'getPathTranslated' not yet implemented!");
408 | }
409 |
410 | @Override
411 | public String getRemoteUser() {
412 | return getHeader(AUTHORIZATION);
413 | }
414 |
415 | @Override
416 | public Principal getUserPrincipal() {
417 | return userPrincipal;
418 | }
419 |
420 | @Override
421 | public boolean isRequestedSessionIdFromURL() {
422 | throw new IllegalStateException(
423 | "Method 'isRequestedSessionIdFromURL' not yet implemented!");
424 | }
425 |
426 | @Override
427 | public boolean isRequestedSessionIdFromUrl() {
428 | throw new IllegalStateException(
429 | "Method 'isRequestedSessionIdFromUrl' not yet implemented!");
430 | }
431 |
432 | @Override
433 | public boolean isRequestedSessionIdValid() {
434 | throw new IllegalStateException(
435 | "Method 'isRequestedSessionIdValid' not yet implemented!");
436 | }
437 |
438 | @Override
439 | public boolean isUserInRole(String role) {
440 | throw new IllegalStateException(
441 | "Method 'isUserInRole' not yet implemented!");
442 | }
443 |
444 | @Override
445 | public String getRealPath(String path) {
446 | throw new IllegalStateException(
447 | "Method 'getRealPath' not yet implemented!");
448 | }
449 |
450 | @Override
451 | public RequestDispatcher getRequestDispatcher(String path) {
452 | throw new IllegalStateException(
453 | "Method 'getRequestDispatcher' not yet implemented!");
454 | }
455 |
456 | }
457 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/HttpServletResponseImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import io.netty.handler.codec.http.*;
20 | import io.netty.handler.codec.http.HttpHeaders.Names;
21 | import net.javaforge.netty.servlet.bridge.ServletBridgeRuntimeException;
22 |
23 | import javax.servlet.ServletOutputStream;
24 | import javax.servlet.http.Cookie;
25 | import javax.servlet.http.HttpServletResponse;
26 | import java.io.IOException;
27 | import java.io.PrintWriter;
28 | import java.io.UnsupportedEncodingException;
29 | import java.net.URLEncoder;
30 | import java.util.Locale;
31 |
32 | import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION;
33 | import static io.netty.handler.codec.http.HttpHeaders.Names.SET_COOKIE;
34 |
35 | public class HttpServletResponseImpl implements HttpServletResponse {
36 | private HttpResponse originalResponse;
37 | private ServletOutputStreamImpl outputStream;
38 | private PrintWriterImpl writer;
39 | private boolean responseCommited = false;
40 | private Locale locale = null;
41 |
42 | public HttpServletResponseImpl(FullHttpResponse response) {
43 | this.originalResponse = response;
44 | this.outputStream = new ServletOutputStreamImpl(response);
45 | this.writer = new PrintWriterImpl(this.outputStream);
46 | }
47 |
48 | public HttpResponse getOriginalResponse() {
49 | return originalResponse;
50 | }
51 |
52 | @Override
53 | public void addCookie(Cookie cookie) {
54 | String result = ServerCookieEncoder.encode(new io.netty.handler.codec.http.DefaultCookie(cookie.getName(), cookie.getValue()));
55 | HttpHeaders.addHeader(this.originalResponse, SET_COOKIE, result);
56 | }
57 |
58 | @Override
59 | public void addDateHeader(String name, long date) {
60 | HttpHeaders.addHeader(this.originalResponse, name, date);
61 | }
62 |
63 | @Override
64 | public void addHeader(String name, String value) {
65 | HttpHeaders.addHeader(this.originalResponse, name, value);
66 | }
67 |
68 | @Override
69 | public void addIntHeader(String name, int value) {
70 | HttpHeaders.addIntHeader(this.originalResponse, name, value);
71 | }
72 |
73 | @Override
74 | public boolean containsHeader(String name) {
75 | return this.originalResponse.headers().contains(name);
76 | }
77 |
78 | @Override
79 | public void sendError(int sc) throws IOException {
80 | this.originalResponse.setStatus(HttpResponseStatus.valueOf(sc));
81 | }
82 |
83 | @Override
84 | public void sendError(int sc, String msg) throws IOException {
85 | //Fix the following exception
86 | /*
87 | java.lang.IllegalArgumentException: reasonPhrase contains one of the following prohibited characters: \r\n: FAILED - Cannot find View Map for null.
88 |
89 | at io.netty.handler.codec.http.HttpResponseStatus.(HttpResponseStatus.java:514) ~[netty-all-4.1.0.Beta3.jar:4.1.0.Beta3]
90 | at io.netty.handler.codec.http.HttpResponseStatus.(HttpResponseStatus.java:496) ~[netty-all-4.1.0.Beta3.jar:4.1.0.Beta3]
91 | */
92 | if (msg != null) {
93 | msg = msg.replace('\r', ' ');
94 | msg = msg.replace('\n', ' ');
95 | }
96 | this.originalResponse.setStatus(new HttpResponseStatus(sc, msg));
97 | }
98 |
99 | @Override
100 | public void sendRedirect(String location) throws IOException {
101 | setStatus(SC_FOUND);
102 | setHeader(LOCATION, location);
103 | }
104 |
105 | @Override
106 | public void setDateHeader(String name, long date) {
107 | HttpHeaders.setHeader(this.originalResponse, name, date);
108 | }
109 |
110 | @Override
111 | public void setHeader(String name, String value) {
112 | HttpHeaders.setHeader(this.originalResponse, name, value);
113 | }
114 |
115 | @Override
116 | public void setIntHeader(String name, int value) {
117 | HttpHeaders.setIntHeader(this.originalResponse, name, value);
118 |
119 | }
120 |
121 | @Override
122 | public ServletOutputStream getOutputStream() throws IOException {
123 | return this.outputStream;
124 | }
125 |
126 | @Override
127 | public PrintWriter getWriter() throws IOException {
128 | return this.writer;
129 | }
130 |
131 | @Override
132 | public void setStatus(int sc) {
133 | this.originalResponse.setStatus(HttpResponseStatus.valueOf(sc));
134 | }
135 |
136 | @Override
137 | public void setStatus(int sc, String sm) {
138 | this.originalResponse.setStatus(new HttpResponseStatus(sc, sm));
139 | }
140 |
141 | @Override
142 | public String getContentType() {
143 | return HttpHeaders.getHeader(this.originalResponse,
144 | HttpHeaders.Names.CONTENT_TYPE);
145 | }
146 |
147 | @Override
148 | public void setContentType(String type) {
149 | HttpHeaders.setHeader(this.originalResponse,
150 | HttpHeaders.Names.CONTENT_TYPE, type);
151 | }
152 |
153 | @Override
154 | public void setContentLength(int len) {
155 | HttpHeaders.setContentLength(this.originalResponse, len);
156 | }
157 |
158 | @Override
159 | public boolean isCommitted() {
160 | return this.responseCommited;
161 | }
162 |
163 | @Override
164 | public void reset() {
165 | if (isCommitted())
166 | throw new IllegalStateException("Response already commited!");
167 |
168 | this.originalResponse.headers().clear();
169 | this.resetBuffer();
170 | }
171 |
172 | @Override
173 | public void resetBuffer() {
174 | if (isCommitted())
175 | throw new IllegalStateException("Response already commited!");
176 |
177 | this.outputStream.resetBuffer();
178 | }
179 |
180 | @Override
181 | public void flushBuffer() throws IOException {
182 | this.getWriter().flush();
183 | this.responseCommited = true;
184 | }
185 |
186 | @Override
187 | public int getBufferSize() {
188 | return this.outputStream.getBufferSize();
189 | }
190 |
191 | @Override
192 | public void setBufferSize(int size) {
193 | // we using always dynamic buffer for now
194 | }
195 |
196 | @Override
197 | public String encodeRedirectURL(String url) {
198 | return this.encodeURL(url);
199 | }
200 |
201 | @Override
202 | public String encodeRedirectUrl(String url) {
203 | return this.encodeURL(url);
204 | }
205 |
206 | @Override
207 | public String encodeURL(String url) {
208 | try {
209 | return URLEncoder.encode(url, getCharacterEncoding());
210 | } catch (UnsupportedEncodingException e) {
211 | throw new ServletBridgeRuntimeException("Error encoding url!", e);
212 | }
213 | }
214 |
215 | @Override
216 | public String encodeUrl(String url) {
217 | return this.encodeRedirectURL(url);
218 | }
219 |
220 | @Override
221 | public String getCharacterEncoding() {
222 | return HttpHeaders.getHeader(this.originalResponse,
223 | Names.CONTENT_ENCODING);
224 | }
225 |
226 | @Override
227 | public void setCharacterEncoding(String charset) {
228 | HttpHeaders.setHeader(this.originalResponse,
229 | Names.CONTENT_ENCODING, charset);
230 | }
231 |
232 | @Override
233 | public Locale getLocale() {
234 | return locale;
235 | }
236 |
237 | @Override
238 | public void setLocale(Locale loc) {
239 | this.locale = loc;
240 | }
241 | }
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/HttpSessionImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import net.javaforge.netty.servlet.bridge.util.Utils;
20 |
21 | import javax.servlet.ServletContext;
22 | import javax.servlet.http.HttpSession;
23 | import javax.servlet.http.HttpSessionBindingEvent;
24 | import javax.servlet.http.HttpSessionBindingListener;
25 | import javax.servlet.http.HttpSessionContext;
26 | import java.util.Enumeration;
27 | import java.util.Map;
28 | import java.util.concurrent.ConcurrentHashMap;
29 |
30 | @SuppressWarnings({"deprecation", "unchecked"})
31 | public class HttpSessionImpl implements HttpSession {
32 |
33 | public static final String SESSION_ID_KEY = "JSESSIONID";
34 |
35 | private String id;
36 |
37 | private long creationTime;
38 |
39 | private long lastAccessedTime;
40 |
41 | private int maxInactiveInterval = -1;
42 |
43 | private Map attributes;
44 |
45 | public HttpSessionImpl(String id) {
46 | this.id = id;
47 | this.creationTime = System.currentTimeMillis();
48 | this.lastAccessedTime = this.creationTime;
49 | }
50 |
51 | @Override
52 | public Object getAttribute(String name) {
53 | return attributes != null ? attributes.get(name) : null;
54 | }
55 |
56 | @Override
57 | public Enumeration getAttributeNames() {
58 | return Utils.enumerationFromKeys(attributes);
59 | }
60 |
61 | @Override
62 | public long getCreationTime() {
63 | return this.creationTime;
64 | }
65 |
66 | @Override
67 | public String getId() {
68 | return this.id;
69 | }
70 |
71 | @Override
72 | public long getLastAccessedTime() {
73 | return this.lastAccessedTime;
74 | }
75 |
76 | @Override
77 | public ServletContext getServletContext() {
78 | return ServletContextImpl.get();
79 | }
80 |
81 | @Override
82 | public HttpSessionContext getSessionContext() {
83 | throw new IllegalStateException(
84 | "As of Version 2.1, this method is deprecated and has no replacement.");
85 | }
86 |
87 | @Override
88 | public Object getValue(String name) {
89 | return getAttribute(name);
90 | }
91 |
92 | @Override
93 | public String[] getValueNames() {
94 | if (attributes == null)
95 | return null;
96 |
97 | return attributes.keySet().toArray(
98 | new String[attributes.keySet().size()]);
99 | }
100 |
101 | @Override
102 | public void invalidate() {
103 | if (attributes != null) {
104 | attributes.clear();
105 | }
106 | }
107 |
108 | @Override
109 | public void putValue(String name, Object value) {
110 | this.setAttribute(name, value);
111 | }
112 |
113 | @Override
114 | public void removeAttribute(String name) {
115 | if (attributes != null) {
116 | Object value = attributes.get(name);
117 | if (value != null && value instanceof HttpSessionBindingListener) {
118 | ((HttpSessionBindingListener) value)
119 | .valueUnbound(new HttpSessionBindingEvent(this, name,
120 | value));
121 | }
122 | attributes.remove(name);
123 | }
124 | }
125 |
126 | @Override
127 | public void removeValue(String name) {
128 | this.removeAttribute(name);
129 | }
130 |
131 | @Override
132 | public void setAttribute(String name, Object value) {
133 | if (attributes == null)
134 | attributes = new ConcurrentHashMap();
135 |
136 | attributes.put(name, value);
137 |
138 | if (value != null && value instanceof HttpSessionBindingListener) {
139 | ((HttpSessionBindingListener) value)
140 | .valueBound(new HttpSessionBindingEvent(this, name, value));
141 | }
142 |
143 | }
144 |
145 | @Override
146 | public int getMaxInactiveInterval() {
147 | return this.maxInactiveInterval;
148 | }
149 |
150 | @Override
151 | public void setMaxInactiveInterval(int interval) {
152 | this.maxInactiveInterval = interval;
153 |
154 | }
155 |
156 | public void touch() {
157 | this.lastAccessedTime = System.currentTimeMillis();
158 | }
159 |
160 | @Override
161 | public boolean isNew() {
162 | throw new IllegalStateException("Method 'isNew' not yet implemented!");
163 | }
164 |
165 | }
166 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/PrintWriterImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import java.io.OutputStream;
20 | import java.io.PrintWriter;
21 |
22 | public class PrintWriterImpl extends PrintWriter {
23 |
24 | private boolean flushed = false;
25 |
26 | public PrintWriterImpl(OutputStream out) {
27 | super(out);
28 | }
29 |
30 | @Override
31 | public void flush() {
32 | super.flush();
33 | this.flushed = true;
34 | }
35 |
36 | public boolean isFlushed() {
37 | return flushed;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/RequestDispatcherImpl.java:
--------------------------------------------------------------------------------
1 | package net.javaforge.netty.servlet.bridge.impl;
2 |
3 | import javax.servlet.RequestDispatcher;
4 | import javax.servlet.ServletException;
5 | import javax.servlet.ServletRequest;
6 | import javax.servlet.ServletResponse;
7 | import javax.servlet.http.HttpServlet;
8 | import javax.servlet.http.HttpServletResponse;
9 | import java.io.IOException;
10 |
11 | /**
12 | * Simple RequestDispatcher Implementation
13 | *
14 | * Created by xshao on 12/22/14.
15 | */
16 | public class RequestDispatcherImpl implements RequestDispatcher {
17 |
18 | /**
19 | * The servlet name for a named dispatcher.
20 | */
21 | private String name = null;
22 |
23 | /**
24 | * The servlet path for this RequestDispatcher.
25 | */
26 | private String servletPath = null;
27 |
28 |
29 | private HttpServlet httpServlet;
30 |
31 |
32 | public RequestDispatcherImpl(String servletName, String servletPath, HttpServlet servlet) {
33 | this.name = servletName;
34 | this.servletPath = servletPath;
35 | this.httpServlet = servlet;
36 | }
37 |
38 |
39 | @Override
40 | public void forward(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
41 | if (httpServlet != null) {
42 | //TODO Wrap
43 | httpServlet.service(servletRequest, servletResponse);
44 | } else {
45 | ((HttpServletResponse) servletResponse).sendError(HttpServletResponse.SC_NOT_FOUND);
46 | }
47 | }
48 |
49 | @Override
50 | public void include(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
51 | if (httpServlet != null) {
52 | //TODO Wrap
53 | httpServlet.service(servletRequest, servletResponse);
54 | } else {
55 | ((HttpServletResponse) servletResponse).sendError(HttpServletResponse.SC_NOT_FOUND);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/ServletBridgeWebapp.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import io.netty.channel.group.ChannelGroup;
20 | import net.javaforge.netty.servlet.bridge.config.FilterConfiguration;
21 | import net.javaforge.netty.servlet.bridge.config.ServletConfiguration;
22 | import net.javaforge.netty.servlet.bridge.config.ServletContextListenerConfiguration;
23 | import net.javaforge.netty.servlet.bridge.config.WebappConfiguration;
24 |
25 | import java.io.File;
26 | import java.util.Map;
27 |
28 | public class ServletBridgeWebapp {
29 |
30 | private static ServletBridgeWebapp instance;
31 |
32 | private WebappConfiguration webappConfig;
33 |
34 | private ChannelGroup sharedChannelGroup;
35 |
36 | public static ServletBridgeWebapp get() {
37 |
38 | if (instance == null)
39 | instance = new ServletBridgeWebapp();
40 |
41 | return instance;
42 | }
43 |
44 | private ServletBridgeWebapp() {
45 | }
46 |
47 | public void init(WebappConfiguration webapp, ChannelGroup sharedChannelGroup) {
48 | this.webappConfig = webapp;
49 | this.sharedChannelGroup = sharedChannelGroup;
50 | this.initServletContext();
51 | this.initContextListeners();
52 | this.initFilters();
53 | this.initServlets();
54 | }
55 |
56 | public void destroy() {
57 | this.destroyServlets();
58 | this.destroyFilters();
59 | this.destroyContextListeners();
60 | }
61 |
62 | private void initContextListeners() {
63 | if (webappConfig.getServletContextListenerConfigurations() != null) {
64 | for (ServletContextListenerConfiguration ctx : webappConfig
65 | .getServletContextListenerConfigurations()) {
66 | ctx.init();
67 | }
68 | }
69 | }
70 |
71 | private void destroyContextListeners() {
72 | if (webappConfig.getServletContextListenerConfigurations() != null) {
73 | for (ServletContextListenerConfiguration ctx : webappConfig
74 | .getServletContextListenerConfigurations()) {
75 | ctx.destroy();
76 | }
77 | }
78 | }
79 |
80 | private void destroyServlets() {
81 | if (webappConfig.getServletConfigurations() != null) {
82 | for (ServletConfiguration servlet : webappConfig
83 | .getServletConfigurations()) {
84 | servlet.destroy();
85 | }
86 | }
87 | }
88 |
89 | private void destroyFilters() {
90 | if (webappConfig.getFilterConfigurations() != null) {
91 | for (FilterConfiguration filter : webappConfig
92 | .getFilterConfigurations()) {
93 | filter.destroy();
94 | }
95 | }
96 | }
97 |
98 | protected void initServletContext() {
99 | ServletContextImpl ctx = ServletContextImpl.get();
100 | ctx.setServletContextName(this.webappConfig.getName());
101 | if (webappConfig.getContextParameters() != null) {
102 | for (Map.Entry entry : webappConfig
103 | .getContextParameters().entrySet()) {
104 | ctx.addInitParameter(entry.getKey(), entry.getValue());
105 | }
106 | }
107 | }
108 |
109 | protected void initFilters() {
110 | if (webappConfig.getFilterConfigurations() != null) {
111 | for (FilterConfiguration filter : webappConfig
112 | .getFilterConfigurations()) {
113 | filter.init();
114 | }
115 | }
116 | }
117 |
118 | protected void initServlets() {
119 | if (webappConfig.hasServletConfigurations()) {
120 | for (ServletConfiguration servlet : webappConfig
121 | .getServletConfigurations()) {
122 | servlet.init();
123 | }
124 | }
125 | }
126 |
127 | public FilterChainImpl initializeChain(String uri) {
128 | ServletConfiguration servletConfiguration = this.findServlet(uri);
129 | FilterChainImpl chain = new FilterChainImpl(servletConfiguration);
130 |
131 | if (this.webappConfig.hasFilterConfigurations()) {
132 | for (FilterConfiguration s : this.webappConfig
133 | .getFilterConfigurations()) {
134 | if (s.matchesUrlPattern(uri))
135 | chain.addFilterConfiguration(s);
136 | }
137 | }
138 |
139 | return chain;
140 | }
141 |
142 | private ServletConfiguration findServlet(String uri) {
143 |
144 | if (!this.webappConfig.hasServletConfigurations()) {
145 | return null;
146 | }
147 |
148 | for (ServletConfiguration s : this.webappConfig
149 | .getServletConfigurations()) {
150 | if (s.matchesUrlPattern(uri))
151 | return s;
152 | }
153 |
154 | return null;
155 | }
156 |
157 | public File getStaticResourcesFolder() {
158 | return this.webappConfig.getStaticResourcesFolder();
159 | }
160 |
161 | public WebappConfiguration getWebappConfig() {
162 | return webappConfig;
163 | }
164 |
165 | public ChannelGroup getSharedChannelGroup() {
166 | return sharedChannelGroup;
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/ServletConfigImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import javax.servlet.ServletConfig;
20 | import javax.servlet.ServletContext;
21 |
22 | public class ServletConfigImpl extends ConfigAdapter implements ServletConfig {
23 |
24 | public ServletConfigImpl(String servletName) {
25 | super(servletName);
26 | }
27 |
28 | @Override
29 | public String getServletName() {
30 | return super.getOwnerName();
31 | }
32 |
33 | @Override
34 | public ServletContext getServletContext() {
35 | return ServletContextImpl.get();
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/ServletContextImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import net.javaforge.netty.servlet.bridge.config.ServletConfiguration;
20 | import net.javaforge.netty.servlet.bridge.util.Utils;
21 | import org.slf4j.Logger;
22 | import org.slf4j.LoggerFactory;
23 |
24 | import javax.servlet.RequestDispatcher;
25 | import javax.servlet.Servlet;
26 | import javax.servlet.ServletContext;
27 | import javax.servlet.ServletException;
28 | import javax.servlet.http.HttpServlet;
29 | import java.io.File;
30 | import java.io.IOException;
31 | import java.io.InputStream;
32 | import java.net.MalformedURLException;
33 | import java.net.URL;
34 | import java.util.*;
35 |
36 | @SuppressWarnings("unchecked")
37 | public class ServletContextImpl extends ConfigAdapter implements ServletContext {
38 |
39 | private static final Logger log = LoggerFactory
40 | .getLogger(ServletContextImpl.class);
41 |
42 | private static ServletContextImpl instance;
43 |
44 | private Map attributes;
45 |
46 | private String servletContextName;
47 |
48 | public static ServletContextImpl get() {
49 | if (instance == null)
50 | instance = new ServletContextImpl();
51 |
52 | return instance;
53 | }
54 |
55 | private ServletContextImpl() {
56 | super("Netty Servlet Bridge");
57 | }
58 |
59 | @Override
60 | public Object getAttribute(String name) {
61 | return attributes != null ? attributes.get(name) : null;
62 | }
63 |
64 | @Override
65 | public Enumeration getAttributeNames() {
66 | return Utils.enumerationFromKeys(attributes);
67 | }
68 |
69 | @Override
70 | public String getContextPath() {
71 | return "";
72 | }
73 |
74 | @Override
75 | public int getMajorVersion() {
76 | return 2;
77 | }
78 |
79 | @Override
80 | public int getMinorVersion() {
81 | return 4;
82 | }
83 |
84 | @Override
85 | public URL getResource(String path) throws MalformedURLException {
86 | return ServletContextImpl.class.getResource(path);
87 | }
88 |
89 | @Override
90 | public InputStream getResourceAsStream(String path) {
91 | return ServletContextImpl.class.getResourceAsStream(path);
92 | }
93 |
94 | @Override
95 | public String getServerInfo() {
96 | return super.getOwnerName();
97 | }
98 |
99 | @Override
100 | public void log(String msg) {
101 | log.info(msg);
102 | }
103 |
104 | @Override
105 | public void log(Exception exception, String msg) {
106 | log.error(msg, exception);
107 | }
108 |
109 | @Override
110 | public void log(String message, Throwable throwable) {
111 | log.error(message, throwable);
112 | }
113 |
114 | @Override
115 | public void removeAttribute(String name) {
116 | if (this.attributes != null)
117 | this.attributes.remove(name);
118 | }
119 |
120 | @Override
121 | public void setAttribute(String name, Object object) {
122 | if (this.attributes == null)
123 | this.attributes = new HashMap();
124 |
125 | this.attributes.put(name, object);
126 | }
127 |
128 | @Override
129 | public String getServletContextName() {
130 | return this.servletContextName;
131 | }
132 |
133 | void setServletContextName(String servletContextName) {
134 | this.servletContextName = servletContextName;
135 | }
136 |
137 | @Override
138 | public Servlet getServlet(String name) throws ServletException {
139 | throw new IllegalStateException(
140 | "Deprecated as of Java Servlet API 2.1, with no direct replacement!");
141 | }
142 |
143 | @Override
144 | public Enumeration getServletNames() {
145 | throw new IllegalStateException(
146 | "Method 'getServletNames' deprecated as of Java Servlet API 2.0, with no replacement.");
147 | }
148 |
149 | @Override
150 | public Enumeration getServlets() {
151 | throw new IllegalStateException(
152 | "Method 'getServlets' deprecated as of Java Servlet API 2.0, with no replacement.");
153 | }
154 |
155 | @Override
156 | public ServletContext getContext(String uripath) {
157 | return this;
158 | }
159 |
160 | @Override
161 | public String getMimeType(String file) {
162 | return Utils.getMimeType(file);
163 |
164 | }
165 |
166 | @Override
167 | public Set getResourcePaths(String path) {
168 | throw new IllegalStateException(
169 | "Method 'getResourcePaths' not yet implemented!");
170 | }
171 |
172 | @Override
173 | public RequestDispatcher getNamedDispatcher(String name) {
174 | Collection colls = ServletBridgeWebapp.get().getWebappConfig().getServletConfigurations();
175 | HttpServlet servlet = null;
176 | for (ServletConfiguration configuration : colls) {
177 | if (configuration.getConfig().getServletName().equals(name)) {
178 | servlet = configuration.getHttpComponent();
179 | }
180 | }
181 |
182 | return new RequestDispatcherImpl(name, null, servlet);
183 | }
184 |
185 | @Override
186 | public String getRealPath(String path) {
187 | if ("/".equals(path)) {
188 | try {
189 | File file = File.createTempFile("netty-servlet-bridge", "");
190 | file.mkdirs();
191 | return file.getAbsolutePath();
192 | } catch (IOException e) {
193 | throw new IllegalStateException(
194 | "Method 'getRealPath' not yet implemented!");
195 | }
196 | } else {
197 | throw new IllegalStateException(
198 | "Method 'getRealPath' not yet implemented!");
199 | }
200 | }
201 |
202 | @Override
203 | public RequestDispatcher getRequestDispatcher(String path) {
204 | Collection colls = ServletBridgeWebapp.get().getWebappConfig().getServletConfigurations();
205 | HttpServlet servlet = null;
206 | String servletName = null;
207 | for (ServletConfiguration configuration : colls) {
208 | if (configuration.matchesUrlPattern(path)) {
209 | servlet = configuration.getHttpComponent();
210 | servletName = configuration.getHttpComponent().getServletName();
211 | }
212 | }
213 |
214 | return new RequestDispatcherImpl(servletName, path, servlet);
215 | }
216 |
217 | }
218 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/ServletInputStreamImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import io.netty.buffer.ByteBufInputStream;
20 | import io.netty.buffer.Unpooled;
21 | import io.netty.handler.codec.http.FullHttpRequest;
22 | import io.netty.handler.codec.http.HttpRequest;
23 |
24 | import javax.servlet.ServletInputStream;
25 | import java.io.IOException;
26 |
27 | public class ServletInputStreamImpl extends ServletInputStream {
28 |
29 | private HttpRequest request;
30 |
31 | private ByteBufInputStream in;
32 |
33 | public ServletInputStreamImpl(FullHttpRequest request) {
34 | this.request = request;
35 |
36 | this.in = new ByteBufInputStream(request.content());
37 | }
38 |
39 | public ServletInputStreamImpl(HttpRequest request) {
40 | this.request = request;
41 |
42 | this.in = new ByteBufInputStream(Unpooled.buffer(0));
43 | }
44 |
45 |
46 | @Override
47 | public int read() throws IOException {
48 | return this.in.read();
49 | }
50 |
51 | @Override
52 | public int read(byte[] buf) throws IOException {
53 | return this.in.read(buf);
54 | }
55 |
56 | @Override
57 | public int read(byte[] buf, int offset, int len) throws IOException {
58 | return this.in.read(buf, offset, len);
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/ServletOutputStreamImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 | import io.netty.buffer.ByteBufOutputStream;
20 | import io.netty.handler.codec.http.FullHttpResponse;
21 |
22 | import javax.servlet.ServletOutputStream;
23 | import java.io.IOException;
24 |
25 | public class ServletOutputStreamImpl extends ServletOutputStream {
26 |
27 | private FullHttpResponse response;
28 |
29 | private ByteBufOutputStream out;
30 |
31 | private boolean flushed = false;
32 |
33 | public ServletOutputStreamImpl(FullHttpResponse response) {
34 | this.response = response;
35 | this.out = new ByteBufOutputStream(response.content());
36 | }
37 |
38 | @Override
39 | public void write(int b) throws IOException {
40 | this.out.write(b);
41 | }
42 |
43 | @Override
44 | public void write(byte[] b) throws IOException {
45 | this.out.write(b);
46 | }
47 |
48 | @Override
49 | public void write(byte[] b, int offset, int len) throws IOException {
50 | this.out.write(b, offset, len);
51 | }
52 |
53 | @Override
54 | public void flush() throws IOException {
55 | // this.response.setContent(out.buffer());
56 | this.flushed = true;
57 | }
58 |
59 | public void resetBuffer() {
60 | this.out.buffer().clear();
61 | }
62 |
63 | public boolean isFlushed() {
64 | return flushed;
65 | }
66 |
67 | public int getBufferSize() {
68 | return this.out.buffer().capacity();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/impl/URIParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.impl;
18 |
19 |
20 | public class URIParser {
21 |
22 | private FilterChainImpl chain;
23 |
24 | private String servletPath;
25 |
26 | private String requestUri;
27 |
28 | private String pathInfo;
29 |
30 | private String queryString;
31 |
32 | public URIParser(FilterChainImpl chain) {
33 | this.chain = chain;
34 | }
35 |
36 | public void parse(String uri) {
37 |
38 | int indx = uri.indexOf('?');
39 | this.servletPath = this.chain.getServletConfiguration()
40 | .getMatchingUrlPattern(uri);
41 | if (!this.servletPath.startsWith("/"))
42 | this.servletPath = "/" + this.servletPath;
43 |
44 | if (indx != -1) {
45 | this.pathInfo = uri.substring(servletPath.length(), indx);
46 | this.queryString = uri.substring(indx + 1);
47 | this.requestUri = uri.substring(0, indx);
48 | } else {
49 | this.pathInfo = uri.substring(servletPath.length());
50 | this.requestUri = uri;
51 | }
52 |
53 | if (this.requestUri.endsWith("/"))
54 | this.requestUri.substring(0, this.requestUri.length() - 1);
55 |
56 | if (this.pathInfo.equals(""))
57 | this.pathInfo = null;
58 | else if (!this.pathInfo.startsWith("/"))
59 | this.pathInfo = "/" + this.pathInfo;
60 |
61 | }
62 |
63 | public String getServletPath() {
64 | return servletPath;
65 | }
66 |
67 | public String getQueryString() {
68 | return queryString;
69 | }
70 |
71 | public String getPathInfo() {
72 | return this.pathInfo;
73 | }
74 |
75 | public String getRequestUri() {
76 | return requestUri;
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/interceptor/ChannelInterceptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.interceptor;
18 |
19 | import io.netty.channel.ChannelHandlerContext;
20 | import io.netty.handler.codec.http.HttpRequest;
21 | import io.netty.handler.codec.http.HttpResponse;
22 | import net.javaforge.netty.servlet.bridge.ChannelThreadLocal;
23 | import net.javaforge.netty.servlet.bridge.ServletBridgeInterceptor;
24 |
25 | public class ChannelInterceptor implements ServletBridgeInterceptor {
26 |
27 | @Override
28 | public void onRequestFailed(ChannelHandlerContext ctx, Throwable e,
29 | HttpResponse response) {
30 | ChannelThreadLocal.unset();
31 | }
32 |
33 | @Override
34 | public void onRequestReceived(ChannelHandlerContext ctx, HttpRequest e) {
35 | ChannelThreadLocal.set(ctx.channel());
36 | }
37 |
38 | @Override
39 | public void onRequestSuccessed(ChannelHandlerContext ctx, HttpRequest e,
40 | HttpResponse response) {
41 | ChannelThreadLocal.unset();
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/interceptor/HttpSessionInterceptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.interceptor;
18 |
19 | import io.netty.channel.ChannelHandlerContext;
20 | import io.netty.handler.codec.http.*;
21 | import net.javaforge.netty.servlet.bridge.HttpSessionThreadLocal;
22 | import net.javaforge.netty.servlet.bridge.ServletBridgeInterceptor;
23 | import net.javaforge.netty.servlet.bridge.impl.HttpSessionImpl;
24 | import net.javaforge.netty.servlet.bridge.session.ServletBridgeHttpSessionStore;
25 | import net.javaforge.netty.servlet.bridge.util.Utils;
26 |
27 | import java.util.Collection;
28 |
29 | import static io.netty.handler.codec.http.HttpHeaders.Names.SET_COOKIE;
30 |
31 | public class HttpSessionInterceptor implements ServletBridgeInterceptor {
32 |
33 | private boolean sessionRequestedByCookie = false;
34 |
35 | public HttpSessionInterceptor(ServletBridgeHttpSessionStore sessionStore) {
36 | HttpSessionThreadLocal.setSessionStore(sessionStore);
37 | }
38 |
39 | @Override
40 | public void onRequestReceived(ChannelHandlerContext ctx, HttpRequest request) {
41 |
42 | HttpSessionThreadLocal.unset();
43 |
44 | Collection cookies = Utils.getCookies(
45 | HttpSessionImpl.SESSION_ID_KEY, request);
46 | if (cookies != null) {
47 | for (Cookie cookie : cookies) {
48 | String jsessionId = cookie.getValue();
49 | HttpSessionImpl s = HttpSessionThreadLocal.getSessionStore()
50 | .findSession(jsessionId);
51 | if (s != null) {
52 | HttpSessionThreadLocal.set(s);
53 | this.sessionRequestedByCookie = true;
54 | break;
55 | }
56 | }
57 | }
58 | }
59 |
60 | @Override
61 | public void onRequestSuccessed(ChannelHandlerContext ctx, HttpRequest request,
62 | HttpResponse response) {
63 |
64 | HttpSessionImpl s = HttpSessionThreadLocal.get();
65 | if (s != null && !this.sessionRequestedByCookie) {
66 | HttpHeaders.addHeader(response, SET_COOKIE, ServerCookieEncoder.encode(HttpSessionImpl.SESSION_ID_KEY, s.getId()));
67 | }
68 |
69 | }
70 |
71 | @Override
72 | public void onRequestFailed(ChannelHandlerContext ctx, Throwable e,
73 | HttpResponse response) {
74 | this.sessionRequestedByCookie = false;
75 | HttpSessionThreadLocal.unset();
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/session/DefaultServletBridgeHttpSessionStore.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.session;
18 |
19 | import net.javaforge.netty.servlet.bridge.impl.HttpSessionImpl;
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 |
23 | import java.util.Map;
24 | import java.util.UUID;
25 | import java.util.concurrent.ConcurrentHashMap;
26 |
27 | public class DefaultServletBridgeHttpSessionStore implements
28 | ServletBridgeHttpSessionStore {
29 |
30 | private static final Logger log = LoggerFactory
31 | .getLogger(DefaultServletBridgeHttpSessionStore.class);
32 |
33 | public static ConcurrentHashMap sessions = new ConcurrentHashMap();
34 |
35 | @Override
36 | public HttpSessionImpl createSession() {
37 | String sessionId = this.generateNewSessionId();
38 | log.debug("Creating new session with id {}", sessionId);
39 |
40 | HttpSessionImpl session = new HttpSessionImpl(sessionId);
41 | sessions.put(sessionId, session);
42 | return session;
43 | }
44 |
45 | @Override
46 | public void destroySession(String sessionId) {
47 | log.debug("Destroying session with id {}", sessionId);
48 | sessions.remove(sessionId);
49 | }
50 |
51 | @Override
52 | public HttpSessionImpl findSession(String sessionId) {
53 | if (sessionId == null)
54 | return null;
55 |
56 | return sessions.get(sessionId);
57 | }
58 |
59 | protected String generateNewSessionId() {
60 | return UUID.randomUUID().toString();
61 | }
62 |
63 | @Override
64 | public void destroyInactiveSessions() {
65 | for (Map.Entry entry : sessions.entrySet()) {
66 | HttpSessionImpl session = entry.getValue();
67 | if (session.getMaxInactiveInterval() < 0)
68 | continue;
69 |
70 | long currentMillis = System.currentTimeMillis();
71 |
72 | if (currentMillis - session.getLastAccessedTime() > session
73 | .getMaxInactiveInterval() * 1000) {
74 |
75 | destroySession(entry.getKey());
76 | }
77 | }
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/session/ServletBridgeHttpSessionStore.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.session;
18 |
19 | import net.javaforge.netty.servlet.bridge.impl.HttpSessionImpl;
20 |
21 | public interface ServletBridgeHttpSessionStore {
22 |
23 | HttpSessionImpl findSession(String sessionId);
24 |
25 | HttpSessionImpl createSession();
26 |
27 | void destroySession(String sessionId);
28 |
29 | void destroyInactiveSessions();
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/netty-servlet-bridge/src/main/java/net/javaforge/netty/servlet/bridge/util/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.servlet.bridge.util;
18 |
19 | import io.netty.handler.codec.http.Cookie;
20 | import io.netty.handler.codec.http.CookieDecoder;
21 | import io.netty.handler.codec.http.HttpRequest;
22 | import io.netty.handler.codec.http.HttpResponse;
23 | import net.javaforge.netty.servlet.bridge.ServletBridgeRuntimeException;
24 |
25 | import java.io.File;
26 | import java.io.UnsupportedEncodingException;
27 | import java.net.FileNameMap;
28 | import java.net.URLConnection;
29 | import java.net.URLDecoder;
30 | import java.util.*;
31 |
32 | import static io.netty.handler.codec.http.HttpHeaders.Names.COOKIE;
33 |
34 | public final class Utils {
35 |
36 | private Utils() {
37 | }
38 |
39 | public static final Enumeration emptyEnumeration() {
40 | return Collections.enumeration(Collections.emptySet());
41 | }
42 |
43 | public static final Enumeration enumeration(Collection collection) {
44 | if (collection == null)
45 | return emptyEnumeration();
46 |
47 | return Collections.enumeration(collection);
48 | }
49 |
50 | public static final Enumeration enumerationFromKeys(Map map) {
51 | if (map == null)
52 | return emptyEnumeration();
53 |
54 | return Collections.enumeration(map.keySet());
55 | }
56 |
57 | public static final Enumeration enumerationFromValues(Map, T> map) {
58 | if (map == null)
59 | return emptyEnumeration();
60 |
61 | return Collections.enumeration(map.values());
62 | }
63 |
64 | public static final T newInstance(Class clazz) {
65 |
66 | try {
67 | return clazz.newInstance();
68 | } catch (InstantiationException e) {
69 | throw new ServletBridgeRuntimeException(
70 | "Error instantiating class: " + clazz, e);
71 | } catch (IllegalAccessException e) {
72 | throw new ServletBridgeRuntimeException(
73 | "Error instantiating class: " + clazz, e);
74 | }
75 |
76 | }
77 |
78 | /**
79 | * Parse the character encoding from the specified content type header. If
80 | * the content type is null, or there is no explicit character encoding,
81 | * null
is returned.
82 | *
83 | * @param contentType
84 | * a content type header
85 | */
86 | public static final String getCharsetFromContentType(String contentType) {
87 |
88 | if (contentType == null) {
89 | return (null);
90 | }
91 | int start = contentType.indexOf("charset=");
92 | if (start < 0) {
93 | return (null);
94 | }
95 | String encoding = contentType.substring(start + 8);
96 | int end = encoding.indexOf(';');
97 | if (end >= 0) {
98 | encoding = encoding.substring(0, end);
99 | }
100 | encoding = encoding.trim();
101 | if ((encoding.length() > 2) && (encoding.startsWith("\""))
102 | && (encoding.endsWith("\""))) {
103 | encoding = encoding.substring(1, encoding.length() - 1);
104 | }
105 | return (encoding.trim());
106 |
107 | }
108 |
109 | public static final Collection getCookies(String name,
110 | HttpRequest request) {
111 | String cookieString = request.headers().get(COOKIE);
112 | if (cookieString != null) {
113 | List foundCookie = new ArrayList();
114 | Set cookies = CookieDecoder.decode(cookieString);
115 | for (Cookie cookie : cookies) {
116 | if (cookie.getName().equals(name))
117 | foundCookie.add(cookie);
118 | }
119 |
120 | return foundCookie;
121 | }
122 | return null;
123 | }
124 |
125 | public static final Collection getCookies(String name,
126 | HttpResponse response) {
127 | String cookieString = response.headers().get(COOKIE);
128 | if (cookieString != null) {
129 | List foundCookie = new ArrayList();
130 | Set cookies = CookieDecoder.decode(cookieString);
131 | for (Cookie cookie : cookies) {
132 | if (cookie.getName().equals(name))
133 | foundCookie.add(cookie);
134 | }
135 |
136 | return foundCookie;
137 | }
138 | return null;
139 | }
140 |
141 | public static final String getMimeType(String fileUrl) {
142 | FileNameMap fileNameMap = URLConnection.getFileNameMap();
143 | String type = fileNameMap.getContentTypeFor(fileUrl);
144 | return type;
145 | }
146 |
147 | public static final String sanitizeUri(String uri) {
148 | // Decode the path.
149 | try {
150 | uri = URLDecoder.decode(uri, "UTF-8");
151 | } catch (UnsupportedEncodingException e) {
152 | try {
153 | uri = URLDecoder.decode(uri, "ISO-8859-1");
154 | } catch (UnsupportedEncodingException e1) {
155 | throw new Error();
156 | }
157 | }
158 |
159 | // Convert file separators.
160 | uri = uri.replace('/', File.separatorChar);
161 |
162 | // Simplistic dumb security check.
163 | // You will have to do something serious in the production environment.
164 | if (uri.contains(File.separator + ".")
165 | || uri.contains("." + File.separator) || uri.startsWith(".")
166 | || uri.endsWith(".")) {
167 | return null;
168 | }
169 |
170 | return uri;
171 | }
172 |
173 | public static final Collection parseAcceptLanguageHeader(
174 | String acceptLanguageHeader) {
175 |
176 | if (acceptLanguageHeader == null)
177 | return null;
178 |
179 | List locales = new ArrayList();
180 |
181 | for (String str : acceptLanguageHeader.split(",")) {
182 | String[] arr = str.trim().replace("-", "_").split(";");
183 |
184 | // Parse the locale
185 | Locale locale = null;
186 | String[] l = arr[0].split("_");
187 | switch (l.length) {
188 | case 2:
189 | locale = new Locale(l[0], l[1]);
190 | break;
191 | case 3:
192 | locale = new Locale(l[0], l[1], l[2]);
193 | break;
194 | default:
195 | locale = new Locale(l[0]);
196 | break;
197 | }
198 |
199 | // Parse the q-value
200 | /*
201 | * Double q = 1.0D; for (String s : arr) { s = s.trim(); if
202 | * (s.startsWith("q=")) { q =
203 | * Double.parseDouble(s.substring(2).trim()); break; } }
204 | */
205 |
206 | locales.add(locale);
207 | }
208 |
209 | return locales;
210 |
211 | }
212 |
213 | }
214 |
--------------------------------------------------------------------------------
/vaadin-netty-example/pom.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 | 4.0.0
20 |
21 | net.javaforge.netty
22 | vaadin-netty-example
23 | 1.0-SNAPSHOT
24 | jar
25 |
26 | vaadin-netty-example
27 | http://maven.apache.org
28 |
29 |
30 | UTF-8
31 | 7.0.0
32 |
33 |
34 |
35 |
36 |
37 | net.javaforge.netty
38 | netty-servlet-bridge
39 | 1.0.0-SNAPSHOT
40 |
41 |
42 | com.vaadin
43 | vaadin-server
44 | ${vaadin.version}
45 |
46 |
47 | com.vaadin
48 | vaadin-theme-compiler
49 |
50 |
51 |
52 |
53 | com.vaadin
54 | vaadin-client-compiled
55 | ${vaadin.version}
56 |
57 |
58 | com.vaadin
59 | vaadin-themes
60 | ${vaadin.version}
61 |
62 |
63 | org.slf4j
64 | slf4j-simple
65 | 1.7.2
66 |
67 |
68 | junit
69 | junit
70 | 4.11
71 | test
72 |
73 |
74 |
75 |
76 |
77 |
78 | org.apache.maven.plugins
79 | maven-eclipse-plugin
80 | 2.9
81 |
82 | true
83 | true
84 |
85 |
86 |
87 | org.apache.maven.plugins
88 | maven-compiler-plugin
89 |
90 | 1.6
91 | 1.6
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/vaadin-netty-example/src/main/java/net/javaforge/netty/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty;
18 |
19 | import com.vaadin.server.VaadinServlet;
20 | import net.javaforge.netty.servlet.bridge.ServletBridgeChannelPipelineFactory;
21 | import net.javaforge.netty.servlet.bridge.config.ServletConfiguration;
22 | import net.javaforge.netty.servlet.bridge.config.WebappConfiguration;
23 | import net.javaforge.netty.vaadin.AddressbookUI;
24 | import org.jboss.netty.bootstrap.ServerBootstrap;
25 | import org.jboss.netty.channel.Channel;
26 | import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 |
30 | import java.net.InetSocketAddress;
31 | import java.util.concurrent.Executors;
32 |
33 | public class App {
34 |
35 | private static final Logger log = LoggerFactory.getLogger(App.class);
36 |
37 | public static void main(String[] args) {
38 |
39 | long start = System.currentTimeMillis();
40 |
41 | // Configure the server.
42 | final ServerBootstrap bootstrap = new ServerBootstrap(
43 | new NioServerSocketChannelFactory(Executors
44 | .newCachedThreadPool(), Executors.newCachedThreadPool()));
45 |
46 | WebappConfiguration webapp = new WebappConfiguration();
47 | webapp.addServletConfigurations(new ServletConfiguration(
48 | VaadinServlet.class, "/*").addInitParameter("UI",
49 | AddressbookUI.class.getName()));
50 |
51 | // Set up the event pipeline factory.
52 | final ServletBridgeChannelPipelineFactory servletBridge = new ServletBridgeChannelPipelineFactory(
53 | webapp);
54 | bootstrap.setPipelineFactory(servletBridge);
55 |
56 | // Bind and start to accept incoming connections.
57 | final Channel serverChannel = bootstrap
58 | .bind(new InetSocketAddress(8080));
59 |
60 | long end = System.currentTimeMillis();
61 | log.info(">>> Server started in {} ms .... <<< ", (end - start));
62 |
63 | Runtime.getRuntime().addShutdownHook(new Thread() {
64 |
65 | @Override
66 | public void run() {
67 | servletBridge.shutdown();
68 | serverChannel.close().awaitUninterruptibly();
69 | bootstrap.releaseExternalResources();
70 | }
71 | });
72 |
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/vaadin-netty-example/src/main/java/net/javaforge/netty/vaadin/AddressbookUI.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 by Maxim Kalina
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 |
17 | package net.javaforge.netty.vaadin;
18 |
19 | import com.vaadin.annotations.Title;
20 | import com.vaadin.data.Container.Filter;
21 | import com.vaadin.data.Item;
22 | import com.vaadin.data.Property;
23 | import com.vaadin.data.Property.ValueChangeEvent;
24 | import com.vaadin.data.fieldgroup.FieldGroup;
25 | import com.vaadin.data.util.IndexedContainer;
26 | import com.vaadin.event.FieldEvents;
27 | import com.vaadin.event.FieldEvents.BlurEvent;
28 | import com.vaadin.event.FieldEvents.TextChangeEvent;
29 | import com.vaadin.event.FieldEvents.TextChangeListener;
30 | import com.vaadin.server.VaadinRequest;
31 | import com.vaadin.ui.AbstractTextField.TextChangeEventMode;
32 | import com.vaadin.ui.*;
33 | import com.vaadin.ui.Button.ClickEvent;
34 | import com.vaadin.ui.Button.ClickListener;
35 |
36 | /*
37 | * UI class is the starting point for your app. You may deploy it with VaadinServlet
38 | * or VaadinPortlet by giving your UI class name a parameter. When you browse to your
39 | * app a web page showing your UI is automatically generated. Or you may choose to
40 | * embed your UI to an existing web page.
41 | */
42 | @Title("Addressbook")
43 | public class AddressbookUI extends UI {
44 |
45 | private static final long serialVersionUID = 1L;
46 |
47 | /* User interface components are stored in session. */
48 | private Table contactList = new Table();
49 | private TextField searchField = new TextField();
50 | private Button addNewContactButton = new Button("New");
51 | private Button removeContactButton = new Button("Remove this contact");
52 | private FormLayout editorLayout = new FormLayout();
53 | private FieldGroup editorFields = new FieldGroup();
54 |
55 | private static final String FNAME = "First Name";
56 | private static final String LNAME = "Last Name";
57 | private static final String COMPANY = "Company";
58 | private static final String[] fieldNames = new String[]{FNAME, LNAME,
59 | COMPANY, "Mobile Phone", "Work Phone", "Home Phone", "Work Email",
60 | "Home Email", "Street", "City", "Zip", "State", "Country"};
61 |
62 | /*
63 | * Any component can be bound to an external data source. This example uses
64 | * just a dummy in-memory list, but there are many more practical
65 | * implementations.
66 | */
67 | IndexedContainer contactContainer = createDummyDatasource();
68 |
69 | /*
70 | * After UI class is created, init() is executed. You should build and wire
71 | * up your user interface here.
72 | */
73 | protected void init(VaadinRequest request) {
74 | initLayout();
75 | initContactList();
76 | initEditor();
77 | initSearch();
78 | initAddRemoveButtons();
79 | }
80 |
81 | /*
82 | * In this example layouts are programmed in Java. You may choose use a
83 | * visual editor, CSS or HTML templates for layout instead.
84 | */
85 | private void initLayout() {
86 |
87 | /* Root of the user interface component tree is set */
88 | HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
89 | setContent(splitPanel);
90 |
91 | /* Build the component tree */
92 | VerticalLayout leftLayout = new VerticalLayout();
93 | splitPanel.addComponent(leftLayout);
94 | splitPanel.addComponent(editorLayout);
95 | leftLayout.addComponent(contactList);
96 | HorizontalLayout bottomLeftLayout = new HorizontalLayout();
97 | leftLayout.addComponent(bottomLeftLayout);
98 | bottomLeftLayout.addComponent(searchField);
99 | bottomLeftLayout.addComponent(addNewContactButton);
100 |
101 | /* Set the contents in the left of the split panel to use all the space */
102 | leftLayout.setSizeFull();
103 |
104 | /*
105 | * On the left side, expand the size of the contactList so that it uses
106 | * all the space left after from bottomLeftLayout
107 | */
108 | leftLayout.setExpandRatio(contactList, 1);
109 | contactList.setSizeFull();
110 |
111 | /*
112 | * In the bottomLeftLayout, searchField takes all the width there is
113 | * after adding addNewContactButton. The height of the layout is defined
114 | * by the tallest component.
115 | */
116 | bottomLeftLayout.setWidth("100%");
117 | searchField.setWidth("100%");
118 | bottomLeftLayout.setExpandRatio(searchField, 1);
119 |
120 | /* Put a little margin around the fields in the right side editor */
121 | editorLayout.setMargin(true);
122 | editorLayout.setVisible(false);
123 | }
124 |
125 | private void initEditor() {
126 |
127 | editorLayout.addComponent(removeContactButton);
128 |
129 | /* User interface can be created dynamically to reflect underlying data. */
130 | for (String fieldName : fieldNames) {
131 | final TextField field = new TextField(fieldName);
132 | editorLayout.addComponent(field);
133 | field.setWidth("100%");
134 |
135 | /*
136 | * We use a FieldGroup to connect multiple components to a data
137 | * source at once.
138 | */
139 | editorFields.bind(field, fieldName);
140 |
141 | field.addBlurListener(new FieldEvents.BlurListener() {
142 | private static final long serialVersionUID = 1L;
143 |
144 | @Override
145 | public void blur(BlurEvent event) {
146 | field.commit();
147 | }
148 | });
149 |
150 | }
151 |
152 | /*
153 | * Data can be buffered in the user interface. When doing so, commit()
154 | * writes the changes to the data source. Here we choose to write the
155 | * changes automatically without calling commit().
156 | */
157 |
158 | // editorFields.setBuffered(false);
159 | }
160 |
161 | private void initSearch() {
162 |
163 | /*
164 | * We want to show a subtle prompt in the search field. We could also
165 | * set a caption that would be shown above the field or description to
166 | * be shown in a tooltip.
167 | */
168 | searchField.setInputPrompt("Search contacts");
169 |
170 | /*
171 | * Granularity for sending events over the wire can be controlled. By
172 | * default simple changes like writing a text in TextField are sent to
173 | * server with the next Ajax call. You can set your component to be
174 | * immediate to send the changes to server immediately after focus
175 | * leaves the field. Here we choose to send the text over the wire as
176 | * soon as user stops writing for a moment.
177 | */
178 | searchField.setTextChangeEventMode(TextChangeEventMode.LAZY);
179 |
180 | /*
181 | * When the event happens, we handle it in the anonymous inner class.
182 | * You may choose to use separate controllers (in MVC) or presenters (in
183 | * MVP) instead. In the end, the preferred application architecture is
184 | * up to you.
185 | */
186 | searchField.addTextChangeListener(new TextChangeListener() {
187 | private static final long serialVersionUID = 1L;
188 |
189 | public void textChange(final TextChangeEvent event) {
190 |
191 | /* Reset the filter for the contactContainer. */
192 | contactContainer.removeAllContainerFilters();
193 | contactContainer.addContainerFilter(new ContactFilter(event
194 | .getText()));
195 | }
196 | });
197 | }
198 |
199 | /*
200 | * A custom filter for searching names and companies in the
201 | * contactContainer.
202 | */
203 | private class ContactFilter implements Filter {
204 | private static final long serialVersionUID = 1L;
205 | private String needle;
206 |
207 | public ContactFilter(String needle) {
208 | this.needle = needle.toLowerCase();
209 | }
210 |
211 | public boolean passesFilter(Object itemId, Item item) {
212 | String haystack = ("" + item.getItemProperty(FNAME).getValue()
213 | + item.getItemProperty(LNAME).getValue() + item
214 | .getItemProperty(COMPANY).getValue()).toLowerCase();
215 | return haystack.contains(needle);
216 | }
217 |
218 | public boolean appliesToProperty(Object id) {
219 | return true;
220 | }
221 | }
222 |
223 | private void initAddRemoveButtons() {
224 | addNewContactButton.addClickListener(new ClickListener() {
225 | private static final long serialVersionUID = 1L;
226 |
227 | @SuppressWarnings("unchecked")
228 | public void buttonClick(ClickEvent event) {
229 |
230 | /*
231 | * Rows in the Container data model are called Item. Here we add
232 | * a new row in the beginning of the list.
233 | */
234 | contactContainer.removeAllContainerFilters();
235 | Object contactId = contactContainer.addItemAt(0);
236 |
237 | /*
238 | * Each Item has a set of Properties that hold values. Here we
239 | * set a couple of those.
240 | */
241 | contactList.getContainerProperty(contactId, FNAME).setValue(
242 | "New");
243 | contactList.getContainerProperty(contactId, LNAME).setValue(
244 | "Contact");
245 |
246 | /* Lets choose the newly created contact to edit it. */
247 | contactList.select(contactId);
248 | }
249 | });
250 |
251 | removeContactButton.addClickListener(new ClickListener() {
252 | private static final long serialVersionUID = 1L;
253 |
254 | public void buttonClick(ClickEvent event) {
255 | Object contactId = contactList.getValue();
256 | contactList.removeItem(contactId);
257 | }
258 | });
259 | }
260 |
261 | private void initContactList() {
262 | contactList.setContainerDataSource(contactContainer);
263 | contactList.setVisibleColumns(new String[]{FNAME, LNAME, COMPANY});
264 | contactList.setSelectable(true);
265 | contactList.setImmediate(true);
266 |
267 | contactList.addValueChangeListener(new Property.ValueChangeListener() {
268 | private static final long serialVersionUID = 1L;
269 |
270 | public void valueChange(ValueChangeEvent event) {
271 | Object contactId = contactList.getValue();
272 |
273 | /*
274 | * When a contact is selected from the list, we want to show
275 | * that in our editor on the right. This is nicely done by the
276 | * FieldGroup that binds all the fields to the corresponding
277 | * Properties in our contact at once.
278 | */
279 | if (contactId != null)
280 | editorFields.setItemDataSource(contactList
281 | .getItem(contactId));
282 |
283 | editorLayout.setVisible(contactId != null);
284 | }
285 | });
286 | }
287 |
288 | /*
289 | * Generate some in-memory example data to play with. In a real application
290 | * we could be using SQLContainer, JPAContainer or some other to persist the
291 | * data.
292 | */
293 | @SuppressWarnings("unchecked")
294 | private static IndexedContainer createDummyDatasource() {
295 | IndexedContainer ic = new IndexedContainer();
296 |
297 | for (String p : fieldNames) {
298 | ic.addContainerProperty(p, String.class, "");
299 | }
300 |
301 | /* Create dummy data by randomly combining first and last names */
302 | String[] fnames = {"Peter", "Alice", "Joshua", "Mike", "Olivia",
303 | "Nina", "Alex", "Rita", "Dan", "Umberto", "Henrik", "Rene",
304 | "Lisa", "Marge"};
305 | String[] lnames = {"Smith", "Gordon", "Simpson", "Brown", "Clavel",
306 | "Simons", "Verne", "Scott", "Allison", "Gates", "Rowling",
307 | "Barks", "Ross", "Schneider", "Tate"};
308 | for (int i = 0; i < 1000; i++) {
309 | Object id = ic.addItem();
310 | ic.getContainerProperty(id, FNAME).setValue(
311 | fnames[(int) (fnames.length * Math.random())]);
312 | ic.getContainerProperty(id, LNAME).setValue(
313 | lnames[(int) (lnames.length * Math.random())]);
314 | }
315 |
316 | return ic;
317 | }
318 |
319 | }
320 |
--------------------------------------------------------------------------------