Package org.rssowl.core.internal.interpreter

Source Code of org.rssowl.core.internal.interpreter.OPMLExporter

/*   **********************************************************************  **
**   Copyright notice                                                       **
**                                                                          **
**   (c) 2005-2009 RSSOwl Development Team                                  **
**   http://www.rssowl.org/                                                 **
**                                                                          **
**   All rights reserved                                                    **
**                                                                          **
**   This program and the accompanying materials are made available under   **
**   the terms of the Eclipse Public License v1.0 which accompanies this    **
**   distribution, and is available at:                                     **
**   http://www.rssowl.org/legal/epl-v10.html                               **
**                                                                          **
**   A copy is found in the file epl-v10.html and important notices to the  **
**   license from the team is found in the textfile LICENSE.txt distributed **
**   in this package.                                                       **
**                                                                          **
**   This copyright notice MUST APPEAR in all copies of the file!           **
**                                                                          **
**   Contributors:                                                          **
**     RSSOwl Development Team - initial API and implementation             **
**                                                                          **
**  **********************************************************************  */

package org.rssowl.core.internal.interpreter;

import static org.rssowl.core.internal.interpreter.OPMLConstants.RSSOWL_NS;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.rssowl.core.Owl;
import org.rssowl.core.internal.Activator;
import org.rssowl.core.internal.interpreter.OPMLConstants.Attributes;
import org.rssowl.core.internal.interpreter.OPMLConstants.Tag;
import org.rssowl.core.interpreter.ITypeExporter;
import org.rssowl.core.interpreter.InterpreterException;
import org.rssowl.core.persist.IBookMark;
import org.rssowl.core.persist.IFilterAction;
import org.rssowl.core.persist.IFolder;
import org.rssowl.core.persist.IFolderChild;
import org.rssowl.core.persist.ILabel;
import org.rssowl.core.persist.IMark;
import org.rssowl.core.persist.INewsBin;
import org.rssowl.core.persist.ISearch;
import org.rssowl.core.persist.ISearchCondition;
import org.rssowl.core.persist.ISearchFilter;
import org.rssowl.core.persist.ISearchMark;
import org.rssowl.core.persist.dao.DynamicDAO;
import org.rssowl.core.persist.pref.IPreferenceScope;
import org.rssowl.core.persist.pref.IPreferenceType;
import org.rssowl.core.persist.pref.Preference;
import org.rssowl.core.persist.pref.IPreferenceScope.Kind;
import org.rssowl.core.util.CoreUtils;
import org.rssowl.core.util.StringUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;

/**
* Implementation of {@link ITypeExporter} for the OPML XML format.
*
* @author bpasero
*/
public class OPMLExporter implements ITypeExporter {

  /* Default Encoding */
  private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$

  /*
   * @see org.rssowl.core.interpreter.ITypeExporter#exportTo(java.io.File,
   * java.util.Collection, java.util.Set)
   */
  public void exportTo(File destination, Collection<? extends IFolderChild> elements, Set<Options> options) throws InterpreterException {
    Format format = Format.getPrettyFormat();
    format.setEncoding(UTF_8);
    XMLOutputter output = new XMLOutputter(format);
    DateFormat dateFormat = DateFormat.getDateInstance();

    Document document = new Document();
    Element root = new Element(Tag.OPML.get());
    root.setAttribute(Attributes.VERSION.get(), "1.1"); //$NON-NLS-1$
    root.addNamespaceDeclaration(RSSOWL_NS);
    document.setRootElement(root);

    /* Head */
    Element head = new Element(Tag.HEAD.get());
    root.addContent(head);

    Element title = new Element(Tag.TITLE.get());
    title.setText(Messages.OPMLExporter_RSSOWL_SUBSCRIPTIONS);
    head.addContent(title);

    Element dateModified = new Element(Tag.DATE_MODIFIED.get());
    dateModified.setText(new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z").format(new Date())); //$NON-NLS-1$
    head.addContent(dateModified);

    /* Body */
    Element body = new Element(Tag.BODY.get());
    root.addContent(body);

    boolean exportPreferences = (options != null && options.contains(Options.EXPORT_PREFERENCES));

    /* Export Folder Childs */
    if (elements != null && !elements.isEmpty()) {
      Map<IFolder, Element> mapFolderToElement = new HashMap<IFolder, Element>();
      mapFolderToElement.put(null, body);

      /* Ensure that all Parent Elements exist */
      repairHierarchy(mapFolderToElement, elements, exportPreferences);

      /* Now export Elements */
      exportFolderChilds(mapFolderToElement, elements, exportPreferences, dateFormat);
    }

    /* Export Labels */
    if (options != null && options.contains(Options.EXPORT_LABELS))
      exportLabels(body);

    /* Export Filters */
    if (options != null && options.contains(Options.EXPORT_FILTERS))
      exportFilters(body, dateFormat);

    /* Export Preferences */
    if (exportPreferences)
      exportPreferences(body);

    /* Write to File */
    FileOutputStream out = null;
    try {
      out = new FileOutputStream(destination);
      output.output(document, out);
      out.close();
    } catch (FileNotFoundException e) {
      throw new InterpreterException(Activator.getDefault().createErrorStatus(e.getMessage(), e));
    } catch (IOException e) {
      throw new InterpreterException(Activator.getDefault().createErrorStatus(e.getMessage(), e));
    } finally {
      if (out != null) {
        try {
          out.close();
        } catch (IOException e) {
          throw new InterpreterException(Activator.getDefault().createErrorStatus(e.getMessage(), e));
        }
      }
    }
  }

  private void repairHierarchy(Map<IFolder, Element> mapFolderToElement, Collection<? extends IFolderChild> elementsToExport, boolean exportPreferences) {

    /* Retrieve all Parents */
    Set<IFolder> allParentFolders = new HashSet<IFolder>();
    for (IFolderChild element : elementsToExport) {
      fillParents(allParentFolders, element);
    }

    /* Return if Hierarchy is already consistent */
    if (allParentFolders.isEmpty())
      return;

    /* Create Elements for all Parents */
    for (IFolder parent : allParentFolders) {
      Element folderElement = createElement(parent, exportPreferences);
      mapFolderToElement.put(parent, folderElement);
    }

    /* Connect all Parent Nodes according to hierarchy */
    for (IFolder parent : allParentFolders) {
      Element folderElement = mapFolderToElement.get(parent);
      Element parentElement = mapFolderToElement.get(parent.getParent());

      parentElement.addContent(folderElement);
    }
  }

  private void fillParents(Set<IFolder> parents, IFolderChild child) {
    IFolder parent = child.getParent();
    if (parent != null) {
      parents.add(parent);
      fillParents(parents, parent);
    }
  }

  private void exportFolderChilds(Map<IFolder, Element> mapFolderToElement, Collection<? extends IFolderChild> childs, boolean exportPreferences, DateFormat df) {
    for (IFolderChild child : childs) {

      /* Export Folder */
      if (child instanceof IFolder)
        exportFolder(mapFolderToElement, (IFolder) child, exportPreferences, df);

      /* Export Bookmark, Search or Bin */
      else if (child instanceof IMark)
        exportMark(mapFolderToElement, (IMark) child, exportPreferences, df);
    }
  }

  private Element createElement(IFolder folder, boolean exportPreferences) {
    Element folderElement = new Element(Tag.OUTLINE.get());
    folderElement.setAttribute(Attributes.TEXT.get(), folder.getName());
    folderElement.setAttribute(Attributes.IS_SET.get(), String.valueOf(folder.getParent() == null), RSSOWL_NS);
    folderElement.setAttribute(Attributes.ID.get(), String.valueOf(folder.getId()), RSSOWL_NS);

    /* Export Preferences if set */
    if (exportPreferences)
      exportPreferences(folderElement, folder);

    return folderElement;
  }

  private void exportFolder(Map<IFolder, Element> mapFolderToElement, IFolder folder, boolean exportPreferences, DateFormat df) {
    Element folderElement = createElement(folder, exportPreferences);

    /* Store in Map for Childs to Use */
    mapFolderToElement.put(folder, folderElement);

    /* Connect Node according to hierarchy */
    mapFolderToElement.get(folder.getParent()).addContent(folderElement);

    /* Proceed with Folder Childs */
    exportFolderChilds(mapFolderToElement, folder.getChildren(), exportPreferences, df);
  }

  private void exportPreferences(Element parent, IFolderChild child) {
    Map<String, Serializable> properties = child.getProperties();
    if (properties != null) {
      Set<Entry<String, Serializable>> entries = properties.entrySet();
      for (Entry<String, Serializable> entry : entries) {
        if (StringUtils.isSet(entry.getKey()) && entry.getValue() != null) {
          String value = getValueAsString(entry.getValue());

          if (value != null) {
            Element prefElement = new Element(Tag.PREFERENCE.get(), RSSOWL_NS);
            prefElement.setAttribute(Attributes.ID.get(), entry.getKey());
            prefElement.setAttribute(Attributes.VALUE.get(), value);
            prefElement.setAttribute(Attributes.TYPE.get(), String.valueOf(IPreferenceType.getType(entry.getValue()).ordinal()));
            parent.addContent(prefElement);
          }
        }
      }
    }
  }

  private String getValueAsString(Object property) {
    if (property instanceof String)
      return (String) property;

    if (property instanceof Long || property instanceof Integer || property instanceof Boolean)
      return String.valueOf(property);

    if (property instanceof long[]) {
      long[] values = (long[]) property;

      StringBuilder builder = new StringBuilder();
      for (long val : values) {
        builder.append(val).append(OPMLConstants.SEPARATOR);
      }

      if (values.length > 0)
        builder.delete(builder.length() - 1, builder.length());

      return builder.toString();
    }

    if (property instanceof int[]) {
      int[] values = (int[]) property;

      StringBuilder builder = new StringBuilder();
      for (int val : values) {
        builder.append(val).append(OPMLConstants.SEPARATOR);
      }

      if (values.length > 0)
        builder.delete(builder.length() - 1, builder.length());

      return builder.toString();
    }

    if (property instanceof String[]) {
      String[] values = (String[]) property;

      StringBuilder builder = new StringBuilder();
      for (String val : values) {
        builder.append(val).append(OPMLConstants.SEPARATOR);
      }

      if (values.length > 0)
        builder.delete(builder.length() - 1, builder.length());

      return builder.toString();
    }

    return null;
  }

  private void exportMark(Map<IFolder, Element> mapFolderToElement, IMark mark, boolean exportPreferences, DateFormat df) {
    String name = mark.getName();
    Element element = null;

    /* Export BookMark */
    if (mark instanceof IBookMark) {
      String link = ((IBookMark) mark).getFeedLinkReference().getLinkAsText();

      element = new Element(Tag.OUTLINE.get());
      element.setAttribute(Attributes.TEXT.get(), name);
      element.setAttribute(Attributes.XML_URL.get(), link);
      element.setAttribute(Attributes.ID.get(), String.valueOf(mark.getId()), RSSOWL_NS);
      mapFolderToElement.get(mark.getParent()).addContent(element);
    }

    /* Export SearchMark */
    else if (mark instanceof ISearchMark) {
      ISearchMark searchMark = (ISearchMark) mark;
      List<ISearchCondition> conditions = searchMark.getSearchConditions();

      element = new Element(Tag.SAVED_SEARCH.get(), RSSOWL_NS);
      element.setAttribute(Attributes.NAME.get(), name);
      element.setAttribute(Attributes.MATCH_ALL_CONDITIONS.get(), String.valueOf(searchMark.matchAllConditions()));
      element.setAttribute(Attributes.ID.get(), String.valueOf(mark.getId()), RSSOWL_NS);
      mapFolderToElement.get(mark.getParent()).addContent(element);

      for (ISearchCondition condition : conditions) {
        Element conditionElement = new Element(Tag.SEARCH_CONDITION.get(), RSSOWL_NS);
        element.addContent(conditionElement);

        if (condition.getValue() != null)
          fillElement(conditionElement, condition, df);
      }
    }

    /* Export Newsbin */
    else if (mark instanceof INewsBin) {
      element = new Element(Tag.BIN.get(), RSSOWL_NS);
      element.setAttribute(Attributes.NAME.get(), name);
      element.setAttribute(Attributes.ID.get(), String.valueOf(mark.getId()), RSSOWL_NS);
      mapFolderToElement.get(mark.getParent()).addContent(element);
    }

    /* Export Preferences if set */
    if (element != null && exportPreferences)
      exportPreferences(element, mark);
  }

  private void exportFilters(Element body, DateFormat df) {
    Collection<ISearchFilter> filters = DynamicDAO.loadAll(ISearchFilter.class);
    for (ISearchFilter filter : filters) {
      String name = filter.getName();
      int order = filter.getOrder();
      boolean isEnabled = filter.isEnabled();
      boolean matchAllNews = filter.matchAllNews();

      Element filterElement = new Element(Tag.FILTER.get(), RSSOWL_NS);
      filterElement.setAttribute(Attributes.NAME.get(), name);
      filterElement.setAttribute(Attributes.ORDER.get(), String.valueOf(order));
      filterElement.setAttribute(Attributes.ENABLED.get(), String.valueOf(isEnabled));
      filterElement.setAttribute(Attributes.MATCH_ALL_NEWS.get(), String.valueOf(matchAllNews));
      body.addContent(filterElement);

      /* Export Search if provided */
      ISearch search = filter.getSearch();
      if (search != null) {
        List<ISearchCondition> conditions = search.getSearchConditions();

        Element searchElement = new Element(Tag.SEARCH.get(), RSSOWL_NS);
        searchElement.setAttribute(Attributes.MATCH_ALL_CONDITIONS.get(), String.valueOf(search.matchAllConditions()));
        filterElement.addContent(searchElement);

        for (ISearchCondition condition : conditions) {
          Element conditionElement = new Element(Tag.SEARCH_CONDITION.get(), RSSOWL_NS);
          searchElement.addContent(conditionElement);

          if (condition.getValue() != null)
            fillElement(conditionElement, condition, df);
        }
      }

      /* Export Actions */
      List<IFilterAction> actions = filter.getActions();
      for (IFilterAction action : actions) {
        String actionId = action.getActionId();

        Element actionElement = new Element(Tag.ACTION.get(), RSSOWL_NS);
        actionElement.setAttribute(Attributes.ID.get(), actionId);

        /* Action Data as Properties */
        if (action.getData() instanceof Properties) {
          Properties data = (Properties) action.getData();
          Set<Entry<Object, Object>> entries = data.entrySet();
          for (Entry<Object, Object> entry : entries) {
            String key = entry.getKey().toString();
            String value = entry.getValue().toString();

            Element actionProperty = new Element(Tag.ACTION_PROPERTY.get(), RSSOWL_NS);
            actionProperty.setAttribute(Attributes.ID.get(), key);
            actionProperty.setAttribute(Attributes.VALUE.get(), value);
            actionElement.addContent(actionProperty);
          }
        }

        /* Action Data as Primitive */
        else {
          String data = toString(action.getData());
          if (data != null)
            actionElement.setAttribute(Attributes.DATA.get(), data);
        }

        filterElement.addContent(actionElement);
      }
    }
  }

  private void fillElement(Element conditionElement, ISearchCondition condition, DateFormat df) {

    /* Search Specifier */
    Element searchSpecifier = new Element(Tag.SPECIFIER.get(), RSSOWL_NS);
    searchSpecifier.setAttribute(Attributes.ID.get(), String.valueOf(condition.getSpecifier().ordinal()));
    conditionElement.addContent(searchSpecifier);

    /* Search Condition: Location */
    if (condition.getValue() instanceof Long[][]) {
      List<IFolderChild> locations = CoreUtils.toEntities((Long[][]) condition.getValue());

      Element searchValue = new Element(Tag.SEARCH_VALUE.get(), RSSOWL_NS);
      searchValue.setAttribute(Attributes.TYPE.get(), String.valueOf(condition.getField().getSearchValueType().getId()));
      conditionElement.addContent(searchValue);

      for (IFolderChild child : locations) {
        boolean isFolder = (child instanceof IFolder);
        boolean isNewsbin = (child instanceof INewsBin);

        Element location = new Element(Tag.LOCATION.get(), RSSOWL_NS);
        location.setAttribute(Attributes.IS_BIN.get(), String.valueOf(isNewsbin));
        location.setAttribute(Attributes.IS_FOLDER.get(), String.valueOf(isFolder));
        location.setAttribute(Attributes.VALUE.get(), String.valueOf(child.getId()));
        searchValue.addContent(location);
      }
    }

    /* Single Value */
    else if (!EnumSet.class.isAssignableFrom(condition.getValue().getClass())) {
      Element searchValue = new Element(Tag.SEARCH_VALUE.get(), RSSOWL_NS);
      searchValue.setAttribute(Attributes.TYPE.get(), String.valueOf(condition.getField().getSearchValueType().getId()));
      searchValue.setAttribute(Attributes.VALUE.get(), getValueString(df, condition));
      conditionElement.addContent(searchValue);
    }

    /* Multiple Values */
    else {
      EnumSet<?> values = ((EnumSet<?>) condition.getValue());

      Element searchValue = new Element(Tag.SEARCH_VALUE.get(), RSSOWL_NS);
      searchValue.setAttribute(Attributes.TYPE.get(), String.valueOf(condition.getField().getSearchValueType().getId()));
      conditionElement.addContent(searchValue);

      for (Enum<?> enumValue : values) {
        Element state = new Element(Tag.STATE.get(), RSSOWL_NS);
        state.setAttribute(Attributes.VALUE.get(), String.valueOf(enumValue.ordinal()));
        searchValue.addContent(state);
      }
    }

    /* Search Field */
    Element field = new Element(Tag.SEARCH_FIELD.get(), RSSOWL_NS);
    field.setAttribute(Attributes.ID.get(), String.valueOf(condition.getField().getId()));
    field.setAttribute(Attributes.ENTITY.get(), condition.getField().getEntityName());
    conditionElement.addContent(field);
  }

  private String toString(Object data) {
    if (data == null)
      return null;

    if (data instanceof String)
      return (String) data;

    if (data instanceof Long)
      return String.valueOf(data);

    if (data instanceof Long[]) {
      Long[] value = (Long[]) data;
      StringBuilder builder = new StringBuilder();
      for (Long val : value) {
        builder.append(val).append(OPMLConstants.SEPARATOR);
      }

      if (value.length > 0)
        builder.delete(builder.length() - 1, builder.length());

      return builder.toString();
    }

    return null;
  }

  private String getValueString(DateFormat df, ISearchCondition condition) {
    if (condition.getValue() instanceof Date)
      return df.format((Date) condition.getValue());

    return condition.getValue().toString();
  }

  private void exportLabels(Element body) {
    Collection<ILabel> labels = DynamicDAO.loadAll(ILabel.class);
    for (ILabel label : labels) {
      Long id = label.getId();
      String name = label.getName();
      String color = label.getColor();
      int order = label.getOrder();

      Element labelElement = new Element(Tag.LABEL.get(), RSSOWL_NS);
      labelElement.setAttribute(Attributes.ID.get(), String.valueOf(id));
      labelElement.setAttribute(Attributes.NAME.get(), name);
      labelElement.setAttribute(Attributes.ORDER.get(), String.valueOf(order));
      labelElement.setAttribute(Attributes.COLOR.get(), color);

      body.addContent(labelElement);
    }
  }

  private void exportPreferences(Element body) {
    IPreferenceScope globalPreferences = Owl.getPreferenceService().getGlobalScope();
    IPreferenceScope eclipsePreferences = Owl.getPreferenceService().getEclipseScope();

    Preference[] preferences = Preference.values();
    for (Preference preference : preferences) {
      if (preference.getKind() == Kind.ENTITY)
        continue;

      String value = getValueAsString(preference, globalPreferences, eclipsePreferences);
      if (value != null) {
        Element prefElement = new Element(Tag.PREFERENCE.get(), RSSOWL_NS);
        prefElement.setAttribute(Attributes.ID.get(), preference.id());
        prefElement.setAttribute(Attributes.VALUE.get(), value);
        prefElement.setAttribute(Attributes.TYPE.get(), String.valueOf(preference.getType().ordinal()));
        prefElement.setAttribute(Attributes.KIND.get(), String.valueOf(preference.getKind().ordinal()));
        body.addContent(prefElement);
      }
    }
  }

  private String getValueAsString(Preference preference, IPreferenceScope global, IPreferenceScope eclipse) {
    IPreferenceScope actualScope = (preference.getKind() == Kind.GLOBAL) ? global : eclipse;
    String id = preference.id();

    switch (preference.getType()) {
      case BOOLEAN:
        return getValueAsString(actualScope.getBoolean(id));
      case INTEGER:
        return getValueAsString(actualScope.getInteger(id));
      case INTEGERS:
        return getValueAsString(actualScope.getIntegers(id));
      case LONG:
        return getValueAsString(actualScope.getLong(id));
      case LONGS:
        return getValueAsString(actualScope.getLongs(id));
      case STRING:
        return getValueAsString(actualScope.getString(id));
      case STRINGS:
        return getValueAsString(actualScope.getStrings(id));
    }

    return null;
  }
}
TOP

Related Classes of org.rssowl.core.internal.interpreter.OPMLExporter

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.