blob: b0bac5de7e4143c4b2ebe53ddc7eafec32ce194d [file] [log] [blame]
/* 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.portals.samples;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.portlet.PortletAsyncContext;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.annotations.ServeResourceMethod;
import org.apache.portals.samples.AsyncDialogBean.OutputType;
/**
* Implements the async resource method for the async portlet.
*
* @author Scott Nicklous
*
*/
public class AsyncPortlet {
private static final Logger LOGGER = Logger.getLogger(AsyncPortlet.class.getName());
private static final boolean isTrace = LOGGER.isLoggable(Level.FINEST);
private final static String JSP = "/WEB-INF/jsp/asyncOutput.jsp";
private final static String ATTRIB_REPS = "reps";
private final static String ATTRIB_AUTO = "auto";
public final static String ATTRIB_TITLE = "title";
public final static String ATTRIB_TIMEOUT = "timeout";
public static class AsyncRunnable implements Runnable {
private PortletAsyncContext ctx;
private int delay;
private OutputType type;
@Inject private PortletRequestRandomNumberBean reqnum;
@Inject private APComplete complete;
public void init(PortletAsyncContext ctx, int delay, OutputType type) {
this.ctx = ctx;
this.delay = delay;
this.type = type;
StringBuilder txt = new StringBuilder(128);
txt.append("Initializing runnable.");
txt.append(" delay: ").append(delay);
txt.append(", type: ").append(type);
LOGGER.fine(txt.toString());
}
@Override
public void run() {
try {
Thread.sleep(delay);
if (complete.isComplete()) {
LOGGER.warning("Request completed before work was finished. processing will be aborted.");
return;
}
ResourceRequest req = ctx.getResourceRequest();
ResourceResponse resp = ctx.getResourceResponse();
PortletRequestDispatcher rd = req.getPortletContext().getRequestDispatcher(JSP);
AsyncPortlet.trace(req, "Runnable: ");
PortletConfig config = (PortletConfig) req.getAttribute("javax.portlet.config");
String portletName = "Could not get PortletConfig";
if (config != null) {
portletName = config.getPortletName();
}
switch (type) {
case TEXT:
LOGGER.fine("Producing text output.");
StringBuilder txt = new StringBuilder(128);
txt.append("<h5>Thread producing text output for portlet: " + portletName + "</h5>");
txt.append("<p>Dispatcher type: ").append(req.getDispatcherType().toString());
txt.append("<span style='margin-left: 2em;'>Request #: ");
try { // in case context not active
txt.append(reqnum.getRandomNumber());
} catch (Exception e) {}
txt.append("</span></p><hr>");
resp.getWriter().write(txt.toString());
ctx.complete();
break;
case AUTO:
StringBuilder str = new StringBuilder(128);
str.append("Dispatching to resource method.");
str.append(" context path: ").append(req.getPortletContext().getContextPath());
LOGGER.fine(str.toString());
req.setAttribute(ATTRIB_AUTO, new Boolean(true));
ctx.dispatch();
break;
case DISPATCH:
LOGGER.fine("Dispatching to JSP.");
req.setAttribute(ATTRIB_TITLE, "Thread dispatching to JSP");
ctx.dispatch(JSP);
break;
case FWD:
LOGGER.fine("Doing request dispatcher forward to JSP: " + JSP);
req.setAttribute(ATTRIB_TITLE, "Thread forwarding to JSP");
rd.forward(req, resp);
LOGGER.fine("After request dispatcher forward to JSP.");
ctx.complete();
break;
case INC:
LOGGER.fine("Including JSP: " + JSP);
req.setAttribute(ATTRIB_TITLE, "Thread including JSP");
rd.include(req, resp);
ctx.complete();
break;
}
} catch (IllegalStateException e) {
LOGGER.warning("Request may have timed out before it could complete. Exception: " + e.toString());
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
LOGGER.fine("Exception during runner execution: \n" + sw.toString());
}
}
}
@Inject private AsyncDialogBean adb;
@Inject private PortletRequestRandomNumberBean reqnum;
@Inject private AsyncRunnable runner;
@ServeResourceMethod(portletNames = "AsyncPortlet", asyncSupported = true)
public void getResource(ResourceRequest req, ResourceResponse resp) throws IOException, PortletException {
if (req.getAttribute(ATTRIB_TIMEOUT) != null) {
StringBuilder txt = new StringBuilder(128);
txt.append("<p>Resource method: listener reports timout.");
txt.append("<span style='margin-left: 2em;'>Request #: ");
txt.append("dispatcher type: ").append(req.getDispatcherType().toString());
txt.append("</span>");
txt.append("<span style='margin-left: 2em;'>Request #: ");
txt.append(reqnum.getRandomNumber());
txt.append("</span></p><hr>");
resp.getWriter().write(txt.toString());
return;
}
Boolean auto = (Boolean) req.getAttribute(ATTRIB_AUTO);
if (auto == null) {
auto = false;
}
req.removeAttribute(ATTRIB_AUTO);
Integer reps = (Integer) req.getAttribute(ATTRIB_REPS);
if (reps == null) {
reps = adb.getReps();
}
boolean done = (reps <= 0) || (adb.getDelay() <= 0);
reps--;
req.setAttribute(ATTRIB_REPS, reps);
StringBuilder txt = new StringBuilder(128);
txt.append("Resource method.");
txt.append(" delay: ").append(adb.getDelay());
txt.append(", type: ").append(adb.getType());
txt.append(", reps: ").append(reps);
txt.append(", total reps: ").append(adb.getReps());
txt.append(", auto: ").append(adb.isAutoDispatch());
txt.append(", auto-dispatch: ").append(auto);
LOGGER.fine(txt.toString());
PortletAsyncContext ctx = req.startAsync();
ctx.setTimeout(4000);
try {
ctx.addListener(ctx.createPortletAsyncListener(APListener.class));
} catch (PortletException e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
LOGGER.fine("Exception adding listener: \n" + sw.toString());
}
if (auto || (adb.getDelay() <= 0)) {
// produce output if dispatched from work thread or if there is no delay requested
PortletRequestDispatcher rd;
trace(req, "Resource method: ");
// HttpServletRequest hreq = (HttpServletRequest) ctx.getRequest();
PortletConfig config = (PortletConfig) req.getAttribute("javax.portlet.config");
String portletName = "Could not get PortletConfig";
if (config != null) {
portletName = config.getPortletName();
}
switch (adb.getType()) {
case DISPATCH:
LOGGER.fine("Dispatching to JSP.");
req.setAttribute(ATTRIB_TITLE, "Resource Method dispatching to JSP");
ctx.dispatch(JSP);
break;
case FWD:
LOGGER.fine("Doing request dispatcher forward to JSP.");
req.setAttribute(ATTRIB_TITLE, "Resource Method forwarding to JSP");
rd = req.getPortletContext().getRequestDispatcher(JSP);
rd.forward(req, resp);
resp.flushBuffer();
if (done) {
ctx.complete();
}
break;
case INC:
LOGGER.fine("Doing request dispatcher include of JSP.");
req.setAttribute(ATTRIB_TITLE, "Resource Method including JSP");
rd = req.getPortletContext().getRequestDispatcher(JSP);
rd.include(req, resp);
resp.flushBuffer();
if (done) {
ctx.complete();
}
break;
default:
LOGGER.fine("Producing text output.");
txt.setLength(0);
txt.append("<h5>Resource method producing text output for portlet: " + portletName + "</h5>");
txt.append("<p>dispatcher type: ").append(req.getDispatcherType().toString());
txt.append("<span style='margin-left: 2em;'>Request #: ");
txt.append(reqnum.getRandomNumber());
txt.append("</span></p><hr>");
resp.getWriter().write(txt.toString());
resp.flushBuffer();
if (done) {
ctx.complete();
}
break;
}
}
if (!done) {
// now start the executor thread
OutputType type = adb.getType();
if (adb.isAutoDispatch()) {
type = OutputType.AUTO;
}
runner.init(ctx, adb.getDelay(), type);
ctx.start(runner);
}
}
public static void trace(ResourceRequest req, String src) {
if (isTrace) {
List<String> attrNames = Collections.list(req.getAttributeNames());
StringBuilder txt = new StringBuilder(128);
txt.append(src);
txt.append("\nAttribute names: ").append(attrNames);
txt.append("\nasync_request_uri: ").append((String) req.getAttribute("javax.servlet.async.request_uri"));
txt.append("\nasync_context_path: ").append((String) req.getAttribute("javax.servlet.async.context_path"));
txt.append("\nasync_servlet_path: ").append((String) req.getAttribute("javax.servlet.async.servlet_path"));
txt.append("\nasync_path_info: ").append((String) req.getAttribute("javax.servlet.async.path_info"));
txt.append("\nasync_query_string: ").append((String) req.getAttribute("javax.servlet.async.query_string"));
txt.append("\nforward_request_uri: ").append((String) req.getAttribute("javax.servlet.forward.request_uri"));
txt.append("\nforward_context_path: ").append((String) req.getAttribute("javax.servlet.forward.context_path"));
txt.append("\nforward_servlet_path: ").append((String) req.getAttribute("javax.servlet.forward.servlet_path"));
txt.append("\nforward_path_info: ").append((String) req.getAttribute("javax.servlet.forward.path_info"));
txt.append("\nforward_query_string: ").append((String) req.getAttribute("javax.servlet.forward.query_string"));
txt.append("\ninclude_request_uri: ").append((String) req.getAttribute("javax.servlet.include.request_uri"));
txt.append("\ninclude_context_path: ").append((String) req.getAttribute("javax.servlet.include.context_path"));
txt.append("\ninclude_servlet_path: ").append((String) req.getAttribute("javax.servlet.include.servlet_path"));
txt.append("\ninclude_path_info: ").append((String) req.getAttribute("javax.servlet.include.path_info"));
txt.append("\ninclude_query_string: ").append((String) req.getAttribute("javax.servlet.include.query_string"));
txt.append("\nmethod_context_path: ").append(req.getContextPath());
LOGGER.fine(txt.toString());
}
}
}