public String build(String className) { String actionName = className; if (actionName.equals(actionSuffix)) throw new IllegalStateException( "The action name cannot be the same as the action suffix [" + actionSuffix + "]"); // Truncate Action suffix if found if (actionName.endsWith(actionSuffix)) { actionName = actionName.substring(0, actionName.length() - actionSuffix.length()); } // Convert to underscores char[] ca = actionName.toCharArray(); StringBuilder build = new StringBuilder("" + ca[0]); boolean lower = true; for (int i = 1; i < ca.length; i++) { char c = ca[i]; if (Character.isUpperCase(c) && lower) { build.append(separator); lower = false; } else if (!Character.isUpperCase(c)) { lower = true; } build.append(c); } actionName = build.toString(); if (lowerCase) { actionName = actionName.toLowerCase(); } if (LOG.isTraceEnabled()) { LOG.trace("Changed action name from [#0] to [#1]", className, actionName); } return actionName; }
/** * Creates any result types from the resources available in the web application. This scans the * web application resources using the servlet context. * * @param actionClass The action class the results are being built for. * @param results The results map to put the result configs created into. * @param resultPath The calculated path to the resources. * @param resultPrefix The prefix for the result. This is usually <code>/resultPath/actionName * </code>. * @param actionName The action name which is used only for logging in this implementation. * @param packageConfig The package configuration which is passed along in order to determine * @param resultsByExtension The map of extensions to result type configuration instances. */ protected void createFromResources( Class<?> actionClass, Map<String, ResultConfig> results, final String resultPath, final String resultPrefix, final String actionName, PackageConfig packageConfig, Map<String, ResultTypeConfig> resultsByExtension) { if (LOG.isTraceEnabled()) { LOG.trace( "Searching for results in the Servlet container at [#0]" + " with result prefix of [#1]", resultPath, resultPrefix); } // Build from web application using the ServletContext @SuppressWarnings("unchecked") Set<String> paths = servletContext.getResourcePaths(flatResultLayout ? resultPath : resultPrefix); if (paths != null) { for (String path : paths) { if (LOG.isTraceEnabled()) { LOG.trace("Processing resource path [#0]", path); } String fileName = StringUtils.substringAfterLast(path, "/"); if (StringUtils.isBlank(fileName) || StringUtils.startsWith(fileName, ".")) { if (LOG.isTraceEnabled()) LOG.trace("Ignoring file without name [#0]", path); continue; } else if (fileName.lastIndexOf(".") > 0) { String suffix = fileName.substring(fileName.lastIndexOf(".") + 1); if (conventionsService.getResultTypesByExtension(packageConfig).get(suffix) == null) { if (LOG.isDebugEnabled()) LOG.debug( "No result type defined for file suffix : [#0]. Ignoring file #1", suffix, fileName); continue; } } makeResults(actionClass, path, resultPrefix, results, packageConfig, resultsByExtension); } } // Building from the classpath String classPathLocation = resultPath.startsWith("/") ? resultPath.substring(1, resultPath.length()) : resultPath; if (LOG.isTraceEnabled()) { LOG.trace( "Searching for results in the class path at [#0]" + " with a result prefix of [#1] and action name [#2]", classPathLocation, resultPrefix, actionName); } ResourceFinder finder = new ResourceFinder(classPathLocation, getClassLoaderInterface()); try { Map<String, URL> matches = finder.getResourcesMap(""); if (matches != null) { Test<URL> resourceTest = getResourceTest(resultPath, actionName); for (Map.Entry<String, URL> entry : matches.entrySet()) { if (resourceTest.test(entry.getValue())) { if (LOG.isTraceEnabled()) { LOG.trace("Processing URL [#0]", entry.getKey()); } String urlStr = entry.getValue().toString(); int index = urlStr.lastIndexOf(resultPrefix); String path = urlStr.substring(index); makeResults( actionClass, path, resultPrefix, results, packageConfig, resultsByExtension); } } } } catch (IOException ex) { if (LOG.isErrorEnabled()) LOG.error("Unable to scan directory [#0] for results", ex, classPathLocation); } }
/** * Makes all the results for the given path. * * @param actionClass The action class the results are being built for. * @param path The path to build the result for. * @param resultPrefix The is the result prefix which is the result location plus the action name. * This is used to determine if the path contains a result code or not. * @param results The Map to place the result(s) * @param packageConfig The package config the results belong to. * @param resultsByExtension The map of extensions to result type configuration instances. */ protected void makeResults( Class<?> actionClass, String path, String resultPrefix, Map<String, ResultConfig> results, PackageConfig packageConfig, Map<String, ResultTypeConfig> resultsByExtension) { if (path.startsWith(resultPrefix)) { int indexOfDot = path.indexOf('.', resultPrefix.length()); // This case is when the path doesn't contain a result code if (indexOfDot == resultPrefix.length() || !flatResultLayout) { if (LOG.isTraceEnabled()) { LOG.trace( "The result file [#0] has no result code and therefore" + " will be associated with success, input and error by default. This might" + " be overridden by another result file or an annotation.", path); } if (!results.containsKey(Action.SUCCESS)) { ResultConfig success = createResultConfig( actionClass, new ResultInfo(Action.SUCCESS, path, packageConfig, resultsByExtension), packageConfig, null); results.put(Action.SUCCESS, success); } if (!results.containsKey(Action.INPUT)) { ResultConfig input = createResultConfig( actionClass, new ResultInfo(Action.INPUT, path, packageConfig, resultsByExtension), packageConfig, null); results.put(Action.INPUT, input); } if (!results.containsKey(Action.ERROR)) { ResultConfig error = createResultConfig( actionClass, new ResultInfo(Action.ERROR, path, packageConfig, resultsByExtension), packageConfig, null); results.put(Action.ERROR, error); } // This case is when the path contains a result code } else if (indexOfDot > resultPrefix.length()) { if (LOG.isTraceEnabled()) { LOG.trace( "The result file [#0] has a result code and therefore" + " will be associated with only that result code.", path); } String resultCode = path.substring(resultPrefix.length() + 1, indexOfDot); ResultConfig result = createResultConfig( actionClass, new ResultInfo(resultCode, path, packageConfig, resultsByExtension), packageConfig, null); results.put(resultCode, result); } } }
@Override protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception { if (LOG.isDebugEnabled()) { LOG.debug("In doExecute. finalLocation: " + finalLocation + ", renderer: " + renderer); } OutputStream os = null; try { final ActionContext actionContext = invocation.getInvocationContext(); final HttpServletRequest request = (HttpServletRequest) actionContext.get(HTTP_REQUEST); final HttpServletResponse response = (HttpServletResponse) actionContext.get(HTTP_RESPONSE); final SimpleServletResponseWrapper responseWrapper = new SimpleServletResponseWrapper(response); final ServletContext servletContext = (ServletContext) actionContext.get(SERVLET_CONTEXT); ViewRenderer viewRenderer; if (renderer == null) { viewRenderer = container.getInstance(ViewRenderer.class); } else { viewRenderer = container.getInstance(ViewRenderer.class, renderer); } if (viewRenderer == null) { final String err = "Cannot get an instance of ViewRenderer with the name '" + renderer + "'."; LOG.error(err); throw new AssertionError(err); } // render view viewRenderer.render( finalLocation, request, responseWrapper, servletContext, actionContext.getLocale(), invocation.getStack(), invocation.getAction()); // Set the content type response.setContentType(PDF_MIME_TYPE); // Set the content-disposition if (contentDisposition != null) { response.addHeader("Content-Disposition", conditionalParse(contentDisposition, invocation)); } // Set the cache control headers if necessary if (!allowCaching) { response.addHeader("Pragma", "no-cache"); response.addHeader("Cache-Control", "no-cache"); } if (LOG.isTraceEnabled()) { LOG.trace("Content before parsing:\n" + responseWrapper.toString()); } // parse response wrapper final Document document = parseContent(responseWrapper.toString()); final Element head = document.head(); // add CSS from cssPathsSet parameter if (cssPathsSet != null && !cssPathsSet.isEmpty()) { for (String css : cssPathsSet) { // remove leading slash if (css.startsWith("\\")) { css = css.substring(1); } head.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + css + "\" />"); } } // add style for font family that supports unicode head.append(FONT_STYLE_TAG); final String content = document.html(); if (LOG.isTraceEnabled()) { LOG.trace("Content after parsing:\n" + content); } // put pdf stream into response createPdfStream(content, findBaseUrl(request), response.getOutputStream()); } finally { if (os != null) { os.close(); } } }