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;
}
}