Commit 1776b9e4 authored by Ryan Graham's avatar Ryan Graham Committed by ryang

* Added the ability to allow users to specify the import and export file locations

* JM-369
* Added additional information to the migration section of the readme file

git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@2755 b35dd754-fafc-0310-a699-88a17e54d16e
parent 7e45a0a4
...@@ -2,23 +2,27 @@ ...@@ -2,23 +2,27 @@
<html> <html>
<head> <head>
<title>User Import/Export Plugin Changelog</title> <title>User Import/Export Plugin Changelog</title>
<style type="text/css"> <style type="text/css">
BODY { BODY {
font-size : 100%; font-size : 100%;
} }
BODY, TD, TH { BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif; font-family : tahoma, verdana, arial, helvetica, sans-serif;
font-size : 0.8em; font-size : 0.8em;
} }
H2 { H2 {
font-size : 10pt; font-size : 10pt;
font-weight : bold; font-weight : bold;
padding-left : 1em; padding-left : 1em;
} }
A:hover { A:hover {
text-decoration : none; text-decoration : none;
} }
H1 { H1 {
font-family : tahoma, arial, helvetica, sans-serif; font-family : tahoma, arial, helvetica, sans-serif;
font-size : 1.4em; font-size : 1.4em;
...@@ -32,11 +36,12 @@ ...@@ -32,11 +36,12 @@
font-weight : bold; font-weight : bold;
color : #060; color : #060;
} }
PRE { PRE {
font-family : courier new; font-family : courier new;
font-size : 100%; font-size : 100%;
} }
</style> </style>
</head> </head>
<body> <body>
...@@ -44,6 +49,13 @@ ...@@ -44,6 +49,13 @@
User Import/Export Plugin Changelog User Import/Export Plugin Changelog
</h1> </h1>
<p><b>2.0</b> -- September 1, 2005</p>
<ul>
<li>Added the ability to allow users to specify the import and export file locations.
<li>[<a href="http://www.jivesoftware.org/issues/browse/JM-369">JM-369</a>] - Add option to replace old domain with new domain while doing an import.
<li>Added additional information to the migration section of the readme file.
</ul>
<p><b>1.0.1</b> -- June 30, 2005</p> <p><b>1.0.1</b> -- June 30, 2005</p>
<ul> <ul>
<li>Added the ability to send export data directly to the screen.</li> <li>Added the ability to send export data directly to the screen.</li>
......
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
<name>User Import Export</name> <name>User Import Export</name>
<description>Enables import and export of user data.</description> <description>Enables import and export of user data.</description>
<author>Ryan Graham</author> <author>Ryan Graham</author>
<version>1.0.1</version> <version>2.0</version>
<date>06/30/2005</date> <date>09/01/2005</date>
<minServerVersion>2.1.4</minServerVersion> <minServerVersion>2.1.5</minServerVersion>
<adminconsole> <adminconsole>
<tab id="tab-users"> <tab id="tab-users">
......
This diff is collapsed.
package org.jivesoftware.messenger.plugin; package org.jivesoftware.messenger.plugin;
import java.io.File; import org.apache.commons.fileupload.FileItem;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper; import org.dom4j.DocumentHelper;
...@@ -30,10 +18,21 @@ import org.jivesoftware.messenger.user.UserAlreadyExistsException; ...@@ -30,10 +18,21 @@ import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserManager; import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException; import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.messenger.user.UserProvider; import org.jivesoftware.messenger.user.UserProvider;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/** /**
* The user import/export plugin provides a way to import and export Jive Messenger * The user import/export plugin provides a way to import and export Jive Messenger
* user data via the Admin Console. The user data consists of jid (aka "username"), * user data via the Admin Console. The user data consists of jid (aka "username"),
...@@ -48,33 +47,12 @@ public class ImportExportPlugin implements Plugin { ...@@ -48,33 +47,12 @@ public class ImportExportPlugin implements Plugin {
private UserProvider provider; private UserProvider provider;
private String serverName; private String serverName;
private String exportDirectory;
public ImportExportPlugin() { public ImportExportPlugin() {
userManager = XMPPServer.getInstance().getUserManager(); userManager = XMPPServer.getInstance().getUserManager();
provider = UserManager.getUserProvider(); provider = UserManager.getUserProvider();
serverName = XMPPServer.getInstance().getServerInfo().getName(); serverName = XMPPServer.getInstance().getServerInfo().getName();
if (exportDirectory == null) {
if (JiveGlobals.getHomeDirectory() != null) {
File messengerHome = new File(JiveGlobals.getHomeDirectory());
if (messengerHome.exists() && messengerHome.canWrite()) {
exportDirectory = (new File(messengerHome, "export")).toString();
}
}
}
if (!exportDirectory.endsWith(File.separator)) {
exportDirectory = exportDirectory + File.separator;
}
// Make sure the export directory exists. If not, make it:
File exportDir = new File(exportDirectory);
if (!exportDir.exists()) {
exportDir.mkdir();
}
} }
public void initializePlugin(PluginManager manager, File pluginDirectory) { public void initializePlugin(PluginManager manager, File pluginDirectory) {
...@@ -84,37 +62,19 @@ public class ImportExportPlugin implements Plugin { ...@@ -84,37 +62,19 @@ public class ImportExportPlugin implements Plugin {
userManager = null; userManager = null;
provider = null; provider = null;
serverName = null; serverName = null;
exportDirectory = null;
} }
public boolean isUserProviderReadOnly() { public boolean isUserProviderReadOnly() {
return provider.isReadOnly(); return provider.isReadOnly();
} }
public String exportDirectory() { public byte[] exportUsersToFile() throws IOException {
return exportDirectory; ByteArrayOutputStream out = new ByteArrayOutputStream();
}
public boolean exportUsersToFile(String file) throws IOException {
if (!file.endsWith(".xml")) {
file += ".xml";
}
String exportFilePath = exportDirectory + file;
XMLWriter writer = null; XMLWriter writer = writer = new XMLWriter(out, OutputFormat.createPrettyPrint());
try {
writer = new XMLWriter(new FileWriter(exportFilePath), OutputFormat.createPrettyPrint());
writer.write(exportUsers()); writer.write(exportUsers());
} catch (IOException ioe) {
Log.error(ioe);
throw ioe;
} finally {
if (writer != null) {
writer.close();
}
}
return true; return out.toByteArray();
} }
public String exportUsersToString() throws IOException { public String exportUsersToString() throws IOException {
...@@ -135,24 +95,10 @@ public class ImportExportPlugin implements Plugin { ...@@ -135,24 +95,10 @@ public class ImportExportPlugin implements Plugin {
return stringWriter.toString(); return stringWriter.toString();
} }
public boolean validateImportFile(String file) { public List<String> importUserData(FileItem file, String previousDomain) throws IOException, DocumentException {
String importFilePath = exportDirectory + file;
try {
return new UserSchemaValidator(importFilePath, "messenger-user-schema.xsd.xml").validate();
}
catch (Exception e) {
Log.error(e);
return false;
}
}
public List importUserData(String file) throws MalformedURLException, DocumentException {
String importFilePath = exportDirectory + File.separator + file;
SAXReader reader = new SAXReader(); SAXReader reader = new SAXReader();
Document document = reader.read(new File(importFilePath).toURL()); Document document = reader.read(file.getInputStream());
return importUsers(document); return importUsers(document, previousDomain);
} }
private Document exportUsers() { private Document exportUsers() {
...@@ -163,16 +109,6 @@ public class ImportExportPlugin implements Plugin { ...@@ -163,16 +109,6 @@ public class ImportExportPlugin implements Plugin {
for (User user : users) { for (User user : users) {
Element userElement = root.addElement("User"); Element userElement = root.addElement("User");
String userName = user.getUsername(); String userName = user.getUsername();
// if (userName != null) {
// try {
// userName = URLEncoder.encode(userName, "UTF-8");
// } catch (UnsupportedEncodingException e) {
// Log.error(e);
// userName = "";
// }
// } else {
// userName = "";
// }
userElement.addElement("Username").addText(userName); userElement.addElement("Username").addText(userName);
try { try {
...@@ -186,16 +122,6 @@ public class ImportExportPlugin implements Plugin { ...@@ -186,16 +122,6 @@ public class ImportExportPlugin implements Plugin {
userElement.addElement("Email").addText(user.getEmail() == null ? "" : user.getEmail()); userElement.addElement("Email").addText(user.getEmail() == null ? "" : user.getEmail());
String name = user.getName(); String name = user.getName();
// if (name != null) {
// try {
// name = URLEncoder.encode(name, "UTF-8");
// } catch (UnsupportedEncodingException e) {
// Log.error(e);
// name = "";
// }
// } else {
// name = "";
// }
userElement.addElement("Name").addText(name == null ? "" : name); userElement.addElement("Name").addText(name == null ? "" : name);
//creation and modified datte are not used as part of the import process but are exported //creation and modified datte are not used as part of the import process but are exported
...@@ -224,7 +150,7 @@ public class ImportExportPlugin implements Plugin { ...@@ -224,7 +150,7 @@ public class ImportExportPlugin implements Plugin {
return document; return document;
} }
public List<String> importUsers(Document document) throws DocumentException { private List<String> importUsers(Document document, String previousDomain) throws DocumentException {
List<String> duplicateUsers = new ArrayList<String>(); List<String> duplicateUsers = new ArrayList<String>();
UserManager userManager = UserManager.getInstance(); UserManager userManager = UserManager.getInstance();
...@@ -281,6 +207,11 @@ public class ImportExportPlugin implements Plugin { ...@@ -281,6 +207,11 @@ public class ImportExportPlugin implements Plugin {
groups.add(group.getText()); groups.add(group.getText());
} }
//used for migration
if (previousDomain != null) {
jid = jid.replace(previousDomain, serverName);
}
rosterItems.add(new RosterItem(new JID(jid), rosterItems.add(new RosterItem(new JID(jid),
RosterItem.SubType.getTypeFromInt(Integer.parseInt(substatus)), RosterItem.SubType.getTypeFromInt(Integer.parseInt(substatus)),
RosterItem.AskType.getTypeFromInt(Integer.parseInt(askstatus)), RosterItem.AskType.getTypeFromInt(Integer.parseInt(askstatus)),
...@@ -340,4 +271,3 @@ public class ImportExportPlugin implements Plugin { ...@@ -340,4 +271,3 @@ public class ImportExportPlugin implements Plugin {
return null; return null;
} }
} }
package org.jivesoftware.messenger.plugin; package org.jivesoftware.messenger.plugin;
import java.io.File; import com.sun.msv.reader.util.GrammarLoader;
import java.net.MalformedURLException; import com.sun.msv.reader.util.IgnoreController;
import java.net.URL; import com.sun.msv.verifier.DocumentDeclaration;
import com.sun.msv.verifier.Verifier;
import javax.xml.parsers.SAXParserFactory;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
...@@ -16,10 +15,11 @@ import org.xml.sax.ErrorHandler; ...@@ -16,10 +15,11 @@ import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator; import org.xml.sax.Locator;
import org.xml.sax.SAXParseException; import org.xml.sax.SAXParseException;
import com.sun.msv.reader.util.GrammarLoader; import java.io.File;
import com.sun.msv.reader.util.IgnoreController; import java.net.MalformedURLException;
import com.sun.msv.verifier.DocumentDeclaration; import java.net.URL;
import com.sun.msv.verifier.Verifier;
import javax.xml.parsers.SAXParserFactory;
public class UserSchemaValidator { public class UserSchemaValidator {
private Document doc; private Document doc;
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
String exportText = ""; String exportText = "";
Map errors = new HashMap(); Map<String, String> errors = new HashMap<String, String>();
if (exportUsers) { if (exportUsers) {
if (exportToFile) { if (exportToFile) {
String file = ParamUtils.getParameter(request, "exportFile"); String file = ParamUtils.getParameter(request, "exportFile");
...@@ -29,19 +29,7 @@ ...@@ -29,19 +29,7 @@
errors.put("missingFile","missingFile"); errors.put("missingFile","missingFile");
} }
else { else {
try { response.sendRedirect("export-file.jsp?fileName="+file);
//todo this could take some, redirect to a progress page?
if (plugin.exportUsersToFile(file)) {
response.sendRedirect("export-user-data.jsp?success=true");
return;
}
else {
errors.put("fileNotCreated","fileNotCreated");
}
}
catch (IOException e) {
errors.put("IOException","IOException");
}
} }
} }
else { else {
...@@ -55,7 +43,6 @@ ...@@ -55,7 +43,6 @@
} }
%> %>
<jsp:useBean id="pageinfo" scope="request" class="org.jivesoftware.admin.AdminPageBean" /> <jsp:useBean id="pageinfo" scope="request" class="org.jivesoftware.admin.AdminPageBean" />
<% // Title of this page and breadcrumbs <% // Title of this page and breadcrumbs
String title = "Export User Data"; String title = "Export User Data";
...@@ -108,45 +95,33 @@ ...@@ -108,45 +95,33 @@
<fieldset> <fieldset>
<legend>Export Options</legend> <legend>Export Options</legend>
<div> <div>
<p>
Select the radio button next to the desired export option and then click on the Export button.
</p>
<table cellpadding="3" cellspacing="0" border="0" width="100%"> <table cellpadding="3" cellspacing="0" border="0" width="100%">
<tbody> <tbody>
<tr> <tr>
<td width="1%"> <td width="1%"><input type="radio" name="exporttofile" value="true" <%= exportToFile ? "checked" : "" %> id="rb01"></td>
<input type="radio" name="exporttofile" value="true" <%= exportToFile ? "checked" : "" %> id="rb01"> <td width="99%"><label for="rb01"><b>To File</b></label> - Save user data to the specified file location.</td>
</td>
<td width="99%">
<label for="rb01"><b>To File</b></label> - Save user data to the specified file location.
</td>
<tr>
<td width="1%">&nbsp;</td>
<td width="99%">
<%= plugin.exportDirectory() %>
</td>
</tr> </tr>
<tr> <tr>
<td width="1%">&nbsp;</td> <td width="1%">&nbsp;</td>
<td width="99%">Export File Name:&nbsp;<input type="text" size="30" maxlength="150" name="exportFile"></td> <td width="99%">Export File Name:&nbsp;<input type="text" size="30" maxlength="150" name="exportFile"></td>
</tr> </tr>
</tr>
<tr> <tr>
<td width="1%"> <td width="1%"><input type="radio" name="exporttofile" value="false" <%= !exportToFile ? "checked" : "" %> id="rb02"></td>
<input type="radio" name="exporttofile" value="false" <%= !exportToFile ? "checked" : "" %> id="rb02"> <td width="99%"><label for="rb02"><b>To Screen</b></label> - Display user data in the text area below.</td>
</td>
<td width="99%">
<label for="rb02"><b>To Screen</b></label> - Display user data in the text area below.
</td>
</tr> </tr>
<tr> <tr>
<td width="1%">&nbsp;</td> <td width="1%">&nbsp;</td>
<td width="99%"> <td width="99%"><textarea cols="80" rows="20" wrap=off><%=exportText %></textarea></td>
<textarea cols="80" rows="20" wrap=off><%=exportText %></textarea>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</fieldset> </fieldset>
<br><br> <br><br>
<input type="submit" value="Export"> <input type="submit" value="Export">
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
<% if (plugin.isUserProviderReadOnly()) { %> <% if (plugin.isUserProviderReadOnly()) { %>
Sorry, because you are using LDAP as your user store this plugin will not work with your Messenger installation. Sorry, because you are using LDAP as your user store, this plugin will not work with your Messenger installation.
<% } else { %> <% } else { %>
......
<%@ page import="java.io.IOException, <%@ page import="java.net.MalformedURLException,
java.net.MalformedURLException,
java.util.*, java.util.*,
org.dom4j.DocumentException, org.dom4j.DocumentException,
org.apache.commons.fileupload.DiskFileUpload,
org.apache.commons.fileupload.FileItem,
org.jivesoftware.admin.AdminPageBean, org.jivesoftware.admin.AdminPageBean,
org.jivesoftware.messenger.plugin.ImportExportPlugin, org.jivesoftware.messenger.plugin.ImportExportPlugin,
org.jivesoftware.messenger.XMPPServer,
org.jivesoftware.util.ParamUtils" org.jivesoftware.util.ParamUtils"
%> %>
<jsp:useBean id="admin" class="org.jivesoftware.util.WebManager" /> <jsp:useBean id="admin" class="org.jivesoftware.util.WebManager" />
<c:set var="admin" value="${admin.manager}" /> <%
<% admin.init(request, response, session, application, out); admin.init(request, response, session, application, out);
boolean importUsers = request.getParameter("importUsers") != null; boolean importUsers = request.getParameter("importUsers") != null;
boolean success = request.getParameter("success") != null; boolean success = request.getParameter("success") != null;
ImportExportPlugin plugin = (ImportExportPlugin) XMPPServer.getInstance().getPluginManager().getPlugin("userimportexport"); ImportExportPlugin plugin = (ImportExportPlugin) admin.getXMPPServer().getPluginManager().getPlugin("userimportexport");
List duplicateUsers = new ArrayList(); List<String> duplicateUsers = new ArrayList<String>();
Map errors = new HashMap(); Map<String, String> errors = new HashMap<String, String>();
if (importUsers) { if (importUsers) {
String file = ParamUtils.getParameter(request, "importFile"); DiskFileUpload dfu = new DiskFileUpload();
if ((file == null) || (file.length() <= 0)) {
errors.put("badFile", "badFile"); List fileItems = dfu.parseRequest(request);
Iterator i = fileItems.iterator();
FileItem fi = (FileItem) i.next();
FileItem pd = (FileItem) i.next();
String previousDomain = pd.getString();
try {
if (isEmpty(previousDomain)) {
duplicateUsers.addAll(plugin.importUserData(fi, null));
}
else if (!isEmpty(previousDomain)) {
duplicateUsers.addAll(plugin.importUserData(fi, previousDomain));
} }
else { else {
try { errors.put("missingDomain", "missingDomain");
//todo this could take some, redirect to a progress page? }
if (plugin.validateImportFile(file)) {
duplicateUsers.addAll(plugin.importUserData(file));
if (duplicateUsers.size() == 0) { if (duplicateUsers.size() == 0) {
response.sendRedirect("import-user-data.jsp?success=true"); response.sendRedirect("import-user-data.jsp?success=true");
return; return;
} }
errors.put("userAlreadyExists", "userAlreadyExists"); errors.put("userAlreadyExists", "userAlreadyExists");
}
else {
errors.put("invalidUserFile", "invalidUserFile");
}
} }
catch (MalformedURLException e) { catch (MalformedURLException e) {
errors.put("MalformedURLException", "MalformedURLException"); errors.put("IOException", "IOException");
} }
catch (DocumentException e) { catch (DocumentException e) {
errors.put("DocumentException", "DocumentException"); errors.put("DocumentException", "DocumentException");
} }
} }
}
%> %>
<jsp:useBean id="pageinfo" scope="request" class="org.jivesoftware.admin.AdminPageBean" /> <jsp:useBean id="pageinfo" scope="request" class="org.jivesoftware.admin.AdminPageBean" />
...@@ -70,7 +74,9 @@ ...@@ -70,7 +74,9 @@
<tr> <tr>
<td class="jive-icon"><img src="images/error-16x16.gif" width="16" height="16" border="0"></td> <td class="jive-icon"><img src="images/error-16x16.gif" width="16" height="16" border="0"></td>
<td class="jive-icon-label"> <td class="jive-icon-label">
<% if (errors.containsKey("MalformedURLException") || errors.containsKey("badFile")) { %> <% if (errors.containsKey("missingDomain")) { %>
You must supply both a existing and new domain name.
<% } else if (errors.containsKey("IOException")) { %>
Missing or bad file name. Missing or bad file name.
<% } else if (errors.containsKey("DocumentException")) { %> <% } else if (errors.containsKey("DocumentException")) { %>
Import failed. Import failed.
...@@ -113,34 +119,41 @@ ...@@ -113,34 +119,41 @@
<% } %> <% } %>
<form action="import-user-data.jsp?importUsers" method="post" enctype="multipart/form-data">
<form action="import-user-data.jsp?importUsers" method="post"> <fieldset>
<legend>Import</legend>
<div>
<p>
Use the Browse button to select the file that conatians the Jive Messenger user data to be imported, then click on the Import button.
</p>
<input type="file" name="thefile"><input type="submit" value="Import">
<div class="jive-table"> <br><br><br>
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<thead> <p>
<tr> <b>Optional</b> - Use the field below to replace the domain name of user roster entries with the current hostname.
<th>Import Properties</th> See the migration section of the <a href="../../plugin-admin.jsp?plugin=userimportexport&showReadme=true">readme</a> for details.
</tr> </p>
</thead> Existing Domain:<input type="text" size="20" maxlength="150" name="previousDomain" value=""/>
<tr class="jive-even">
<td style="border-right:1px #ccc solid;">Import Location:</td>
</tr>
<tr class="jive-odd">
<td style="border-right:1px #ccc solid;"><%= plugin.exportDirectory() %></td>
</tr>
<tr class="jive-even">
<td style="border-right:1px #ccc solid;">Import File Name:</td>
</tr>
<tr class="jive-odd">
<td style="border-right:1px #ccc solid;"><input type="text" size="30" maxlength="150" name="importFile"></td>
</tr>
</table>
</div>
<br><br> </div>
</fieldset>
<input type="submit" value="Import">
</form> </form>
<jsp:include page="bottom.jsp" flush="true" /> <jsp:include page="bottom.jsp" flush="true" />
<%!
public boolean isEmpty(String s) {
if (s == null) {
return true;
}
if (s.trim().length() == 0) {
return true;
}
return false;
}
%>
Markdown is supported
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