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,41 +2,46 @@ ...@@ -2,41 +2,46 @@
<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 {
font-family : tahoma, verdana, arial, helvetica, sans-serif; BODY, TD, TH {
font-size : 0.8em; font-family : tahoma, verdana, arial, helvetica, sans-serif;
} font-size : 0.8em;
H2 { }
font-size : 10pt;
font-weight : bold; H2 {
padding-left : 1em; font-size : 10pt;
} font-weight : bold;
A:hover { padding-left : 1em;
text-decoration : none; }
}
H1 { A:hover {
font-family : tahoma, arial, helvetica, sans-serif; text-decoration : none;
font-size : 1.4em; }
font-weight: bold;
border-bottom : 1px #ccc solid; H1 {
padding-bottom : 2px; font-family : tahoma, arial, helvetica, sans-serif;
} font-size : 1.4em;
font-weight: bold;
border-bottom : 1px #ccc solid;
padding-bottom : 2px;
}
TT { TT {
font-family : courier new; font-family : courier new;
font-weight : bold; font-weight : bold;
color : #060; color : #060;
} }
PRE {
font-family : courier new; PRE {
font-size : 100%; font-family : courier new;
} font-size : 100%;
</style> }
</style>
</head> </head>
<body> <body>
...@@ -44,11 +49,18 @@ ...@@ -44,11 +49,18 @@
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>
<li>Fixed compatibility issue with Messenger version 2.1.4 and 2.1.5.</li> <li>Fixed compatibility issue with Messenger version 2.1.4 and 2.1.5.</li>
<li>Refactored the code that creates the output directory to try and alleviate permission issues on Unix installations.</li> <li>Refactored the code that creates the output directory to try and alleviate permission issues on Unix installations.</li>
</ul> </ul>
<p><b>1.0</b> -- June 1, 2005</p> <p><b>1.0</b> -- June 1, 2005</p>
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<plugin> <plugin>
<class>org.jivesoftware.messenger.plugin.ImportExportPlugin</class> <class>org.jivesoftware.messenger.plugin.ImportExportPlugin</class>
<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">
<sidebar id="user-import-export" name="Import &amp; Export"> <sidebar id="user-import-export" name="Import &amp; Export">
<item id="import-export-selection" name="User Import &amp; Export" <item id="import-export-selection" name="User Import &amp; Export"
url="import-export-selection.jsp" url="import-export-selection.jsp"
description="Allows the importing and exporting of Messenger user data." /> description="Allows the importing and exporting of Messenger user data." />
</sidebar> </sidebar>
</tab> </tab>
</adminconsole> </adminconsole>
</plugin> </plugin>
\ No newline at end of file
...@@ -2,89 +2,284 @@ ...@@ -2,89 +2,284 @@
<html> <html>
<head> <head>
<title>User Import/Export Plugin Readme</title> <title>User Import/Export Plugin Readme</title>
<style type="text/css"> <style type="text/css">
BODY { BODY {
font-size : 100%; font-size : 100%;
} }
BODY, TD, TH {
font-family : tahoma, verdana, arial, helvetica, sans-serif; BODY, TD, TH {
font-size : 0.8em; font-family : tahoma, verdana, arial, helvetica, sans-serif;
} font-size : 0.8em;
H2 { }
font-size : 10pt;
font-weight : bold; H2 {
} font-size : 11pt;
A:hover { font-weight : bold;
text-decoration : none; }
}
H1 { A:hover {
font-family : tahoma, arial, helvetica, sans-serif; text-decoration : none;
font-size : 1.4em; }
font-weight: bold;
border-bottom : 1px #ccc solid; H1 {
padding-bottom : 2px; font-family : tahoma, arial, helvetica, sans-serif;
} font-size : 1.4em;
font-weight: bold;
TT { border-bottom : 1px #ccc solid;
font-family : courier new; padding-bottom : 2px;
font-weight : bold; }
color : #060;
} TT {
PRE { font-family : courier new;
font-family : courier new; font-weight : bold;
font-size : 100%; color : #060;
} }
</style>
PRE {
font-family : courier new;
font-size : 100%;
}
#datatable TH {
color : #fff;
background-color : #2A448C;
text-align : left;
}
#datatable TD {
background-color : #FAF6EF;
}
#datatable .name {
background-color : #DCE2F5;
text-align : center;
}
</style>
</head> </head>
<body> <body>
<h1>User Import/Export Plugin Readme</h1> <h1>User Import/Export Plugin Readme</h1>
<h2>Overview</h2> <h2>Overview</h2>
<p>The user import/export plugin provides a way to import and export Jive Messenger <p>The user import/export plugin provides a way to import and export Jive Messenger user data via
user data via the Admin Console. The user data consists of jid (aka "username"), the Admin Console. The user data consists of jid (aka "username"), name, email address, password
name, email address, password and roster list (aka "buddy list"). This plugin also and roster list (aka "buddy list"). This plugin also can aid in the migration of users from other
can aid in the migration of users from other Jabber/XMPP based systems to Jive Jabber/XMPP based systems to Jive Messenger.</p>
Messenger.</p>
<h2>Installation</h2> <h2>Installation</h2>
<p>Copy the userImportExport.jar into the plugins directory of your Jive Messenger <p>Copy the userImportExport.jar into the plugins directory of your Jive Messenger installation.
installation. The plugin will then be automatically deployed. To upgrade to a new The plugin will then be automatically deployed. To upgrade to a new version, copy the new
version, copy the new userImportExport.jar file over the existing file.</p> userImportExport.jar file over the existing file.</p>
<h2>Configuration</h2> <h2>Configuration</h2>
<p>Presently, there is nothing that can be configured for the user import/export plugin.</p> <p>Presently, there is nothing that can be configured for the user import/export plugin.</p>
<h2>Using the Plugin</h2> <h2>Using the Plugin</h2>
<p> The plugin is accessed via the "User Import & Export" sidebar item located under <p>The plugin is accessed via the "User Import & Export" sidebar item located under the
the "Users/Groups" tab in the Admin Console. Note: if you are using LDAP as your user "Users/Groups" tab in the Admin Console. Note: if you are using LDAP as your user data source the
data source the following message will appear: "Sorry, because you are using LDAP as following message will appear: "Sorry, because you are using LDAP as your user store this plugin
your user store this plugin will not work with your Messenger installation." will not work with your Messenger installation."
<li>Importing - Select the "Import User Data" option from the user import/export
selection page. On the import page, notice that the plugin will look for user data <li><b>Importing</b> - Select the "Import User Data" option from the user import/export selection
import files in the MESSENGER_HOME/export directory. In the "Import File Name" field, page. On the import page, use the "Browse" button to locate the file that contains the user
enter the name of the file you want import from and then click on the "Import" button. information you want to locate and then click on the "Import" button. If the plugin is successful
If the plugin is successful in importing all user data, you will be presented with the in importing all user data, you will be presented with the message: "All users added successfully".
message: "All users added successfully" If the plugin was not successful in importing If the plugin was not successful in importing all user data you, will receive a message indicating
all user data you, will receive a message indicating what might have gone wrong. If what might have gone wrong. If during the import process, the plugin detects that you are trying to
during the import process, the plugin detects that you are trying to import a user import a user that already exists in the system, it will not import that user or any roster
that already exists in the system, it will not import that user or any roster
information.</li> information.</li>
<li>Exporting - Select the "Export User Data" option from the user import/export <br>
selection page. User data can be exported either to a file or directly to the screen. <li><b>Exporting</b> - Select the "Export User Data" option from the user import/export selection
To export to a file, select the "To File" radio button. Notice that the plugin will page. User data can be exported either to a file or directly to the screen. To export to a file,
export user data to the MESSENGER_HOME/export directory. In the "Export File Name" select the "To File" radio button, enter the name you want your export file to be called in the
field, enter the name of the file you want export to and then click on the "Export" "Export File Name" and then click on the "Export" button. Note: the plugin will automatically append
button. Note: the plugin will automatically append an ".xml" extension to the file an ".xml" extension to the file name if it is not already present. To export to the screen, select
name if it is not already present. To export to the screen, select the "To Screen" the "To Screen" radio button and then click on the "Export" button. The user data will be placed in
radio button and then click on the "Export" button. The user data will be placed in
the provided text area.</li> the provided text area.</li>
<li>Migration - To import user data from another instant messenger system using the <br>
plugin, the import file must conform to the messenger-user-schema.xsd.xml schema file <li><b>Migration</b> - To import user data from another instant messenger system using the plugin,
(located in the classes directory). When importing a user data file the plugin will the import file must conform to the messenger-user-schema.xsd.xml schema file (located in the classes
first validate the file against the schema file." If the plugin cannot validate the directory of the userImportExport.jar). When importing a user data file the plugin will first validate
import file the user data will not be imported.</li> the file against the schema file." If the plugin cannot validate the import file the user data will
not be imported. During the import process the plugin gives you the ability to update user roster
entries domain names to server name of your Messenger installation. For example, say you have a user
whose roster looks like: <br>
<br>
<textarea cols=95 rows=16>
<User>
<Username>mike</Username>
<Password>iamcool</Password>
<Email>mike@mike.com</Email>
<Name>Mike Jones</Name>
<CreationDate>1125442154664</CreationDate>
<ModifiedDate>1125442154664</ModifiedDate>
<Roster>
<Item jid="jane@im.olddomain.net" askstatus="-1" recvstatus="-1" substatus="3" name="Jane">
<Group></Group>
</Item>
<Item jid="paul@xyz.net" askstatus="-1" recvstatus="-1" substatus="3" name="Paul">
<Group></Group>
</Item>
</Roster>
</User>
</textarea>
<br>
<br>
Mike and Jane's accounts both reside on server whose domain name is "im.olddomain.net" and are being
imported to a Messenger installation whose server name is "im.newdomain.net". If on the import screen
the "Optional Existing Domain" field is filled in with "im.olddomain.net" (without the quotes) any
roster item jid that contains "im.olddomain.net" will be replaced with "im.newdomain.net". So, in
effect, the import file would be transformed to look like:
<br>
<br>
<textarea cols=95 rows=16>
<User>
<Username>mike</Username>
<Password>iamcool</Password>
<Email>mike@mike.com</Email>
<Name>Mike Jones</Name>
<CreationDate>1125442154664</CreationDate>
<ModifiedDate>1125442154664</ModifiedDate>
<Roster>
<Item jid="jane@im.newdomain.net" askstatus="-1" recvstatus="-1" substatus="3" name="Jane">
<Group></Group>
</Item>
<Item jid="paul@xyz.net" askstatus="-1" recvstatus="-1" substatus="3" name="Paul">
<Group></Group>
</Item>
</Roster>
</User>
</textarea></li>
</p>
<br>
<br>
Below is a sample of an exported user list from Messenger than contains two users, Joe and Sally, who
have added each other to their respective rosters.
<br>
<br>
<textarea cols=95 rows=16>
<?xml version="1.0" encoding="UTF-8"?>
<JiveMessenger>
<User>
<Username>joe</Username>
<Password>joepwd</Password>
<Email></Email>
<Name></Name>
<CreationDate>1125601449177</CreationDate>
<ModifiedDate>1125601449177</ModifiedDate>
<Roster>
<Item jid="sally@localhost" askstatus="-1" recvstatus="-1" substatus="3" name="Sally">
<Group/>
</Item>
</Roster>
</User>
<User>
<Username>sally</Username>
<Password>sallypwd</Password>
<Email></Email>
<Name></Name>
<CreationDate>1125601471848</CreationDate>
<ModifiedDate>1125601471848</ModifiedDate>
<Roster>
<Item jid="joe@localhost" askstatus="-1" recvstatus="-1" substatus="3">
<Group/>
</Item>
</Roster>
</User>
</JiveMessenger>
</textarea></li>
</p> </p>
<br>
<br>
Below is a list of the different status types and what their associated numbers mean.
<br>
<br>
<div id="datatable">
<table cellpadding="3" cellspacing="1" border="0" width="700">
<thead>
<tr>
<th colspan="2">askstatus</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name">-1</td>
<td>The roster item has no pending subscripton requests.</td>
</tr>
<tr>
<td class="name">0</td>
<td>The roster item has been asked for permission to subscribe to their presence but no
response has been received.</td>
</tr>
<tr>
<td class="name">1</td>
<td>The roster owner has asked to the roster item to unsubscribe from it's presence but
has not received confirmation.</td>
</tr>
</tbody>
</table>
<br>
<table cellpadding="3" cellspacing="1" border="0" width="700">
<thead>
<tr>
<th colspan="2">recvstatus</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name">-1</td>
<td>There are no subscriptions that have been received but not presented to the user.</td>
</tr>
<tr>
<td class="name">1</td>
<td>The server has received a subscribe request, but has not forwarded it to the user.</td>
</tr>
<tr>
<td class="name">2</td>
<td>The server has received an unsubscribe request, but has not forwarded it to the user.</td>
</tr>
</tbody>
</table>
<br>
<table cellpadding="3" cellspacing="1" border="0" width="700">
<thead>
<tr>
<th colspan="2">substatus</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name">-1</td>
<td>Indicates the roster item should be removed.</td>
</tr>
<tr>
<td class="name">0</td>
<td>No subscription is established.</td>
</tr>
<tr>
<td class="name">1</td>
<td>The roster owner has a subscription to the roster item's presence.</td>
</tr>
<tr>
<td class="name">2</td>
<td>The roster item has a subscription to the roster owner's presence.</td>
</tr>
<tr>
<td class="name">3</td>
<td>The roster item and owner have a mutual subscription.</td>
</tr>
</tbody>
</table>
</div>
</body> </body>
</html> </html>
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"),
...@@ -44,37 +43,16 @@ import org.xmpp.packet.JID; ...@@ -44,37 +43,16 @@ import org.xmpp.packet.JID;
* @author Ryan Graham * @author Ryan Graham
*/ */
public class ImportExportPlugin implements Plugin { public class ImportExportPlugin implements Plugin {
private UserManager userManager; private UserManager userManager;
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,98 +62,56 @@ public class ImportExportPlugin implements Plugin { ...@@ -84,98 +62,56 @@ 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.write(exportUsers());
writer = new XMLWriter(new FileWriter(exportFilePath), OutputFormat.createPrettyPrint());
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 {
StringWriter stringWriter = new StringWriter(); StringWriter stringWriter = new StringWriter();
XMLWriter writer = null; XMLWriter writer = null;
try { try {
writer = new XMLWriter(stringWriter, OutputFormat.createPrettyPrint()); writer = new XMLWriter(stringWriter, OutputFormat.createPrettyPrint());
writer.write(exportUsers()); writer.write(exportUsers());
} catch (IOException ioe) { } catch (IOException ioe) {
Log.error(ioe); Log.error(ioe);
throw ioe; throw ioe;
} finally { } finally {
if (writer != null) { if (writer != null) {
writer.close(); writer.close();
} }
} }
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() {
Document document = DocumentHelper.createDocument(); Document document = DocumentHelper.createDocument();
Element root = document.addElement("JiveMessenger"); Element root = document.addElement("JiveMessenger");
Collection<User> users = userManager.getUsers(); Collection<User> users = userManager.getUsers();
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 {
userElement.addElement("Password").addText(provider.getPassword(user.getUsername())); userElement.addElement("Password").addText(provider.getPassword(user.getUsername()));
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
...@@ -183,51 +119,41 @@ public class ImportExportPlugin implements Plugin { ...@@ -183,51 +119,41 @@ public class ImportExportPlugin implements Plugin {
Log.info("User not found: " + userName + ", setting password to their username"); Log.info("User not found: " + userName + ", setting password to their username");
userElement.addElement("Password").addText(userName); userElement.addElement("Password").addText(userName);
} }
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) { userElement.addElement("Name").addText(name == null ? "" : name);
// try {
// name = URLEncoder.encode(name, "UTF-8");
// } catch (UnsupportedEncodingException e) {
// Log.error(e);
// name = "";
// }
// } else {
// 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
//for historical purposes, should they be formatted differently? //for historical purposes, should they be formatted differently?
userElement.addElement("CreationDate").addText(String.valueOf(user.getCreationDate().getTime())); userElement.addElement("CreationDate").addText(String.valueOf(user.getCreationDate().getTime()));
userElement.addElement("ModifiedDate").addText(String.valueOf(user.getModificationDate().getTime())); userElement.addElement("ModifiedDate").addText(String.valueOf(user.getModificationDate().getTime()));
Element rosterElement = userElement.addElement("Roster"); Element rosterElement = userElement.addElement("Roster");
Collection<RosterItem> roster = user.getRoster().getRosterItems(); Collection<RosterItem> roster = user.getRoster().getRosterItems();
for (RosterItem ri : roster) { for (RosterItem ri : roster) {
Element itemElement = rosterElement.addElement("Item"); Element itemElement = rosterElement.addElement("Item");
itemElement.addAttribute("jid", ri.getJid().toBareJID()); itemElement.addAttribute("jid", ri.getJid().toBareJID());
itemElement.addAttribute("askstatus", String.valueOf(ri.getAskStatus().getValue())); itemElement.addAttribute("askstatus", String.valueOf(ri.getAskStatus().getValue()));
itemElement.addAttribute("recvstatus", String.valueOf(ri.getRecvStatus().getValue())); itemElement.addAttribute("recvstatus", String.valueOf(ri.getRecvStatus().getValue()));
itemElement.addAttribute("substatus", String.valueOf(ri.getSubStatus().getValue())); itemElement.addAttribute("substatus", String.valueOf(ri.getSubStatus().getValue()));
itemElement.addAttribute("name", ri.getNickname()); itemElement.addAttribute("name", ri.getNickname());
Element groupElement = itemElement.addElement("Group"); Element groupElement = itemElement.addElement("Group");
List<String> groups = ri.getGroups(); List<String> groups = ri.getGroups();
for (String group : groups) { for (String group : groups) {
groupElement.addText(group); groupElement.addText(group);
} }
} }
} }
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();
RosterItemProvider rosterItemProvider = RosterItemProvider.getInstance(); RosterItemProvider rosterItemProvider = RosterItemProvider.getInstance();
Map<String, List> rosterMap = new HashMap<String, List>(); Map<String, List> rosterMap = new HashMap<String, List>();
...@@ -239,19 +165,19 @@ public class ImportExportPlugin implements Plugin { ...@@ -239,19 +165,19 @@ public class ImportExportPlugin implements Plugin {
Element user = (Element) usersIter.next(); Element user = (Element) usersIter.next();
String userName = null; String userName = null;
String password = null; String password = null;
String email = null; String email = null;
String name = null; String name = null;
List<RosterItem> rosterItems = new ArrayList<RosterItem>(); List<RosterItem> rosterItems = new ArrayList<RosterItem>();
Iterator userElements = user.elementIterator(); Iterator userElements = user.elementIterator();
while (userElements.hasNext()) { while (userElements.hasNext()) {
Element userElement = (Element) userElements.next(); Element userElement = (Element) userElements.next();
String nameElement = userElement.getName(); String nameElement = userElement.getName();
if ("Username".equals(nameElement)) { if ("Username".equals(nameElement)) {
userName = userElement.getText(); userName = userElement.getText();
} }
else if ("Password".equals(nameElement)) { else if ("Password".equals(nameElement)) {
password = userElement.getText(); password = userElement.getText();
...@@ -260,7 +186,7 @@ public class ImportExportPlugin implements Plugin { ...@@ -260,7 +186,7 @@ public class ImportExportPlugin implements Plugin {
name = userElement.getText(); name = userElement.getText();
} }
else if ("Email".equals(nameElement)) { else if ("Email".equals(nameElement)) {
email = userElement.getText(); email = userElement.getText();
} }
else if ("Roster".equals(nameElement)) { else if ("Roster".equals(nameElement)) {
Iterator rosterIter = userElement.elementIterator("Item"); Iterator rosterIter = userElement.elementIterator("Item");
...@@ -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)),
...@@ -292,14 +223,14 @@ public class ImportExportPlugin implements Plugin { ...@@ -292,14 +223,14 @@ public class ImportExportPlugin implements Plugin {
} }
if ((userName != null) && (password != null)) { if ((userName != null) && (password != null)) {
try { try {
userManager.createUser(userName, password, name, email); userManager.createUser(userName, password, name, email);
rosterMap.put(userName, rosterItems); rosterMap.put(userName, rosterItems);
} }
catch (UserAlreadyExistsException e) { catch (UserAlreadyExistsException e) {
Log.info("User already exists: " + userName); Log.info("User already exists: " + userName);
duplicateUsers.add(userName); duplicateUsers.add(userName);
} }
} }
} }
...@@ -329,7 +260,7 @@ public class ImportExportPlugin implements Plugin { ...@@ -329,7 +260,7 @@ public class ImportExportPlugin implements Plugin {
} }
return duplicateUsers; return duplicateUsers;
} }
private static String removeDoman(JID jid) { private static String removeDoman(JID jid) {
StringTokenizer tokens = new StringTokenizer(jid.toBareJID(), "@"); StringTokenizer tokens = new StringTokenizer(jid.toBareJID(), "@");
...@@ -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;
......
<%@ page import="java.io.IOException, <%@ page import="java.io.IOException,
java.util.*, java.util.*,
org.jivesoftware.admin.AdminPageBean, org.jivesoftware.admin.AdminPageBean,
org.jivesoftware.messenger.plugin.ImportExportPlugin, org.jivesoftware.messenger.plugin.ImportExportPlugin,
org.jivesoftware.messenger.XMPPServer, org.jivesoftware.messenger.XMPPServer,
org.jivesoftware.util.ParamUtils" org.jivesoftware.util.ParamUtils"
%> %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<jsp:useBean id="admin" class="org.jivesoftware.util.WebManager" /> <jsp:useBean id="admin" class="org.jivesoftware.util.WebManager" />
<% <%
admin.init(request, response, session, application, out); admin.init(request, response, session, application, out);
boolean exportUsers = request.getParameter("exportUsers") != null; boolean exportUsers = request.getParameter("exportUsers") != null;
boolean success = request.getParameter("success") != null; boolean success = request.getParameter("success") != null;
...@@ -21,41 +21,28 @@ ...@@ -21,41 +21,28 @@
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");
if ((file == null) || (file.length() <= 0)) { if ((file == null) || (file.length() <= 0)) {
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 {
try { try {
exportText = plugin.exportUsersToString(); exportText = plugin.exportUsersToString();
}
catch (IOException e) {
errors.put("IOException","IOException");
} }
catch (IOException e) {
errors.put("IOException","IOException");
}
} }
} }
%> %>
<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";
...@@ -73,14 +60,14 @@ ...@@ -73,14 +60,14 @@
<table cellpadding="0" cellspacing="0" border="0"> <table cellpadding="0" cellspacing="0" border="0">
<tbody> <tbody>
<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("missingFile")) { %> <% if (errors.containsKey("missingFile")) { %>
Missing or bad file name. Missing or bad file name.
<% } else if (errors.containsKey("IOException") || errors.containsKey("fileNotCreated")) { %> <% } else if (errors.containsKey("IOException") || errors.containsKey("fileNotCreated")) { %>
Couldn't create export file. Couldn't create export file.
<% } %> <% } %>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -93,8 +80,8 @@ ...@@ -93,8 +80,8 @@
<table cellpadding="0" cellspacing="0" border="0"> <table cellpadding="0" cellspacing="0" border="0">
<tbody> <tbody>
<tr> <tr>
<td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0"></td> <td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0"></td>
<td class="jive-icon-label">User data successfully exported.</td> <td class="jive-icon-label">User data successfully exported.</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -107,49 +94,37 @@ ...@@ -107,49 +94,37 @@
<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>
<td width="1%">&nbsp;</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%">&nbsp;</td>
<input type="radio" name="exporttofile" value="false" <%= !exportToFile ? "checked" : "" %> id="rb02"> <td width="99%">Export File Name:&nbsp;<input type="text" size="30" maxlength="150" name="exportFile"></td>
</td> </tr>
<td width="99%"> <tr>
<label for="rb02"><b>To Screen</b></label> - Display user data in the text area below. <td width="1%"><input type="radio" name="exporttofile" value="false" <%= !exportToFile ? "checked" : "" %> id="rb02"></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">
</form> </form>
<jsp:include page="bottom.jsp" flush="true" /> <jsp:include page="bottom.jsp" flush="true" />
\ No newline at end of file
<%@ page import="org.jivesoftware.admin.AdminPageBean, <%@ page import="org.jivesoftware.admin.AdminPageBean,
org.jivesoftware.messenger.plugin.ImportExportPlugin, org.jivesoftware.messenger.plugin.ImportExportPlugin,
org.jivesoftware.messenger.XMPPServer" org.jivesoftware.messenger.XMPPServer"
%> %>
<jsp:useBean id="pageinfo" scope="request" class="org.jivesoftware.admin.AdminPageBean" /> <jsp:useBean id="pageinfo" scope="request" class="org.jivesoftware.admin.AdminPageBean" />
...@@ -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 { %>
...@@ -28,10 +28,10 @@ The import and export functions allow you to read data into and write user ...@@ -28,10 +28,10 @@ The import and export functions allow you to read data into and write user
data from your Jive Messenger installation. data from your Jive Messenger installation.
<ul> <ul>
<li><a href="import-user-data.jsp">Import User Data</a></li> <li><a href="import-user-data.jsp">Import User Data</a></li>
<li><a href="export-user-data.jsp">Export User Data</a></li> <li><a href="export-user-data.jsp">Export User Data</a></li>
</ul> </ul>
<% } %> <% } %>
<jsp:include page="bottom.jsp" flush="true" /> <jsp:include page="bottom.jsp" flush="true" />
\ No newline at end of file
<%@ 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.jivesoftware.admin.AdminPageBean, org.apache.commons.fileupload.FileItem,
org.jivesoftware.messenger.plugin.ImportExportPlugin, org.jivesoftware.admin.AdminPageBean,
org.jivesoftware.messenger.XMPPServer, org.jivesoftware.messenger.plugin.ImportExportPlugin,
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 {
errors.put("missingDomain", "missingDomain");
}
if (duplicateUsers.size() == 0) {
response.sendRedirect("import-user-data.jsp?success=true");
return;
}
errors.put("userAlreadyExists", "userAlreadyExists");
}
catch (MalformedURLException e) {
errors.put("IOException", "IOException");
} }
else { catch (DocumentException e) {
try { errors.put("DocumentException", "DocumentException");
//todo this could take some, redirect to a progress page? }
if (plugin.validateImportFile(file)) { }
duplicateUsers.addAll(plugin.importUserData(file));
if (duplicateUsers.size() == 0) {
response.sendRedirect("import-user-data.jsp?success=true");
return;
}
errors.put("userAlreadyExists", "userAlreadyExists");
}
else {
errors.put("invalidUserFile", "invalidUserFile");
}
}
catch (MalformedURLException e) {
errors.put("MalformedURLException", "MalformedURLException");
}
catch (DocumentException e) {
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" />
...@@ -64,35 +68,37 @@ ...@@ -64,35 +68,37 @@
<% if (errors.size() > 0) { %> <% if (errors.size() > 0) { %>
<div class="jive-error"> <div class="jive-error">
<table cellpadding="0" cellspacing="0" border="0"> <table cellpadding="0" cellspacing="0" border="0">
<tbody> <tbody>
<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")) { %>
Missing or bad file name. You must supply both a existing and new domain name.
<% } else if (errors.containsKey("DocumentException")) { %> <% } else if (errors.containsKey("IOException")) { %>
Import failed. Missing or bad file name.
<% } else if (errors.containsKey("invalidUserFile")) { %> <% } else if (errors.containsKey("DocumentException")) { %>
The import file does not match the user schema. Import failed.
<% } else if (errors.containsKey("userAlreadyExists")) { %> <% } else if (errors.containsKey("invalidUserFile")) { %>
The following users are already exist in the system and were not loaded:<br> The import file does not match the user schema.
<% <% } else if (errors.containsKey("userAlreadyExists")) { %>
Iterator iter = duplicateUsers.iterator(); The following users are already exist in the system and were not loaded:<br>
while (iter.hasNext()) { <%
String username = (String) iter.next(); Iterator iter = duplicateUsers.iterator();
%><%= username %><% while (iter.hasNext()) {
if (iter.hasNext()) { String username = (String) iter.next();
%>,&nbsp;<% %><%= username %><%
} else { if (iter.hasNext()) {
%>.<% %>,&nbsp;<%
} } else {
} %>.<%
} %> }
</td> }
} %>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<br> <br>
...@@ -101,46 +107,53 @@ ...@@ -101,46 +107,53 @@
<div class="jive-success"> <div class="jive-success">
<table cellpadding="0" cellspacing="0" border="0"> <table cellpadding="0" cellspacing="0" border="0">
<tbody> <tbody>
<tr> <tr>
<td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0"></td> <td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0"></td>
<td class="jive-icon-label">All users added successfully.</td> <td class="jive-icon-label">All users added successfully.</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<br> <br>
<% } %> <% } %>
<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 class="jive-table"> <div>
<table cellpadding="0" cellspacing="0" border="0" width="100%"> <p>
<thead> Use the Browse button to select the file that conatians the Jive Messenger user data to be imported, then click on the Import button.
<tr> </p>
<th>Import Properties</th> <input type="file" name="thefile"><input type="submit" value="Import">
</tr>
</thead> <br><br><br>
<tr class="jive-even">
<td style="border-right:1px #ccc solid;">Import Location:</td> <p>
</tr> <b>Optional</b> - Use the field below to replace the domain name of user roster entries with the current hostname.
<tr class="jive-odd"> See the migration section of the <a href="../../plugin-admin.jsp?plugin=userimportexport&showReadme=true">readme</a> for details.
<td style="border-right:1px #ccc solid;"><%= plugin.exportDirectory() %></td> </p>
</tr> Existing Domain:<input type="text" size="20" maxlength="150" name="previousDomain" value=""/>
<tr class="jive-even">
<td style="border-right:1px #ccc solid;">Import File Name:</td> </div>
</tr> </fieldset>
<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>
<input type="submit" value="Import">
</form> </form>
<jsp:include page="bottom.jsp" flush="true" /> <jsp:include page="bottom.jsp" flush="true" />
\ No newline at end of file
<%!
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