Thank you Romain! :) On Sun, Dec 28, 2014 at 11:43 AM, <[email protected]> wrote:
> Repository: tomee > Updated Branches: > refs/heads/develop 2a9630a02 -> ce3ee00b9 > > > missing files > > > Project: http://git-wip-us.apache.org/repos/asf/tomee/repo > Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/ce3ee00b > Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/ce3ee00b > Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/ce3ee00b > > Branch: refs/heads/develop > Commit: ce3ee00b9cafc4cf73ecf57070ab27aa3f611b37 > Parents: 2a9630a > Author: Romain Manni-Bucau <[email protected]> > Authored: Sun Dec 28 12:42:36 2014 +0100 > Committer: Romain Manni-Bucau <[email protected]> > Committed: Sun Dec 28 12:42:36 2014 +0100 > > ---------------------------------------------------------------------- > .../openejb/testing/ContainerProperties.java | 37 +++ > .../AppComposerClassConfigurationTest.java | 37 +++ > ...ghtweightWebAppBuilderListenerExtractor.java | 62 ++++ > .../server/httpd/OpenEJBAsyncContext.java | 320 +++++++++++++++++++ > .../openejb/server/httpd/AsyncHttpTest.java | 171 ++++++++++ > 5 files changed, 627 insertions(+) > ---------------------------------------------------------------------- > > > > http://git-wip-us.apache.org/repos/asf/tomee/blob/ce3ee00b/container/openejb-core/src/main/java/org/apache/openejb/testing/ContainerProperties.java > ---------------------------------------------------------------------- > diff --git > a/container/openejb-core/src/main/java/org/apache/openejb/testing/ContainerProperties.java > b/container/openejb-core/src/main/java/org/apache/openejb/testing/ContainerProperties.java > new file mode 100644 > index 0000000..8284bdf > --- /dev/null > +++ > b/container/openejb-core/src/main/java/org/apache/openejb/testing/ContainerProperties.java > @@ -0,0 +1,37 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You under the Apache License, Version 2.0 > + * (the "License"); you may not use this file except in compliance with > + * the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +package org.apache.openejb.testing; > + > +import java.lang.annotation.ElementType; > +import java.lang.annotation.Retention; > +import java.lang.annotation.RetentionPolicy; > +import java.lang.annotation.Target; > + > +@Target(ElementType.TYPE) > +@Retention(RetentionPolicy.RUNTIME) > +public @interface ContainerProperties { > + Property[] value(); > + > + @Target(ElementType.PARAMETER) // TODO: method > + @Retention(RetentionPolicy.RUNTIME) > + public @interface Property { > + String IGNORED = "__not__set__so__ignored"; > + > + String name(); > + String value() default IGNORED; > + } > +} > > > http://git-wip-us.apache.org/repos/asf/tomee/blob/ce3ee00b/container/openejb-core/src/test/java/org/apache/openejb/testing/AppComposerClassConfigurationTest.java > ---------------------------------------------------------------------- > diff --git > a/container/openejb-core/src/test/java/org/apache/openejb/testing/AppComposerClassConfigurationTest.java > b/container/openejb-core/src/test/java/org/apache/openejb/testing/AppComposerClassConfigurationTest.java > new file mode 100644 > index 0000000..f324536 > --- /dev/null > +++ > b/container/openejb-core/src/test/java/org/apache/openejb/testing/AppComposerClassConfigurationTest.java > @@ -0,0 +1,37 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You under the Apache License, Version 2.0 > + * (the "License"); you may not use this file except in compliance with > + * the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +package org.apache.openejb.testing; > + > +import org.apache.openejb.junit.ApplicationComposerRule; > +import org.apache.openejb.loader.SystemInstance; > +import org.junit.Rule; > +import org.junit.Test; > + > +import static org.junit.Assert.assertEquals; > + > +@ContainerProperties(@ContainerProperties.Property(name = > "AppComposerClassConfigurationTest.test", value = "expected result")) > +@Classes(context = "app") > +public class AppComposerClassConfigurationTest { > + @Rule > + public final ApplicationComposerRule rule = new > ApplicationComposerRule(this); > + > + @Test > + public void run() { > + assertEquals("expected result", > SystemInstance.get().getProperty("AppComposerClassConfigurationTest.test")); > + assertEquals("expected result", > System.getProperty("AppComposerClassConfigurationTest.test")); > + } > +} > > > http://git-wip-us.apache.org/repos/asf/tomee/blob/ce3ee00b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/LightweightWebAppBuilderListenerExtractor.java > ---------------------------------------------------------------------- > diff --git > a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/LightweightWebAppBuilderListenerExtractor.java > b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/LightweightWebAppBuilderListenerExtractor.java > new file mode 100644 > index 0000000..5dddd47 > --- /dev/null > +++ > b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/LightweightWebAppBuilderListenerExtractor.java > @@ -0,0 +1,62 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You under the Apache License, Version 2.0 > + * (the "License"); you may not use this file except in compliance with > + * the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +package org.apache.openejb.server.httpd; > + > +import org.apache.openejb.AppContext; > +import org.apache.openejb.assembler.classic.WebAppBuilder; > +import org.apache.openejb.core.WebContext; > +import org.apache.openejb.loader.SystemInstance; > +import org.apache.openejb.spi.ContainerSystem; > +import org.apache.openejb.web.LightweightWebAppBuilder; > + > +import java.util.ArrayList; > +import java.util.Collection; > +import java.util.Collections; > + > +// could be optimized since we could bind to the request the listeners in > org.apache.openejb.server.httpd.OpenEJBHttpRegistry.ClassLoaderHttpListener.onMessage() > +// but ok for now since that's fully for the embedded mode > +public final class LightweightWebAppBuilderListenerExtractor { > + public static <T> Collection<T> findByTypeForContext(final String > context, final Class<T> type) { > + final WebAppBuilder builder = > SystemInstance.get().getComponent(WebAppBuilder.class); > + if (!LightweightWebAppBuilder.class.isInstance(builder)) { > + return Collections.emptyList(); > + } > + > + for (final AppContext app : > SystemInstance.get().getComponent(ContainerSystem.class).getAppContexts()) { > + for (final WebContext web : app.getWebContexts()) { > + if (web.getContextRoot().replace("/", > "").equals(context.replace("/", ""))) { > + final Collection<Object> potentials = > LightweightWebAppBuilder.class.cast(builder).listenersFor(web.getContextRoot()); > + if (potentials == null) { > + return Collections.emptyList(); > + } > + final Collection<T> filtered = new > ArrayList<>(potentials.size()); > + for (final Object o : potentials) { > + if (type.isInstance(o)) { > + filtered.add(type.cast(o)); > + } > + } > + return filtered; > + } > + } > + } > + return Collections.emptyList(); > + } > + > + private LightweightWebAppBuilderListenerExtractor() { > + // no-op > + } > +} > > > http://git-wip-us.apache.org/repos/asf/tomee/blob/ce3ee00b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/OpenEJBAsyncContext.java > ---------------------------------------------------------------------- > diff --git > a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/OpenEJBAsyncContext.java > b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/OpenEJBAsyncContext.java > new file mode 100644 > index 0000000..bdd3b4e > --- /dev/null > +++ > b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/OpenEJBAsyncContext.java > @@ -0,0 +1,320 @@ > +/** > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You under the Apache License, Version 2.0 > + * (the "License"); you may not use this file except in compliance with > + * the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +package org.apache.openejb.server.httpd; > + > +import org.apache.openejb.AppContext; > +import org.apache.openejb.OpenEJBRuntimeException; > +import org.apache.openejb.core.WebContext; > +import org.apache.openejb.loader.SystemInstance; > +import org.apache.openejb.spi.ContainerSystem; > +import org.apache.openejb.util.DaemonThreadFactory; > + > +import javax.servlet.AsyncContext; > +import javax.servlet.AsyncEvent; > +import javax.servlet.AsyncListener; > +import javax.servlet.ServletContext; > +import javax.servlet.ServletException; > +import javax.servlet.ServletRequest; > +import javax.servlet.ServletResponse; > +import javax.servlet.http.HttpServletRequest; > +import javax.servlet.http.HttpServletResponse; > +import java.io.IOException; > +import java.net.HttpURLConnection; > +import java.net.Socket; > +import java.util.ArrayList; > +import java.util.List; > +import java.util.Set; > +import java.util.concurrent.CopyOnWriteArraySet; > +import java.util.concurrent.Executors; > +import java.util.concurrent.ScheduledExecutorService; > +import java.util.concurrent.TimeUnit; > + > +// stupid impl, ~ mock. it handles itself eviction to avoid to have it > always started which is not the common case > +public class OpenEJBAsyncContext implements AsyncContext { > + private static final Set<OpenEJBAsyncContext> INITIALIZED = new > CopyOnWriteArraySet<>(); > + private static volatile ScheduledExecutorService es; > + > + public static void destroy() { > + if (es == null) { > + return; > + } > + es.shutdownNow(); > + for (final OpenEJBAsyncContext ctx : new > ArrayList<>(INITIALIZED)) { > + if (ctx.lastTouch + ctx.getTimeout() < > System.currentTimeMillis()) { > + for (final AsyncListener listener : ctx.listeners) { > + try { > + listener.onTimeout(ctx.event); > + } catch (final IOException t) { > + throw new OpenEJBRuntimeException(t); > + } > + } > + ctx.complete(); > + } > + } > + INITIALIZED.clear(); > + } > + > + public static void init() { > + if > (!"true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.http.async.eviction", > "true"))) { > + return; > + } > + es = Executors.newScheduledThreadPool(1, new > DaemonThreadFactory(OpenEJBAsyncContext.class)); > + es.scheduleWithFixedDelay(new Runnable() { > + @Override > + public void run() { > + for (final OpenEJBAsyncContext ctx : new > ArrayList<>(INITIALIZED)) { > + if (ctx.lastTouch + ctx.getTimeout() < > System.currentTimeMillis()) { > + INITIALIZED.remove(ctx); > + for (final AsyncListener listener : > ctx.listeners) { > + try { > + listener.onTimeout(ctx.event); > + } catch (final IOException t) { > + throw new OpenEJBRuntimeException(t); > + } > + } > + ctx.complete(); > + } > + } > + } > + }, 1, 1, TimeUnit.MINUTES); > + } > + > + private final List<AsyncListener> listeners = new ArrayList<>(); > + private final ServletResponse response; > + private final HttpRequestImpl request; > + private final Socket socket; > + private final AsyncEvent event; > + private WebContext context = null; > + private volatile boolean started = false; > + private volatile boolean committed = false; > + private long timeout = 30000; > + private long lastTouch = System.currentTimeMillis(); > + > + public OpenEJBAsyncContext(final HttpRequestImpl request, final > ServletResponse response, final String contextPath) { > + if (es == null) { > + synchronized (OpenEJBAsyncContext.class) { // we don't care > since impl is not really thread safe, just here for testing > + if (es == null) { > + init(); > + } > + } > + } > + > + this.request = request; > + if (contextPath != null) { > + for (final AppContext app : > SystemInstance.get().getComponent(ContainerSystem.class).getAppContexts()) { > + for (final WebContext web : app.getWebContexts()) { > + if (web.getContextRoot().replace("/", > "").equals(contextPath.replace("/", ""))) { > + this.context = web; > + break; > + } > + } > + } > + } > + this.response = response; > + this.socket = > Socket.class.cast(request.getAttribute("openejb_socket")); > + this.event = new AsyncEvent(this, request, response); > + INITIALIZED.add(this); > + } > + > + @Override > + public void complete() { > + for (final AsyncListener listener : listeners) { > + try { > + listener.onComplete(event); > + } catch (final IOException t) { > + throw new OpenEJBRuntimeException(t); > + } > + } > + > + commit(); > + } > + > + private void onError(final Throwable ignored) { > + for (final AsyncListener listener : listeners) { > + try { > + listener.onError(event); > + } catch (final IOException t) { > + throw new OpenEJBRuntimeException(t); > + } > + } > + try { > + > HttpServletResponse.class.cast(response).sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); > + commit(); > + } catch (final IOException e) { > + // no-op > + } > + } > + > + private void commit() { > + if (committed) { // avoid to commit it twice on errors (often a > listener will do it, we just force it in case of) > + return; > + } > + committed = true; > + if (HttpResponseImpl.class.isInstance(response) && socket != > null) { > + try { > + > HttpResponseImpl.class.cast(response).writeMessage(socket.getOutputStream(), > false); > + } catch (final IOException e) { > + // no-op > + } > + } // else TODO > + > + if (socket != null) { > + try { > + socket.getInputStream().close(); > + } catch (final IOException e) { > + // no-op > + } > + try { > + socket.getOutputStream().close(); > + } catch (final IOException e) { > + // no-op > + } > + try { > + socket.close(); > + } catch (final IOException e) { > + // no-op > + } > + } > + } > + > + @Override > + public void dispatch() { > + String path; > + final String pathInfo; > + ServletRequest servletRequest = getRequest(); > + if (servletRequest instanceof HttpServletRequest) { > + HttpServletRequest sr = (HttpServletRequest) servletRequest; > + path = sr.getServletPath(); > + pathInfo = sr.getPathInfo(); > + } else { > + path = request.getServletPath(); > + pathInfo = request.getPathInfo(); > + } > + if (pathInfo != null) { > + path += pathInfo; > + } > + dispatch(path); > + } > + > + @Override > + public void dispatch(final String path) { > + dispatch(request.getServletContext(), path); > + } > + > + @Override > + public void dispatch(final ServletContext context, final String path) > { > + final HttpListenerRegistry registry = > SystemInstance.get().getComponent(HttpListenerRegistry.class); > + try { > + final String contextPath = > this.context.getContextRoot().startsWith("/") ? > this.context.getContextRoot() : ('/' + this.context.getContextRoot()); > + final HttpRequestImpl req = new > HttpRequestImpl(request.getSocketURI()) { > + @Override > + public String getContextPath() { > + return contextPath; > + } > + > + @Override > + public String getServletPath() { > + return path; > + } > + > + @Override > + public String getRequestURI() { > + return contextPath + path; > + } > + }; > + registry.onMessage(req, > HttpResponse.class.isInstance(response) ? HttpResponse.class.cast(response) > : new ServletResponseAdapter(HttpServletResponse.class.cast(response))); > + complete(); > + } catch (final Exception e) { > + onError(e); > + } > + } > + > + @Override > + public ServletRequest getRequest() { > + return request; > + } > + > + @Override > + public ServletResponse getResponse() { > + if (response == null) { > + throw new IllegalStateException("no response"); > + } > + return response; > + } > + > + @Override > + public void start(final Runnable run) { > + internalStartAsync(); > + // TODO: another thread > + run.run(); > + } > + > + public void internalStartAsync() { > + started = true; > + for (final AsyncListener listener : listeners) { > + try { > + listener.onStartAsync(event); > + } catch (final IOException t) { > + throw new OpenEJBRuntimeException(t); > + } > + } > + } > + > + @Override > + public void addListener(final AsyncListener listener) { > + listeners.add(listener); > + if (started) { > + try { > + listener.onStartAsync(event); > + } catch (final IOException e) { > + throw new OpenEJBRuntimeException(e); > + } > + } > + } > + > + @Override > + public void addListener(final AsyncListener listener, > + final ServletRequest servletRequest, > + final ServletResponse servletResponse) { > + addListener(listener); > + } > + > + @Override > + public <T extends AsyncListener> T createListener(final Class<T> > clazz) > + throws ServletException { > + try { > + return (T) context.inject(clazz.newInstance()); > + } catch (final Exception e) { > + throw new ServletException(e); > + } > + } > + > + @Override > + public boolean hasOriginalRequestAndResponse() { > + return true; > + } > + > + @Override > + public long getTimeout() { > + return timeout; > + } > + > + @Override > + public void setTimeout(long timeout) { > + this.timeout = timeout; > + } > +} > > > http://git-wip-us.apache.org/repos/asf/tomee/blob/ce3ee00b/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/AsyncHttpTest.java > ---------------------------------------------------------------------- > diff --git > a/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/AsyncHttpTest.java > b/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/AsyncHttpTest.java > new file mode 100644 > index 0000000..41c8117 > --- /dev/null > +++ > b/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/AsyncHttpTest.java > @@ -0,0 +1,171 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You under the Apache License, Version 2.0 > + * (the "License"); you may not use this file except in compliance with > + * the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +package org.apache.openejb.server.httpd; > + > +import org.apache.openejb.junit.ApplicationComposerRule; > +import org.apache.openejb.loader.IO; > +import org.apache.openejb.testing.Classes; > +import org.apache.openejb.testing.ContainerProperties; > +import org.apache.openejb.testing.EnableServices; > +import org.apache.openejb.testing.RandomPort; > +import org.junit.Rule; > +import org.junit.Test; > + > +import javax.inject.Inject; > +import javax.servlet.AsyncContext; > +import javax.servlet.AsyncEvent; > +import javax.servlet.AsyncListener; > +import javax.servlet.ServletException; > +import javax.servlet.annotation.WebServlet; > +import javax.servlet.http.HttpServlet; > +import javax.servlet.http.HttpServletRequest; > +import javax.servlet.http.HttpServletResponse; > +import java.io.IOException; > +import java.net.URL; > +import java.util.concurrent.ExecutorService; > +import java.util.concurrent.Executors; > + > +import static org.junit.Assert.assertEquals; > +import static org.junit.Assert.assertTrue; > + > +@EnableServices("http") > +@Classes(cdi = true, innerClassesAsBean = true) > +@ContainerProperties(@ContainerProperties.Property(name = > "httpejbd.useJetty", value = "fase")) > +public class AsyncHttpTest { > + @Rule > + public final ApplicationComposerRule container = new > ApplicationComposerRule(this); > + > + @RandomPort("http") > + private URL context; > + > + @Test > + public void async() throws IOException { > + SimpleAsyncListener.started = false; > + assertEquals("OK", IO.slurp(new URL(context.toExternalForm() + > "openejb/AsyncServlet"))); > + assertTrue(SimpleAsyncListener.started); > + } > + > + @Test > + public void asyncDispatch() throws IOException { > + assertEquals("OK2", IO.slurp(new URL(context.toExternalForm() + > "openejb/DispatchAsyncServlet"))); > + } > + > + @WebServlet(name = "AsyncServlet", urlPatterns = "/AsyncServlet", > asyncSupported = true) > + public static class AsyncServlet extends HttpServlet { > + private ExecutorService executorService; > + > + @Override > + public void init() throws ServletException { > + executorService = Executors.newSingleThreadExecutor(); > + } > + > + @Override > + protected void service(final HttpServletRequest req, final > HttpServletResponse resp) throws ServletException, IOException { > + final AsyncContext actx = req.startAsync(); > + > actx.addListener(actx.createListener(SimpleAsyncListener.class)); > + resp.setContentType("text/plain"); > + executorService.execute(new AsyncHandler(actx)); > + } > + > + @Override > + public void destroy() { > + executorService.shutdownNow(); > + } > + } > + > + @WebServlet(name = "DispatchAsyncServlet", urlPatterns = > "/DispatchAsyncServlet", asyncSupported = true) > + public static class DispatchAsyncServlet extends HttpServlet { > + private ExecutorService executorService; > + > + @Override > + public void init() throws ServletException { > + executorService = Executors.newSingleThreadExecutor(); > + } > + > + @Override > + protected void service(final HttpServletRequest req, final > HttpServletResponse resp) throws ServletException, IOException { > + final AsyncContext actx = req.startAsync(); > + resp.setContentType("text/plain"); > + actx.dispatch("/ok"); > + } > + > + @Override > + public void destroy() { > + executorService.shutdownNow(); > + } > + } > + > + public static class ABean {} > + > + public static class SimpleAsyncListener implements AsyncListener { > + private static boolean started; > + > + @Inject > + private ABean bean; > + > + @Override > + public void onComplete(final AsyncEvent event) throws IOException > { > + // no-op > + } > + > + @Override > + public void onTimeout(AsyncEvent event) throws IOException { > + // no-op > + } > + > + @Override > + public void onError(AsyncEvent event) throws IOException { > + // no-op > + } > + > + @Override > + public void onStartAsync(final AsyncEvent event) throws > IOException { > + started = bean != null; > + } > + } > + > + @WebServlet("/ok") > + public static class SimpleServlet extends HttpServlet { > + @Override > + protected void service(final HttpServletRequest req, final > HttpServletResponse resp) throws ServletException, IOException { > + resp.getWriter().write("OK2"); > + } > + } > + > + private static class AsyncHandler implements Runnable { > + private final AsyncContext actx; > + > + public AsyncHandler(final AsyncContext ctx) { > + this.actx = ctx; > + } > + > + @Override > + public void run() { > + try { > + actx.getResponse().getWriter().write("OK"); > + } catch (final IOException e) { > + try { > + > HttpServletResponse.class.cast(actx.getResponse()).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); > + } catch (final IOException e1) { > + // no-op > + } > + actx.complete(); > + } > + actx.complete(); > + } > + } > +} > > -- Daniel Cunha (soro)
