/* * Carrot2 project. * * Copyright (C) 2002-2016, Dawid Weiss, Stanisław Osiński. * All rights reserved. * * Refer to the full license file "carrot2.LICENSE" * in the root folder of the repository checkout or at: * http://www.carrot2.org/carrot2.LICENSE */ package org.carrot2.workbench.core.helpers; import java.beans.Introspector; import java.io.*; import org.apache.commons.lang.StringUtils; import org.carrot2.util.ExceptionUtils; import org.carrot2.workbench.core.WorkbenchCorePlugin; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.ui.IMemento; import org.eclipse.ui.XMLMemento; import org.simpleframework.xml.Root; import org.simpleframework.xml.core.Persister; /** * Utilities for storing and reading preferences ({@link IMemento}, * {@link IPreferenceStore}) using <code>org.simpleframework.xml</code> library. */ public final class SimpleXmlMemento { /** * Creates an {@link XMLMemento} from Simple XML-annotated bean. */ static IMemento toMemento(Object benchmarkSettings) throws IOException { try { final StringWriter w = new StringWriter(); new Persister().write(benchmarkSettings, w); XMLMemento memento = XMLMemento .createReadRoot(new StringReader(w.toString())); return memento; } catch (Exception e) { throw ExceptionUtils.wrapAs(IOException.class, e); } } /** * Reads an object from a {@link IMemento}. The memento's type (root) must equal the * bean's {@link Root} annotation name attribute. */ static <T> T fromMemento(Class<T> clazz, IMemento memento) throws IOException { try { final StringWriter sw = new StringWriter(); final XMLMemento m = XMLMemento.createWriteRoot(memento.getType()); m.putMemento(memento); m.save(sw); return new Persister().read(clazz, new StringReader(sw.toString())); } catch (Exception e) { throw ExceptionUtils.wrapAs(IOException.class, e); } } /** * A shortcut for: * * <pre> * fromMemento(clazz, memento.getChild(childName)) * </pre> * * verifying precondition that only one child of a given name exists. */ static <T> T fromMemento(Class<T> clazz, IMemento memento, String childName) throws IOException { final IMemento [] children = memento.getChildren(childName); if (children.length != 1) { throw new IOException("Expected a single node named '" + childName + "' under memento '" + memento.getType() + "'."); } return fromMemento(clazz, children[0]); } /** * Convert any {@link IMemento} to a string. */ public static String toString(IMemento memento) { if (!(memento instanceof XMLMemento)) { XMLMemento m = XMLMemento.createWriteRoot(memento.getType()); m.putMemento(memento); memento = m; } try { final StringWriter w = new StringWriter(); ((XMLMemento) memento).save(w); return w.toString(); } catch (Exception e) { throw new RuntimeException(e); } } /** * Convert any <code>org.simpleframework.xml</code>-enabled object to an XML string. */ public static String toString(Object object) throws IOException { checkObject(object); try { final StringWriter w = new StringWriter(); new Persister().write(object, w); return w.toString(); } catch (Exception e) { throw ExceptionUtils.wrapAs(IOException.class, e); } } /** * Convert an XML string to <code>org.simpleframework.xml</code>-enabled object. */ public static <T> T fromString(Class<T> clazz, String xml) throws IOException { try { final StringReader r = new StringReader(xml); return new Persister().read(clazz, r); } catch (Exception e) { throw ExceptionUtils.wrapAs(IOException.class, e); } } /** * Add a child node to a given memento, named after the object's {@link Root} * annotation. */ public static void addChild(IMemento memento, Object object) throws IOException { checkObject(object); final IMemento child = toMemento(object); memento.createChild(child.getType()).putMemento(child); } /** * Returns an object deserialized from a child node of a given memento. */ public static <T> T getChild(Class<T> clazz, IMemento memento) throws IOException { Root root = clazz.getAnnotation(Root.class); if (root == null) { throw new IllegalArgumentException("Missing @Root annotation on: " + clazz.getName()); } String childName = root.name(); if (StringUtils.isEmpty(childName)) { childName = getClassName(clazz); } IMemento [] children = memento.getChildren(childName); if (children.length == 0) { return null; } if (children.length != 1) { throw new IOException("More than one child named '" + childName + "':" + children.length); } return fromMemento(clazz, children[0]); } /** * Save an object to global plugin's preference store. */ public static void toPreferenceStore(String globalPreferenceKey, Object object) { final IPreferenceStore prefStore = WorkbenchCorePlugin.getDefault().getPreferenceStore(); try { prefStore.setValue(globalPreferenceKey, toString(object)); } catch (IOException e) { Utils.logError(e, false); } } /** * Read an object from the global plugin's preference store. May return * <code>null</code> if an error occurred. */ public static <T> T fromPreferenceStore(Class<T> clazz, String globalPreferenceKey) { final IPreferenceStore prefStore = WorkbenchCorePlugin.getDefault().getPreferenceStore(); final String xml = prefStore.getString(globalPreferenceKey); if (!StringUtils.isEmpty(xml)) { try { return fromString(clazz, xml); } catch (IOException e) { Utils.logError(e, false); } } return null; } /** * Check if the target contains simple XML's annotation. */ private static void checkObject(Object object) { Root root = object.getClass().getAnnotation(Root.class); if (root == null) { throw new IllegalArgumentException("Missing @Root annotation on: " + object.getClass()); } } /** * Mimics SimpleXML's naming for classes without {@link Root#name()}. */ private static String getClassName(Class<?> type) { if (type.isArray()) type = type.getComponentType(); final String name = type.getSimpleName(); if (type.isPrimitive()) return name; else return Introspector.decapitalize(name); } }