Package net.processone.plugin.openfire

Source Code of net.processone.plugin.openfire.ExporterXEP227

package net.processone.plugin.openfire;

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.Iterator;
import java.util.List;

import org.apache.commons.fileupload.FileItem;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.jivesoftware.openfire.OfflineMessage;
import org.jivesoftware.openfire.OfflineMessageStore;
import org.jivesoftware.openfire.PrivateStorage;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterItemProvider;
import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserAlreadyExistsException;
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.openfire.user.UserProvider;
import org.jivesoftware.openfire.vcard.VCardManager;
import org.jivesoftware.stringprep.Stringprep;
import org.jivesoftware.stringprep.StringprepException;
import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;

/**
* <p>
* The user import/export plugin provides a way to import and export Openfire
* user data via the Admin Console. This plugin is XEP-0227 compliant
* </p>
* This plugin can export: <li>User data</li> <li>vCard</li> <li>Offline
* messages</li> <br/>
* <p>
* <b>See also:</b> {@link List http://xmpp.org/extensions/xep-0227.html}
* </p>
*
* @author <a href="mailto:smartinez@process-one.net">Vidal Santiago
*         Martinez</a>
*/
public class ExporterXEP227 implements Plugin {
 
  private static final String LOAD_ALL_PRIVATE = "SELECT privateData FROM ofPrivate WHERE username=?";
 
  private UserManager userManager;
  private UserProvider provider;
  private String serverName;
  private OfflineMessageStore offlineMessagesStore;
  private VCardManager vCardManager;
  private PrivateStorage privateStorage;

 
  public ExporterXEP227() {
    userManager = XMPPServer.getInstance().getUserManager();
    offlineMessagesStore = XMPPServer.getInstance()
        .getOfflineMessageStore();
    provider = UserManager.getUserProvider();
    serverName = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
    privateStorage = XMPPServer.getInstance().getPrivateStorage();
    vCardManager = VCardManager.getInstance();
  }

  public void initializePlugin(PluginManager manager, File pluginDirectory) {
  }

  public void destroyPlugin() {
    userManager = null;
    provider = null;
    serverName = null;
    offlineMessagesStore = null;
  }

  /**
   * Convenience method that returns true if this UserProvider is read-only.
   *
   * @return true if the user provider is read-only.
   */
  public boolean isUserProviderReadOnly() {
    return provider.isReadOnly();
  }

  /**
   * Converts the user data that is to be exported to a byte[]. If a read-only
   * user store is being used a user's password will be the same as their
   * username.
   *
   * @return a byte[] of the user data.
   * @throws IOException
   *             if there's a problem writing to the XMLWriter.
   */
  public byte[] exportUsersToByteArray() throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    XMLWriter writer = new XMLWriter(out, OutputFormat.createPrettyPrint());
    writer.write(exportUsers());

    return out.toByteArray();
  }

  /**
   * Converts the exported user data to a String. If a read-only user store is
   * being used a user's password will be the same as their username.
   *
   * @return a formatted String representation of the user data.
   * @throws IOException
   *             if there's a problem writing to the XMLWriter.
   */
  public String exportUsersToString() throws IOException {
    StringWriter stringWriter = new StringWriter();
    XMLWriter writer = null;
    try {
      writer = new XMLWriter(stringWriter, OutputFormat
          .createPrettyPrint());
      writer.write(exportUsers());
    } catch (IOException ioe) {
      Log.error(ioe);
      throw ioe;
    } finally {
      if (writer != null) {
        writer.close();
      }
    }

    return stringWriter.toString();
  }

  /**
   * Returns a list of usernames that were unable to be imported or whose
   * rosters could not imported. Users are not able to be imported for the
   * following reasons: <li>Their username is not properly formatted. <li>If a
   * read-only user data store is being used and the user could not be found.
   * <li>If a writeable user data store is being used and the user already
   * exists.
   *
   * @param file
   *            a FileItem containing the user data to be imported.
   * @param previousDomain
   *            a String an optional parameter that if supplied will replace
   *            the user roster entries domain names to server name of current
   *            Openfire installation.
   * @return True if FileItem matches the openfire user schema.
   * @throws IOException
   *             if there is a problem reading the FileItem.
   * @throws DocumentException
   *             if an error occurs during parsing.
   */
  public List<String> importUserData(FileItem file, String previousDomain)
      throws DocumentException, IOException {
    SAXReader reader = new SAXReader();
    Document document = reader.read(file.getInputStream());
    return importUsers(document, previousDomain);
  }

  /**
   * Returns whether or not the supplied FileItem matches the openfire user
   * schema
   *
   * @param file
   *            a FileItem to be validated.
   * @return True if FileItem matches the openfire user schema.
   */
  public boolean validateImportFile(FileItem file) {
    try {
      return new UserSchemaValidator(file, "wildfire-user-schema.xsd")
          .validate();
    } catch (Exception e) {
      Log.error(e);
      return false;
    }
  }

  /**
   * Adding heading of an user and its parameters
   *
   * @param userElement
   *            DOM element
   * @param user
   *            User object
   */
  private void addUser(Element userElement, User user) {

    String userName = user.getUsername();
    userElement.addAttribute("name", userName);

    try {
      userElement.addAttribute("password", AuthFactory
          .getPassword(userName));

    } catch (UserNotFoundException e) {
      Log.info("User " + userName
          + " not found, setting their password to their username");
      userElement.addAttribute("password", userName);
    } catch (UnsupportedOperationException e) {
      Log.info("Unable to retrieve " + userName
          + " password, setting their password to their username");
      userElement.addAttribute("password", userName);
    }

  }

  /**
   * Add roster and its groups to a DOM element
   *
   * @param userElement
   *            DOM element
   * @param user
   *            User
   */
  private void addRoster(Element userElement, User user) {
    Element rosterElement = userElement.addElement("query",
        "jabber:iq:roster");

    Collection<RosterItem> roster = user.getRoster().getRosterItems();
    for (RosterItem ri : roster) {
      Element itemElement = rosterElement.addElement("item");

      itemElement.addAttribute("jid", ri.getJid().toBareJID());
      itemElement.addAttribute("name", ri.getNickname());
      itemElement.addAttribute("subscription", ri.getSubStatus()
          .getName());

      /**
       * Adding groups
       */
      Element groupElement = itemElement.addElement("group");
      List<String> groups = ri.getGroups();
      for (String group : groups) {
        groupElement.addText(group);
      }

    }
  }

  /**
   * Adding offline messages, if there are some.
   *
   * @param hostname
   *            host name
   * @param userElement
   *            DOM element
   * @param userName
   *            user name
   */
  private void addOfflineMessages(String hostname, Element userElement,
      String userName) {
    Collection<OfflineMessage> offlineMessages = offlineMessagesStore
        .getMessages(userName, false);

    if (!offlineMessages.isEmpty()) {
      Element offlineElement = userElement.addElement("offline-messages");

      for (OfflineMessage offMessage : offlineMessages) {
        Element messageElement = offlineElement.addElement("message",
            "jabber:client");
        messageElement.addAttribute("from", offMessage.getFrom()
            .toString());
        messageElement
            .addAttribute("to", offMessage.getTo().toString());
        messageElement
            .addAttribute("type", offMessage.getType().name());

        /**
         * Adding text message
         */
        Element bodyElement = messageElement.addElement("body");
        String body = offMessage.getBody();
        bodyElement.addText(body != null ? body : "");

        /**
         * Adding delay element
         */
        Element delayElement = messageElement.addElement("delay",
            "urn:xmpp:delay");
        delayElement.addAttribute("from", hostname);
        delayElement.addAttribute("stamp", offMessage.getCreationDate()
            .toString());
        delayElement.addText("Offline Storage");
      }

    }

  }

  /**
   * Adding vcard element
   *
   * @param userElement
   *            DOM element
   * @param userName
   *            user name
   */
  @SuppressWarnings("unchecked")
  private void addVCard(Element userElement, String userName) {
    Element vCard = vCardManager.getVCard(userName);
    if (vCard != null) {
      Element vCardElement = userElement
          .addElement("vCard", "vcard-temp");
      for (Iterator<Element> iterator = vCard.elementIterator(); iterator
          .hasNext();) {
        Element element = iterator.next();
        vCardElement.addElement(element.getName()).addText(
            element.getText());
      }
    }
  }

  /**
   * Add all the private stored information (XEP-0049)
   * <b>Note: this method is not suported in the available openfire releases,
     * If you want to use it, you will need to change your openfire.jar file to
     * openfire.jar file in this projects lib folder, remove comment to this
     * method and recompile the plugin.
     * 
   * </b> 
   * @param userName User name
   * @param userElement User element
   */
  private void addPrivateStorage(String userName, Element userElement) {
//    Element result = privateStorage.getAll(userName);
//    if (result.elements().size() > 0) {
//      userElement.add(result.createCopy());
//    }
  }

  /**
   * Export the user list and its, Vcard, Offline mesages and roster list to
   * an XML representation XEP-0227 compliant
   *
   * @return DOM document
   */
  private Document exportUsers() {
    Document document = DocumentHelper.createDocument();

    Element root = document.addElement("server-data",
        "http://www.xmpp.org/extensions/xep-0227.html#ns");

    Element host = root.addElement("host");

    host.addAttribute("jid", serverName);

    Collection<User> users = userManager.getUsers();
    for (User user : users) {

      String userName = user.getUsername();

      Element userElement = host.addElement("user");

      addUser(userElement, user);

      addRoster(userElement, user);

      addVCard(userElement, userName);

      addOfflineMessages(serverName, userElement, userName);

      addPrivateStorage(userName, userElement);

    }

    return document;
  }

  private List<String> importUsers(Document document, String previousDomain) {
    List<String> invalidUsers = new ArrayList<String>();

    UserManager userManager = UserManager.getInstance();
    RosterItemProvider rosterItemProvider = RosterItemProvider
        .getInstance();

    Element users = document.getRootElement();

    Iterator usersIter = users.elementIterator("User");
    while (usersIter.hasNext()) {
      Element user = (Element) usersIter.next();

      String userName = null;
      String password = null;
      String email = null;
      String name = null;
      List<RosterItem> rosterItems = new ArrayList<RosterItem>();

      Iterator userElements = user.elementIterator();
      while (userElements.hasNext()) {
        Element userElement = (Element) userElements.next();

        String nameElement = userElement.getName();
        if ("Username".equals(nameElement)) {
          userName = userElement.getText();
        } else if ("Password".equals(nameElement)) {
          password = userElement.getText();
        } else if ("Name".equals(nameElement)) {
          name = userElement.getText();
        } else if ("Email".equals(nameElement)) {
          email = userElement.getText();
        } else if ("Roster".equals(nameElement)) {
          Iterator rosterIter = userElement.elementIterator("Item");

          while (rosterIter.hasNext()) {
            Element rosterElement = (Element) rosterIter.next();

            String jid = rosterElement.attributeValue("jid");
            String askstatus = rosterElement
                .attributeValue("askstatus");
            String recvstatus = rosterElement
                .attributeValue("recvstatus");
            String substatus = rosterElement
                .attributeValue("substatus");
            String nickname = rosterElement.attributeValue("name");

            List<String> groups = new ArrayList<String>();
            Iterator groupIter = rosterElement
                .elementIterator("Group");
            while (groupIter.hasNext()) {
              Element group = (Element) groupIter.next();
              groups.add(group.getText());
            }

            // used for migration
            if (previousDomain != null) {
              jid = jid.replace(previousDomain, serverName);
            }

            rosterItems.add(new RosterItem(new JID(jid),
                RosterItem.SubType.getTypeFromInt(Integer
                    .parseInt(substatus)),
                RosterItem.AskType.getTypeFromInt(Integer
                    .parseInt(askstatus)),
                RosterItem.RecvType.getTypeFromInt(Integer
                    .parseInt(recvstatus)), nickname,
                groups));
          }
        }
      }

      if ((userName != null) && (password != null)) {
        try {
          userName = Stringprep.nodeprep(userName);

          if (!isUserProviderReadOnly()) {
            userManager.createUser(userName, password, name, email);
          }

          // Check to see user exists before adding their roster, this
          // is for read-only user providers.
          userManager.getUser(userName);
          for (RosterItem ri : rosterItems) {
            rosterItemProvider.createItem(userName, ri);
          }
        } catch (StringprepException se) {
          Log.info("Invalid username " + userName);
          invalidUsers.add(userName);
        } catch (UserAlreadyExistsException e) {
          Log.info("User already exists " + userName);
          invalidUsers.add(userName);
        } catch (UserNotFoundException e) {
          Log.info("User not found " + userName);
          invalidUsers.add(userName);
        }
      }
    }

    return invalidUsers;
  }
}
TOP

Related Classes of net.processone.plugin.openfire.ExporterXEP227

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.