Commit 85169a1b authored by Maxime Sinclair's avatar Maxime Sinclair
Browse files

Enhanced version with short URL scheme, http headers to take advantage of the...

Enhanced version with short URL scheme, http headers to take advantage of the browser cache, and a new structure with JSP files.
parent 3847a2e1
/user.property
/WEB-INF/classes /WEB-INF/classes
/plantuml.war /plantuml.war
\ No newline at end of file /.settings
package net.sourceforge.plantuml.servlet; package net.sourceforge.plantuml.servlet;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import net.sourceforge.plantuml.SourceStringReader; import net.sourceforge.plantuml.SourceStringReader;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.code.Transcoder; import net.sourceforge.plantuml.code.Transcoder;
import net.sourceforge.plantuml.code.TranscoderUtil; import net.sourceforge.plantuml.code.TranscoderUtil;
import HTTPClient.CookieModule; import HTTPClient.CookieModule;
import HTTPClient.HTTPConnection; import HTTPClient.HTTPConnection;
import HTTPClient.HTTPResponse; import HTTPClient.HTTPResponse;
...@@ -32,15 +34,14 @@ import HTTPClient.ParseException; ...@@ -32,15 +34,14 @@ import HTTPClient.ParseException;
*/ */
public class PlantUmlServlet extends HttpServlet { public class PlantUmlServlet extends HttpServlet {
private static final Pattern startumlPattern = Pattern private static final Pattern startumlPattern = Pattern.compile("/\\w+/start/(.*)");
.compile("/\\w+/uml/startuml/(.*)"); private static final Pattern imagePattern = Pattern.compile("/\\w+/img/(.*)");
private static final Pattern proxyPattern = Pattern.compile("/\\w+/proxy/((\\d+)/)?(http://.*)");
private static final Pattern imagePattern = Pattern private static final Pattern oldStartumlPattern = Pattern.compile("/\\w+/uml/startuml/(.*)");
.compile("/\\w+/uml/image/(.*)"); private static final Pattern oldImagePattern = Pattern.compile("/\\w+/uml/image/(.*)");
private static final Pattern oldProxyPattern = Pattern.compile("/\\w+/uml/proxy/((\\d+)/)?(http://.*)");
private static final Pattern proxyPattern = Pattern
.compile("/\\w+/uml/proxy/((\\d+)/)?(http://.*)");
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException { throws IOException, ServletException {
...@@ -48,7 +49,9 @@ public class PlantUmlServlet extends HttpServlet { ...@@ -48,7 +49,9 @@ public class PlantUmlServlet extends HttpServlet {
Matcher startumlMatcher = startumlPattern.matcher(uri); Matcher startumlMatcher = startumlPattern.matcher(uri);
Matcher imageMatcher = imagePattern.matcher(uri); Matcher imageMatcher = imagePattern.matcher(uri);
Matcher proxyMatcher = proxyPattern.matcher(uri); Matcher proxyMatcher = proxyPattern.matcher(uri);
Matcher oldStartumlMatcher = oldStartumlPattern.matcher(uri);
Matcher oldImageMatcher = oldImagePattern.matcher(uri);
Matcher oldProxyMatcher = oldProxyPattern.matcher(uri);
if (startumlMatcher.matches()) { if (startumlMatcher.matches()) {
String source = startumlMatcher.group(1); String source = startumlMatcher.group(1);
handleImage(response, source); handleImage(response, source);
...@@ -59,79 +62,51 @@ public class PlantUmlServlet extends HttpServlet { ...@@ -59,79 +62,51 @@ public class PlantUmlServlet extends HttpServlet {
String num = proxyMatcher.group(2); String num = proxyMatcher.group(2);
String source = proxyMatcher.group(3); String source = proxyMatcher.group(3);
handleImageProxy(response, num, source); handleImageProxy(response, num, source);
} else if (oldStartumlMatcher.matches()) {
String source = oldStartumlMatcher.group(1);
handleImage(response, source);
} else if (oldImageMatcher.matches()) {
String source = oldImageMatcher.group(1);
handleImageDecompress(response, source);
} else if (oldProxyMatcher.matches()) {
String num = oldProxyMatcher.group(2);
String source = oldProxyMatcher.group(3);
handleImageProxy(response, num, source);
} else { } else {
doPost(request, response); doPost(request, response);
} }
} }
@Override @Override
protected void doPost(HttpServletRequest request, HttpServletResponse resp) protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.print("<html>");
writer.print("<head>");
writer
.print("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
writer.print("<meta http-equiv=\"expires\" content=\"0\">");
writer.print("<meta http-equiv=\"pragma\" content=\"no-cache\">");
writer
.print("<meta http-equiv=\"cache-control\" content=\"no-cache, must-revalidate\">");
writer
.print("<link rel=\"SHORTCUT ICON\" href=\"/plantuml/favicon.ico\">");
writer.print("</head>");
writer.print("<body>");
writer
.print("<h1>PlantUMLServer</h1><p>This application provides a servlet which serves images createdby <a href=\"http://plantuml.sourceforge.net\">PlantUML</a>.</p>");
String text = request.getParameter("text"); String text = request.getParameter("text");
String url = request.getParameter("url"); String url = request.getParameter("url");
String encode = ""; String encoded = "";
Transcoder transcoder = getTranscoder(); Transcoder transcoder = getTranscoder();
if (url != null) { // the URL form has been submitted
if ((url != null) && (!url.trim().isEmpty())) {
// TODO Verify the url is correct
Pattern p = Pattern.compile(".*/(.*)"); Pattern p = Pattern.compile(".*/(.*)");
Matcher m = p.matcher(url); Matcher m = p.matcher(url);
if (m.find()) { if (m.find()) {
url = m.group(1); url = m.group(1);
text = transcoder.decode(url);
} }
text = transcoder.decode(url);
}
writer
.print("<form method=post action=\"/plantuml/uml/post\"><textarea name=\"text\" cols=\"120\" rows=\"10\">");
if (text != null) {
encode = transcoder.encode(text);
writer.print(text);
} }
writer.print("</textarea><br><input type=\"submit\"></form>"); // the Text form has been submitted
writer.print("<hr>"); if ((text != null) && (!text.trim().isEmpty())) {
writer.print("You can enter here a previously generated URL:<p>"); encoded = transcoder.encode(text);
String host = "http://" + request.getServerName() + ":"
+ request.getServerPort();
String total = host + "/plantuml/uml/image/" + encode;
writer
.print("<form method=\"post\" action=\"/plantuml/uml/post\"><input name=\"url\" type=\"text\" size=\"150\" value=\""
+ total + "\">");
writer.print("<br><input type=\"submit\"></form>");
if (text != null) {
writer.print("<hr>");
writer.print("You can use the following URL:<p>");
String urlPart = "\"" + total + "\"";
writer.print("<a href=" + urlPart + " >");
writer.print("<code>");
writer.print("&lt;img src=" + urlPart + " &gt;");
writer.print("</code></a><p>");
writer.print("<a href=" + urlPart + " >");
writer.print("<img src=\"/plantuml/uml/image/" + encode + "\" >");
writer.print("</a>");
} }
writer.print("</body></html>");
writer.flush(); request.setAttribute("net.sourceforge.plantuml.servlet.decoded", text);
request.setAttribute("net.sourceforge.plantuml.servlet.encoded", encoded);
// forward to index.jsp
RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp");
dispatcher.forward(request, response);
} }
private Transcoder getTranscoder() { private Transcoder getTranscoder() {
...@@ -162,8 +137,7 @@ public class PlantUmlServlet extends HttpServlet { ...@@ -162,8 +137,7 @@ public class PlantUmlServlet extends HttpServlet {
private void handleImageProxy(HttpServletResponse response, String num, private void handleImageProxy(HttpServletResponse response, String num,
String source) throws IOException { String source) throws IOException {
String s = getContent(source); SourceStringReader reader = new SourceStringReader( getContent(source));
SourceStringReader reader = new SourceStringReader(s);
int n = num == null ? 0 : Integer.parseInt(num); int n = num == null ? 0 : Integer.parseInt(num);
// Write the first image to "os" // Write the first image to "os"
reader.generateImage(response.getOutputStream(), n); reader.generateImage(response.getOutputStream(), n);
...@@ -175,16 +149,18 @@ public class PlantUmlServlet extends HttpServlet { ...@@ -175,16 +149,18 @@ public class PlantUmlServlet extends HttpServlet {
plantUmlSource.append("@startuml\n"); plantUmlSource.append("@startuml\n");
plantUmlSource.append(text); plantUmlSource.append(text);
plantUmlSource.append("\n@enduml"); plantUmlSource.append("\n@enduml");
final String uml = plantUmlSource.toString();
SourceStringReader reader = new SourceStringReader(plantUmlSource SourceStringReader reader = new SourceStringReader(uml);
.toString());
// Write the first image to "os" // Write the first image to "os"
long today = System.currentTimeMillis(); long today = System.currentTimeMillis();
response.addDateHeader("Expires", today + 31536000000L); if ( StringUtils.isDiagramCacheable( uml)) {
// today + 1 year // Add http headers to force the browser to cache the image
response.addDateHeader("Last-Modified", 1261440000000L); response.addDateHeader("Expires", today + 31536000000L);
// 2009 dec 22 constant date in the past // today + 1 year
response.addHeader("Cache-Control", "public"); response.addDateHeader("Last-Modified", 1261440000000L);
// 2009 dec 22 constant date in the past
response.addHeader("Cache-Control", "public");
}
response.setContentType("image/png"); response.setContentType("image/png");
reader.generateImage(response.getOutputStream()); reader.generateImage(response.getOutputStream());
......
...@@ -5,11 +5,36 @@ ...@@ -5,11 +5,36 @@
<servlet-name>plantumlservlet</servlet-name> <servlet-name>plantumlservlet</servlet-name>
<servlet-class>net.sourceforge.plantuml.servlet.PlantUmlServlet</servlet-class> <servlet-class>net.sourceforge.plantuml.servlet.PlantUmlServlet</servlet-class>
</servlet> </servlet>
<!-- Patterns of the servlet -->
<servlet-mapping> <servlet-mapping>
<servlet-name>plantumlservlet</servlet-name> <servlet-name>plantumlservlet</servlet-name>
<url-pattern>/uml/*</url-pattern> <url-pattern>/uml/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet-mapping>
<servlet-name>plantumlservlet</servlet-name>
<url-pattern>/form</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>plantumlservlet</servlet-name>
<url-pattern>/img/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>plantumlservlet</servlet-name>
<url-pattern>/start/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>plantumlservlet</servlet-name>
<url-pattern>/proxy/*</url-pattern>
</servlet-mapping>
<welcome-file-list> <welcome-file-list>
<welcome-file>uml</welcome-file> <welcome-file>/index.jsp</welcome-file>
</welcome-file-list> </welcome-file-list>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
</web-app> </web-app>
<project default="main" basedir="."> <project default="main" basedir=".">
<property name="tomcat-home" value="/tomcat" />
<path id="project-classpath">
<fileset dir="WEB-INF/lib" includes="*.jar" />
<fileset dir="${tomcat-home}/lib" includes="*.jar" />
</path>
<target name="main" depends="clean,compile,war"> <target name="main" depends="clean,compile,war">
</target> </target>
<target name="init">
<!-- overwrite with your own values in a user.property file -->
<property file="user.property" />
<property name="tomcat-home" value="/tomcat" />
<property name="debug" value="false" />
<path id="project-classpath">
<fileset dir="WEB-INF/lib" includes="*.jar" />
<fileset dir="${tomcat-home}/lib" includes="*.jar" />
</path>
</target>
<target name="clean"> <target name="clean">
<delete file="plantuml.war" /> <delete file="plantuml.war" />
<delete dir="WEB-INF/classes" /> <delete dir="WEB-INF/classes" />
<mkdir dir="WEB-INF/classes" /> <mkdir dir="WEB-INF/classes" />
</target> </target>
<target name="compile"> <target name="compile" depends="init">
<javac srcdir="WEB-INF/src" destdir="WEB-INF/classes" classpathref="project-classpath" /> <javac srcdir="WEB-INF/src" destdir="WEB-INF/classes" debug="${debug}" classpathref="project-classpath" />
</target> </target>
<target name="war"> <target name="war">
<war destfile="plantuml.war" <war destfile="plantuml.war"
webxml="WEB-INF/web.xml"> webxml="WEB-INF/web.xml">
<classes dir="WEB-INF/classes" /> <classes dir="WEB-INF/classes" />
<fileset file="favicon.ico" /> <fileset dir="content" />
<lib dir="WEB-INF/lib" /> <lib dir="WEB-INF/lib" />
</war> </war>
</target> </target>
<target name="deploy" depends="main">
<copy file="plantuml.war" todir="${tomcat-home}/webapps" overwrite="true" />
</target>
</project> </project>
<%@ page isErrorPage="true" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%
String contextRoot = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache, must-revalidate" />
<link rel="stylesheet" href="<%=contextRoot %>/plantuml.css" type="text/css"/>
<link rel="icon" href="<%=contextRoot %>/favicon.ico" type="image/x-icon"/>
<link rel="shortcut icon" href="<%=contextRoot %>/favicon.ico" type="image/x-icon"/>
<title>PlantUMLServer Error</title>
</head>
<body>
<p>
Sorry, but things didn't work out as planned.
</p>
<hr/>
<jsp:useBean id="now" class="java.util.Date" />
<ul>
<li><%=now.toString() %></li>
<li>Request that failed: <%=pageContext.getErrorData().getRequestURI() %></li>
<li>Status code: <%=pageContext.getErrorData().getStatusCode() %></li>
<li>Exception: <%=pageContext.getErrorData().getThrowable() %></li>
</ul>
<hr/>
</body>
</html>
\ No newline at end of file
<%@ page info="index" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%
String contextRoot = request.getContextPath();
String host = "http://" + request.getServerName() + ":" + request.getServerPort();
String encoded = "";
String umltext = "";
String imgurl = "";
Object encodedAttribute = request.getAttribute("net.sourceforge.plantuml.servlet.encoded");
if (encodedAttribute != null) {
encoded = encodedAttribute.toString();
if (!encoded.isEmpty()) {
imgurl = host + contextRoot + "/img/" + encoded;
}
}
Object decodedAttribute = request.getAttribute("net.sourceforge.plantuml.servlet.decoded");
if (decodedAttribute != null) {
umltext = decodedAttribute.toString();
}
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache, must-revalidate" />
<link rel="stylesheet" href="<%=contextRoot %>/plantuml.css" type="text/css"/>
<link rel="icon" href="<%=contextRoot %>/favicon.ico" type="image/x-icon"/>
<link rel="shortcut icon" href="<%=contextRoot %>/favicon.ico" type="image/x-icon"/>
<title>PlantUMLServer</title>
</head>
<body>
<div id="header">
<%-- PAGE TITLE --%>
<h1>PlantUMLServer</h1>
<p>This application provides a servlet which serves images created by <a href="http://plantuml.sourceforge.net">PlantUML</a>.</p>
</div>
<div id="content">
<%-- CONTENT --%>
<form method="post" action="<%=contextRoot %>/form">
<p>
<textarea name="text" cols="120" rows="10"><%=umltext %></textarea>
<br/>
<input type="submit" />
</p>
</form>
<hr/>
You can enter here a previously generated URL:
<form method="post" action="<%=contextRoot %>/form">
<p>
<input name="url" type="text" size="150" value="<%=imgurl %>" />
<br/>
<input type="submit"/>
</p>
</form>
<% if ( !imgurl.isEmpty()) { %>
<hr/>
<p>You can use the following URL:
<br/>
<a href="<%=imgurl %>"><code>&lt;img src="<%=imgurl %>" /&gt;</code></a>
<br/><br/>
<img id="diagram" src="<%=imgurl %>" alt="PlantUML diagram"/>
</p>
<% } //endif %>
</div>
<%-- FOOTER
<%@ include file="util/footer.jspf" %> --%>
</body>
</html>
/******************************
* PlantUMLServlet style sheet *
******************************/
/* Header */
#header {
margin-left: auto;
margin-right: auto;
text-align: center;
}
/* Form inputs */
#content textarea, #content input[type=text] {
width: 900px;
}
/* Diagram */
#content img#diagram {
border: thin solid green;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment