Author: snoopdave
Date: Tue Mar 2 04:37:43 2010
New Revision: 917872
URL: http://svn.apache.org/viewvc?rev=917872&view=rev
Log:
Updates to Movable Type export https://issues.apache.org/jira/browse/ROL-1822
Modified:
roller/trunk/weblogger-web/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java
roller/trunk/weblogger-web/src/main/webapp/WEB-INF/jsps/editor/WeblogExport.jsp
Modified:
roller/trunk/weblogger-web/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java
URL:
http://svn.apache.org/viewvc/roller/trunk/weblogger-web/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java?rev=917872&r1=917871&r2=917872&view=diff
==============================================================================
---
roller/trunk/weblogger-web/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java
(original)
+++
roller/trunk/weblogger-web/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/WeblogExport.java
Tue Mar 2 04:37:43 2010
@@ -23,14 +23,22 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.LinkedHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
+// import java.net.URL;
+// import java.net.MalformedURLException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
+// import org.apache.abdera.Abdera;
+// import org.apache.abdera.ext.thread.ThreadHelper;
+// import org.apache.abdera.model.Entry;
+// import org.apache.abdera.model.Feed;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.RollerException;
@@ -45,6 +53,7 @@
import org.apache.roller.weblogger.pojos.WeblogEntry;
import org.apache.roller.weblogger.pojos.WeblogPermission;
import org.apache.roller.weblogger.pojos.wrapper.WeblogEntryCommentWrapper;
+// import org.apache.roller.weblogger.pojos.wrapper.WeblogEntryTagWrapper;
import org.apache.roller.weblogger.pojos.wrapper.WeblogEntryWrapper;
import org.apache.roller.weblogger.ui.struts2.util.UIAction;
import org.apache.struts2.interceptor.ServletResponseAware;
@@ -57,19 +66,37 @@
// Static Variables
--------------------------------------------------------
private static final Log log = LogFactory.getLog(WeblogExport.class);
- /** Used to replace <foo bar="foobar"/> with <foo bar="foobar" /> **/
- private static final Pattern BAD_SELF_CLOSING_TAG = Pattern.compile(
- "(([\\S])(/>))");
- // TODO: Add enum to manage the different MT constants
+
+ private static final Pattern SC_TAG_PATTERN =
+ Pattern.compile("(([\\S])(/>))");
+
+ private static final Pattern PRE_TAG_PATTERN =
+ Pattern.compile("<pre>[\\s\\S]+?</pre>");
+
+ private static final Pattern NEWLINE_PATTERN =
+ Pattern.compile("\\r\\n|\\r|\\n");
+
+ // TODO: Perhaps add enum to manage the different MT constants
private static final String MT_SECTION_DIVIDER = "-----\n";
private static final String MT_ENTRY_DIVIDER = "--------\n";
- private static final SimpleDateFormat MT_DATE_FORMAT = new
SimpleDateFormat(
- "MM/dd/yyyy HH:mm:ss");
+
+ private static final SimpleDateFormat MT_DATE_FORMAT =
+ new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
+ private static final SimpleDateFormat ATOM_ID_DATE_FORMAT =
+ new SimpleDateFormat("yyyy-MM-dd");
+
+ private static final String MT_FORMAT = "mtimport";
+ private static final String MT_PLUS_FORMAT = "mtimportplus";
+ private static final String ATOM_FORMAT = "atom";
+
+ // private static final Abdera abdera = new Abdera();
+
// Instance Variables
------------------------------------------------------
+ private Pattern baseUrlPattern;
+
private HttpServletResponse response;
private String baseUrl;
- private List<WeblogEntryWrapper> entries;
- private Pattern baseUrlPattern;
+ private String format;
// Constructors
------------------------------------------------------------
public WeblogExport() {
@@ -77,7 +104,8 @@
this.desiredMenu = "editor";
this.pageTitle = "weblogExport.title";
- this.entries = new ArrayList<WeblogEntryWrapper>();
+ // Set the default format
+ this.format = MT_FORMAT;
}
// Public Methods
----------------------------------------------------------
@@ -100,6 +128,40 @@
}
/**
+ * Get the current format.
+ *
+ * @return The current format.
+ */
+ public String getFormat() {
+ return format;
+ }
+
+ /**
+ * Sets the desired export format.
+ *
+ * @param format The desired export format.
+ */
+ public void setFormat(String format) {
+ this.format = format;
+ }
+
+ /**
+ * Gets the list of supported export formats.
+ *
+ * @return A list of string made of of supported export formats.
+ */
+ public Map<String, String> getFormatOptions() {
+ Map<String, String> options;
+ options = new LinkedHashMap<String, String>();
+
+ options.put(MT_FORMAT, getText("weblogExport.format.mtimport"));
+ options.put(MT_PLUS_FORMAT,
getText("weblogExport.format.mtimportplus"));
+ // options.put(ATOM_FORMAT, getText("weblogExport.format.atom"));
+
+ return options;
+ }
+
+ /**
* Require the author role before allowing export functionality.
*/
@Override
@@ -132,7 +194,7 @@
if (!WebloggerConfig.getBooleanProperty("weblog.export.enabled")) {
throw new WebloggerException("ERROR: export is disabled");
}
-
+
try {
WeblogEntryManager wmgr =
WebloggerFactory.getWeblogger().getWeblogEntryManager();
@@ -144,6 +206,9 @@
rawEntries = wmgr.getWeblogEntries(getActionWeblog(), null, null,
null, null, null, null, null, null, null, null, 0, -1);
+ List<WeblogEntryWrapper> entries;
+ entries = new ArrayList<WeblogEntryWrapper>();
+
for (Object entry : rawEntries) {
entries.add(WeblogEntryWrapper.wrap((WeblogEntry) entry,
urlStrategy));
@@ -151,12 +216,21 @@
// Compile the resource URL pattern using the weblog handle
baseUrlPattern = Pattern.compile(
- "(<[ \\S]+=[\"'])(http[s]*://[\\S]+/" +
- getActionWeblog().getHandle() + "/resource/|/" +
- getActionWeblog().getHandle() + "/resource/)");
+ "(<[\\s\\S]+?=[\"'])(http[s]*?://[\\S]+/" +
+ getActionWeblog().getHandle() + "/resource/|/" +
+ getActionWeblog().getHandle() + "/resource/)");
+ // Produce the selected output format
String output;
output = formatAsMoveableType(entries);
+ /*
+ if (format.equals(ATOM_FORMAT)) {
+ output = formatAsAtom(entries);
+ }
+ else {
+ output = formatAsMoveableType(entries);
+ }
+ */
if (!response.isCommitted()) {
response.reset();
@@ -169,11 +243,22 @@
fileName.append(getActionWeblog().getHandle());
fileName.append("-entries-");
fileName.append(dateFormat.format(System.currentTimeMillis()));
- fileName.append(".txt");
- response.setContentType("text/plain; charset=utf-8");
- response.setHeader("Content-Disposition",
- "attachment; filename=\"" + fileName.toString() +
"\"");
+ if (format.equals(ATOM_FORMAT)) {
+ fileName.append(".xml");
+ }
+ else {
+ fileName.append(".txt");
+ }
+
+ // Force the browser to download the export file
+ response.setContentType(
+ "application/octet-stream; charset=utf-8");
+ response.setContentLength(
+ output.getBytes("UTF-8").length);
+ response.setHeader(
+ "Content-Disposition", "attachment; filename=\"" +
+ fileName.toString() + "\"");
ServletOutputStream outputStream;
outputStream = response.getOutputStream();
@@ -263,7 +348,189 @@
// Private Methods
---------------------------------------------------------
/**
* Formats all entries and comments, including draft entries, in the
- * Moveable Type import format (mtimport). This format can be imported
+ * Atom Syndication Format.
+ *
+ * @param entries A collection of entries to format.
+ * @return A String of all entries and comments formatted as Atom
+ */
+ /*
+ private String formatAsAtom(List<WeblogEntryWrapper> entries) {
+ Weblog weblog;
+ weblog = getActionWeblog();
+
+ String hostname;
+ URL absoluteUrl;
+ try {
+ absoluteUrl = new URL(weblog.getAbsoluteURL());
+ hostname = absoluteUrl.getHost();
+ }
+ catch (MalformedURLException e) {
+ log.error("Unable to parse the absolute URL: " + e.getMessage());
+ hostname = "unknown";
+ }
+
+ // Feed
+ StringBuilder feedId;
+ feedId = new StringBuilder();
+
+ feedId.append("tag:");
+ feedId.append(hostname);
+ feedId.append(",");
+ feedId.append(ATOM_ID_DATE_FORMAT.format(weblog.getDateCreated()));
+ feedId.append(":");
+ feedId.append(weblog.getId());
+
+ Feed feed;
+ feed = abdera.newFeed();
+
+ feed.setId(feedId.toString());
+ feed.setTitle(weblog.getName());
+
+ if (weblog.getDescription() != null &&
+ !weblog.getDescription().equals("")) {
+ feed.setSubtitle(weblog.getDescription());
+ }
+
+ // TODO: Maybe want to add all authors
+ feed.addAuthor(weblog.getCreator().getScreenName());
+
+ // TODO: Really need a "self" link, but what to use?
+ feed.addLink(weblog.getAbsoluteURL(), "self");
+ feed.addLink(weblog.getAbsoluteURL(), "alternate");
+
+ feed.setUpdated(weblog.getLastModified());
+
+ feed.setGenerator("http://roller.apache.org",
+ WebloggerFactory.getWeblogger().getVersion(), "Apache Roller");
+
+ // Entries
+ for (WeblogEntryWrapper entryWrapper : entries) {
+ StringBuilder entryId;
+ entryId = new StringBuilder();
+
+ entryId.append("tag:");
+ entryId.append(hostname);
+ entryId.append(",");
+ entryId.append(ATOM_ID_DATE_FORMAT.format(
+ (entryWrapper.getPubTime() != null) ?
+ entryWrapper.getPubTime() :
+ entryWrapper.getUpdateTime()));
+ entryId.append(":");
+ entryId.append(entryWrapper.getId());
+
+ Entry entry;
+ entry = feed.addEntry();
+
+ entry.setId(entryId.toString());
+ entry.setTitle(entryWrapper.getTitle());
+ entry.addAuthor(entryWrapper.getCreator().getScreenName());
+ entry.addLink(entryWrapper.getPermalink(), "alternate");
+ entry.setPublished(entryWrapper.getPubTime());
+ entry.setUpdated(entryWrapper.getUpdateTime());
+
+ // Category
+ entry.addCategory(null, entryWrapper.getCategory().getPath(),
+ entryWrapper.getCategory().getName());
+
+ // Tags
+ for (Object tagWrapperObj : entryWrapper.getTags()) {
+ WeblogEntryTagWrapper tagWrapper;
+ tagWrapper = (WeblogEntryTagWrapper) tagWrapperObj;
+
+ entry.addCategory("http://roller.apache.org/ns/tags/",
+ tagWrapper.getName(), tagWrapper.getName());
+ }
+
+ // Enclosure
+ String enclosureUrl;
+ enclosureUrl = entryWrapper.findEntryAttribute(
+ "att_mediacast_url");
+
+ if (enclosureUrl != null && !enclosureUrl.equals("")) {
+ String enclosureType;
+ enclosureType = entryWrapper.findEntryAttribute(
+ "att_mediacast_type");
+
+ Long enclosureLength;
+ try {
+ enclosureLength = Long.parseLong(
+ entryWrapper.findEntryAttribute(
+ "att_mediacast_length"));
+ }
+ catch (NumberFormatException e) {
+ log.error("Unable to parse 'att_mediacast_length': " +
+ e.getMessage());
+ enclosureLength = (long) 0;
+ }
+
+ entry.addLink(enclosureUrl, "enclosure", enclosureType, null,
+ null, enclosureLength);
+ }
+
+ // Summary
+ if (entryWrapper.getSummary() != null &&
+ !entryWrapper.getSummary().equals("")) {
+ entry.setSummaryAsHtml(processEntry(
+ entryWrapper.getSummary().trim()));
+ }
+
+ // Content
+ if (entryWrapper.getText() != null &&
+ !entryWrapper.getText().equals("")) {
+ entry.setContentAsHtml(processEntry(
+ entryWrapper.getText().trim()));
+ }
+
+ // Comments in reply to the entry
+ for (Object commentObj : entryWrapper.getComments()) {
+ WeblogEntryCommentWrapper commentEntryWrapper;
+ commentEntryWrapper = (WeblogEntryCommentWrapper) commentObj;
+
+ StringBuilder commentEntryId;
+ commentEntryId = new StringBuilder();
+
+ commentEntryId.append("tag:");
+ commentEntryId.append(hostname);
+ commentEntryId.append(",");
+ commentEntryId.append(ATOM_ID_DATE_FORMAT.format(
+ commentEntryWrapper.getPostTime()));
+ commentEntryId.append(":");
+ commentEntryId.append(commentEntryWrapper.getId());
+
+ Entry commentEntry;
+ commentEntry = feed.addEntry();
+
+ commentEntry.setId(commentEntryId.toString());
+ commentEntry.setTitle("Re: " + entryWrapper.getTitle());
+
+ // Author
+ if (commentEntryWrapper.getName() != null &&
+ ! commentEntryWrapper.getName().equals("")) {
+ commentEntry.addAuthor(commentEntryWrapper.getName());
+ }
+ else {
+ commentEntry.addAuthor("Anonymous");
+ }
+
+ commentEntry.addLink(entryWrapper.getPermalink() +
+ "#comment-" + commentEntryWrapper.getTimestamp(),
+ "alternate");
+ commentEntry.setPublished(commentEntryWrapper.getPostTime());
+ commentEntry.setUpdated(commentEntryWrapper.getPostTime());
+
commentEntry.setContentAsHtml(commentEntryWrapper.getContent());
+
+ // The important bit
+ ThreadHelper.addInReplyTo(commentEntry, entry);
+ }
+ }
+
+ return feed.toString();
+ }
+ */
+
+ /**
+ * Formats all entries and comments, including draft entries, in the
+ * Moveable Type Import Format (mtimport). This format can be imported
* into both Moveable Type and WordPress blogging platforms.
*
* @param entries A collection of entries to format.
@@ -319,6 +586,7 @@
result.append(MT_SECTION_DIVIDER);
// Body
+ // TODO: May want to use transformed text here
result.append("BODY: \n");
result.append(processEntry(entry.getText().trim()));
result.append("\n");
@@ -327,6 +595,7 @@
// Excerpt
if (entry.getSummary() != null && !entry.getSummary().equals("")) {
+ // TODO: May want to use transformed summary here
result.append("EXCERPT: \n");
result.append(processEntry(entry.getSummary().trim()));
result.append("\n");
@@ -378,12 +647,45 @@
*/
private String processEntry(String text) {
String result;
+ result = text;
- // Fix self closing tags that are missing a space
- Matcher badSelfClosingTagMatcher;
- badSelfClosingTagMatcher = BAD_SELF_CLOSING_TAG.matcher(text);
+ // Some special processing is needed for mtimport
+ if (format.startsWith(MT_FORMAT)) {
+ // Fix self closing tags that are missing a space,
+ // replaceing <foo bar="foobar"/> with <foo bar="foobar" />
+ Matcher badSelfClosingTagMatcher;
+ badSelfClosingTagMatcher = SC_TAG_PATTERN.matcher(result);
+
+ result = badSelfClosingTagMatcher.replaceAll("$2 />");
+
+ if (format.equals(MT_PLUS_FORMAT)) {
+ // Replace all newlines with spaces leaving "<pre>" blocks
+ // alone. WordPress will automatically convert newlines to
+ // "<br />" which alters the intended formatting.
+ Matcher preTagMatcher;
+ preTagMatcher = PRE_TAG_PATTERN.matcher(result);
+
+ StringBuilder replacedNewLines;
+ replacedNewLines = new StringBuilder();
+
+ int index;
+ index = 0;
+
+ while (preTagMatcher.find()) {
+ replacedNewLines.append(NEWLINE_PATTERN.matcher(
+ result.substring(index, preTagMatcher.start())).
+ replaceAll(" "));
+ replacedNewLines.append(preTagMatcher.group());
+ index = preTagMatcher.end();
+ }
+
+ replacedNewLines.append(NEWLINE_PATTERN.matcher(
+ result.substring(index, result.length())).
+ replaceAll(" "));
- result = badSelfClosingTagMatcher.replaceAll("$2 />");
+ result = replacedNewLines.toString();
+ }
+ }
// Replace all /weblog-handle/resource/ links with a specified base URL
if (baseUrl != null && !baseUrl.equals("")) {
@@ -405,15 +707,15 @@
* Adds all the non-directory files for the specified path to the provided
* List.
*
- * @param resources The List in which to add the resource objects.
- * @param path The path from which to load. If null, the root path is used.
+ * @param mfiles The List in which to add the resource objects.
+ * @param mdir The path from which to load. If null, the root path is used.
*/
private void loadResources(List<MediaFile> mfiles, MediaFileDirectory
mdir) {
try {
// Load the non-directory files
mfiles.addAll(mdir.getMediaFiles());
} catch (Exception e) {
- log.error("Error load resources: " + e.getMessage());
+ log.error("Error loading resources: " + e.getMessage());
}
}
}
Modified:
roller/trunk/weblogger-web/src/main/webapp/WEB-INF/jsps/editor/WeblogExport.jsp
URL:
http://svn.apache.org/viewvc/roller/trunk/weblogger-web/src/main/webapp/WEB-INF/jsps/editor/WeblogExport.jsp?rev=917872&r1=917871&r2=917872&view=diff
==============================================================================
---
roller/trunk/weblogger-web/src/main/webapp/WEB-INF/jsps/editor/WeblogExport.jsp
(original)
+++
roller/trunk/weblogger-web/src/main/webapp/WEB-INF/jsps/editor/WeblogExport.jsp
Tue Mar 2 04:37:43 2010
@@ -30,21 +30,33 @@
<h2><s:text name="weblogExport.entries" /></h2>
<p class="pagetip" style="width:50%"><s:text name="weblogExport.entries.tip"
/></p>
<s:form name="entriesExport" action="weblogExport!exportEntries" method="POST">
- <p>
- <s:text name="weblogExport.baseUrl"/>
- <s:textfield name="baseUrl" size="30" />
- </p>
- <p>
- <s:submit value="%{getText('weblogExport.exportEntries')}" />
- <s:hidden name="weblog" />
- </p>
+ <table cellpadding="0" cellspacing="5" border="0">
+ <tr>
+ <td valign="baseline" align="right"><s:text
name="weblogExport.baseUrl"/></td>
+ <td valign="baseline"><s:textfield name="baseUrl" size="30" /></td>
+ </tr>
+ <tr>
+ <td valign="baseline" align="right"><s:text
name="weblogExport.format" /></td>
+ <td valign="baseline"><s:radio theme="roller" name="format"
list="formatOptions" value="format"/></td>
+ </tr>
+ <tr>
+ <td valign="baseline" colspan="2">
+ <s:submit key="weblogExport.exportEntries" />
+ <s:hidden name="weblog" />
+ </td>
+ </tr>
+ </table>
</s:form>
<h2><s:text name="weblogExport.resources" /></h2>
<p class="pagetip" style="width:50%"><s:text name="weblogExport.resources.tip"
/></p>
-<p>
- <s:form name="resourcesExport" action="weblogExport!exportResources"
method="POST">
- <s:submit value="%{getText('weblogExport.exportResources')}" />
- <s:hidden name="weblog" />
- </s:form>
-</p>
+<s:form name="resourcesExport" action="weblogExport!exportResources"
method="POST">
+ <table cellpadding="0" cellspacing="5" border="0">
+ <tr>
+ <td valign="baseline">
+ <s:submit key="weblogExport.exportResources" />
+ <s:hidden name="weblog" />
+ </td>
+ </tr>
+ </table>
+</s:form>