package org.springframework.roo.addon.web.mvc.embedded; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.logging.Logger; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.springframework.roo.addon.web.mvc.jsp.JspOperations; import org.springframework.roo.process.manager.FileManager; import org.springframework.roo.project.Path; import org.springframework.roo.project.PathResolver; import org.springframework.roo.support.util.FileUtils; import org.springframework.roo.support.util.XmlElementBuilder; import org.springframework.roo.url.stream.UrlInputStreamService; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * Convenience class for the implementation of a {@link EmbeddedProvider}. * Offers methods for installing tagx, jspx files and making HTTP requests. * * @author Stefan Schmidt * @since 1.1 */ @Component(componentAbstract = true) public abstract class AbstractEmbeddedProvider implements EmbeddedProvider { private static final Logger LOGGER = Logger.getLogger(AbstractEmbeddedProvider.class.getName()); @Reference private FileManager fileManager; @Reference private UrlInputStreamService urlInputStreamService; @Reference private JspOperations jspOperations; @Reference private PathResolver pathResolver; /** * Convenience method to create a readable title for a EmbeddedCompletor * enum value * * @param providerName the original String * @return the readable String */ private String getTitle(final String providerName) { final String[] names = providerName.split("_"); final StringBuilder sb = new StringBuilder(); for (final String name : names) { sb.append(StringUtils.capitalize(name.toLowerCase())); sb.append(" "); } return sb.toString().trim(); } /** * Convenience method to clean view name of a jspx. * * @param viewName the view name to clean * @param defaultName the default page name * @return the cleaned name */ public String getViewName(String viewName, final String defaultName) { if (viewName == null || viewName.length() == 0) { viewName = defaultName; } if (viewName.endsWith(".jspx")) { viewName = viewName.substring(0, viewName.indexOf(".") - 1); } return viewName.toLowerCase(); } /** * Method to install jspx file into /WEB-INF/views/embed/ of target project. * * @param viewName the jspx file name to install (required) * @param title the title of the page to be displayed (not required, * viewName is used alternatively) * @param contentElement the DOM element to include into the page. */ public void installJspx(String viewName, String title, final Element contentElement) { Validate.notBlank(viewName, "View name required"); Validate.notNull(contentElement, "Content element required"); if (StringUtils.isBlank(title)) { title = getTitle(viewName); } viewName = getViewName(viewName, "default"); final String jspx = pathResolver.getFocusedIdentifier(Path.SRC_MAIN_WEBAPP, "WEB-INF/views/embed/" + viewName + ".jspx"); final Document document = contentElement.getOwnerDocument(); if (!fileManager.exists(jspx)) { // Add document namespaces final Element div = new XmlElementBuilder("div", document) .addAttribute("xmlns:util", "urn:jsptagdir:/WEB-INF/tags/util") .addAttribute("xmlns:embed", "urn:jsptagdir:/WEB-INF/tags/embed") .addAttribute("xmlns:jsp", "http://java.sun.com/JSP/Page") .addAttribute("version", "2.0") .addChild( new XmlElementBuilder("jsp:output", document).addAttribute( "omit-xml-declaration", "yes").build()).build(); document.appendChild(div); div.appendChild(new XmlElementBuilder("util:panel", document).addAttribute("id", "title") .addAttribute("title", title).addChild(contentElement).build()); jspOperations.installView("/embed", viewName, title, "Embedded", document, pathResolver.getFocusedPath(Path.SRC_MAIN_WEBAPP)); } else { LOGGER.warning("Could not install jspx with name " + viewName + " because it exists already. Use the --viewName attribute to specify unique name."); } } /** * Method to install tagx file into /WEB-INF/tags/embed/ of target project. * * @param tagName */ public void installTagx(String tagName) { Validate.notBlank(tagName, "Tag name required"); if (!tagName.endsWith(".tagx")) { tagName = tagName.concat(".tagx"); } final String tagx = pathResolver.getFocusedIdentifier(Path.SRC_MAIN_WEBAPP, "WEB-INF/tags/embed/" + tagName); if (!fileManager.exists(tagx)) { InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = FileUtils.getInputStream(getClass(), "tags/" + tagName); outputStream = fileManager.createFile(tagx).getOutputStream(); IOUtils.copy(inputStream, outputStream); } catch (final IOException e) { throw new IllegalStateException("Could not install " + tagx); } finally { IOUtils.closeQuietly(inputStream); IOUtils.closeQuietly(outputStream); } } } /** * Helper method to determine if a given provider is supported by this * implementation. * * @param candidate the provider name * @param completors the completors offered by this implementation * @return true if the provider is supported */ public boolean isProviderSupported(final String candidate, final EmbeddedCompletor[] completors) { for (final EmbeddedCompletor completor : completors) { if (completor.name().equalsIgnoreCase(candidate)) { return true; } } return false; } /** * Method to send a HTTP GET request through the Roo provided * infrastructure. * * @param urlStr the URL * @return the result of the GET request. */ public String sendHttpGetRequest(final String urlStr) { Validate.notBlank(urlStr, "URL required"); String result = null; if (urlStr.startsWith("http://")) { InputStream inputStream = null; try { final URL url = new URL(urlStr); inputStream = urlInputStreamService.openConnection(url); return IOUtils.toString(inputStream); } catch (final IOException e) { LOGGER.warning("Unable to connect to " + urlStr); } finally { IOUtils.closeQuietly(inputStream); } } return result; } }