/*
* This file is part of WebLookAndFeel library.
*
* WebLookAndFeel library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* WebLookAndFeel library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WebLookAndFeel library. If not, see .
*/
package com.alee.utils;
import com.alee.managers.plugin.data.PluginInformation;
import com.alee.managers.plugin.data.PluginLibrary;
import com.alee.managers.plugin.data.PluginVersion;
import com.alee.utils.collection.ValuesTable;
import com.alee.utils.xml.*;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.SingleValueConverter;
import com.thoughtworks.xstream.io.xml.DomDriver;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* This class provides a set of utilities to easily serialize and deserialize objects into and from XML.
* There are is a lot of methods to read specific library objects using various resource files.
*
* @author Mikle Garin
*/
public final class XmlUtils
{
/**
* Whether should offer better aliases for standard Java classes like Point and Rectangle or not.
*/
public static boolean aliasJdkClasses = true;
/**
* Custom converters.
*/
public static final ColorConverter colorConverter = new ColorConverter ();
public static final InsetsConverter insetsConverter = new InsetsConverter ();
/**
* Custom password converter that encrypts serialized passwords.
*/
public static final PasswordConverter passwordConverter = new PasswordConverter ();
/**
* XStream instance.
*/
private static XStream xStream = null;
/**
* Returns global XStream instance configured with all required aliases and converters.
*
* @return XStream
*/
public static XStream getXStream ()
{
if ( xStream == null )
{
initializeXStream ();
}
return xStream;
}
/**
* Initializes global XStream instance.
*/
private static void initializeXStream ()
{
try
{
// XStream instnce initialization
xStream = new XStream ( new DomDriver () );
// Standart Java-classes aliases
if ( aliasJdkClasses )
{
xStream.alias ( "Point", Point.class );
xStream.useAttributeFor ( Point.class, "x" );
xStream.useAttributeFor ( Point.class, "y" );
xStream.alias ( "Dimension", Dimension.class );
xStream.useAttributeFor ( Dimension.class, "width" );
xStream.useAttributeFor ( Dimension.class, "height" );
xStream.alias ( "Rectangle", Rectangle.class );
xStream.useAttributeFor ( Rectangle.class, "x" );
xStream.useAttributeFor ( Rectangle.class, "y" );
xStream.useAttributeFor ( Rectangle.class, "width" );
xStream.useAttributeFor ( Rectangle.class, "height" );
xStream.alias ( "Font", Font.class );
xStream.alias ( "Color", Color.class );
xStream.registerConverter ( colorConverter );
xStream.alias ( "Insets", Insets.class );
xStream.registerConverter ( insetsConverter );
}
// XML resources aliases
xStream.processAnnotations ( ResourceLocation.class );
xStream.processAnnotations ( ResourceFile.class );
xStream.processAnnotations ( ResourceList.class );
xStream.processAnnotations ( ResourceMap.class );
// Additional WebLaF data classes aliases
xStream.processAnnotations ( ValuesTable.class );
// Plugin manager classes aliases
xStream.processAnnotations ( PluginInformation.class );
xStream.processAnnotations ( PluginVersion.class );
xStream.processAnnotations ( PluginLibrary.class );
}
catch ( final Throwable e )
{
e.printStackTrace ();
}
}
/**
* Process the annotations of the given type and configure the XStream.
* A call of this method will automatically turn the auto-detection mode for annotations off.
*
* @param type the type with XStream annotations
*/
public static void processAnnotations ( final Class type )
{
getXStream ().processAnnotations ( type );
}
/**
* Process the annotations of the given types and configure the XStream.
*
* @param types the types with XStream annotations
*/
public static void processAnnotations ( final Class[] types )
{
getXStream ().processAnnotations ( types );
}
/**
* Alias a Class to a shorter name to be used in XML elements.
*
* @param name Short name
* @param type Type to be aliased
*/
public static void alias ( final String name, final Class type )
{
getXStream ().alias ( name, type );
}
/**
* Use an attribute for a field declared in a specific type.
*
* @param type the name of the field
* @param field the Class containing such field
*/
public static void useAttributeFor ( final Class type, final String field )
{
getXStream ().useAttributeFor ( type, field );
}
/**
* Adds an implicit array.
*
* @param type class owning the implicit array
* @param field name of the array field
*/
public static void addImplicitArray ( final Class type, final String field )
{
getXStream ().addImplicitArray ( type, field );
}
/**
* Adds an implicit array which is used for all items of the given element name defined by itemName.
*
* @param type class owning the implicit array
* @param field name of the array field in the ownerType
* @param itemName alias name of the items
*/
public static void addImplicitArray ( final Class type, final String field, final String itemName )
{
getXStream ().addImplicitArray ( type, field, itemName );
}
/**
* Adds a new converter into converters registry.
*
* @param converter the new converter
*/
public static void registerConverter ( final Converter converter )
{
getXStream ().registerConverter ( converter );
}
/**
* Adds a new converter into converters registry.
*
* @param converter the new converter
*/
public static void registerConverter ( final SingleValueConverter converter )
{
getXStream ().registerConverter ( converter );
}
/**
* Calls static "provideAliases" method on a class that implements AliasProvider.
* This method is created mostly for internal library usage.
*
* @param aliasProvider AliasProvider ancestor class
* @param specific class type
*/
public static void alias ( final Class aliasProvider )
{
ReflectUtils.callStaticMethodSafely ( aliasProvider, AliasProvider.methodName, getXStream () );
}
/**
* Serializes Object into XML and writes it into specified file.
*
* @param obj object to serialize
* @param file output file
*/
public static void toXML ( final Object obj, final String file )
{
toXML ( obj, new File ( file ) );
}
/**
* Serializes Object into XML and writes it into specified file.
*
* @param obj object to serialize
* @param file output file
*/
public static void toXML ( final Object obj, final File file )
{
try
{
final FileOutputStream fos = new FileOutputStream ( file );
final OutputStreamWriter osw = new OutputStreamWriter ( fos, "UTF-8" );
toXML ( obj, osw );
osw.close ();
fos.close ();
}
catch ( final IOException e )
{
e.printStackTrace ();
}
}
/**
* Returns Object serialized into XML.
*
* @param obj object to serialize
* @return serialized into XML object representation
*/
public static String toXML ( final Object obj )
{
return getXStream ().toXML ( obj );
}
/**
* Serializes Object into XML and writes it using a specified Writer.
*
* @param obj object to serialize
* @param out output writer
*/
public static void toXML ( final Object obj, final Writer out )
{
getXStream ().toXML ( obj, out );
}
/**
* Serializes Object into XML and writes it using a specified OutputStream.
*
* @param obj object to serialize
* @param out output stream
*/
public static void toXML ( final Object obj, final OutputStream out )
{
getXStream ().toXML ( obj, out );
}
/**
* Returns Object deserialized from XML content.
*
* @param reader XML text source
* @param read object type
* @return deserialized object
*/
public static T fromXML ( final Reader reader )
{
return ( T ) getXStream ().fromXML ( reader );
}
/**
* Returns Object deserialized from XML content.
*
* @param input XML text source
* @param read object type
* @return deserialized object
*/
public static T fromXML ( final InputStream input )
{
return ( T ) getXStream ().fromXML ( input );
}
/**
* Returns Object deserialized from XML text
*
* @param url XML text source
* @param read object type
* @return deserialized object
*/
public static T fromXML ( final URL url )
{
return ( T ) getXStream ().fromXML ( url );
}
/**
* Returns Object deserialized from XML content.
*
* @param file file with XML content
* @param read object type
* @return deserialized object
*/
public static T fromXML ( final File file )
{
return ( T ) getXStream ().fromXML ( file );
}
/**
* Returns Object deserialized from XML content.
*
* @param xml XML content
* @param read object type
* @return deserialized object
*/
public static T fromXML ( final String xml )
{
return ( T ) getXStream ().fromXML ( xml );
}
/**
* Returns Object deserialized from XML content.
*
* @param source XML text source
* @param read object type
* @return deserialized object
*/
public static T fromXML ( final Object source )
{
if ( source instanceof URL )
{
return fromXML ( ( URL ) source );
}
else if ( source instanceof String )
{
return fromXML ( new File ( ( String ) source ) );
}
else if ( source instanceof File )
{
return fromXML ( ( File ) source );
}
else if ( source instanceof Reader )
{
return fromXML ( ( Reader ) source );
}
else if ( source instanceof InputStream )
{
return fromXML ( ( InputStream ) source );
}
else
{
return null;
}
}
/**
* Returns Object deserialized from XML text
*
* @param resource XML text source description
* @param read object type
* @return deserialized object
*/
public static T fromXML ( final ResourceFile resource )
{
switch ( resource.getLocation () )
{
case url:
{
try
{
return XmlUtils.fromXML ( new URL ( resource.getSource () ) );
}
catch ( final MalformedURLException e )
{
e.printStackTrace ();
return null;
}
}
case filePath:
{
return XmlUtils.fromXML ( new File ( resource.getSource () ) );
}
case nearClass:
{
InputStream is = null;
try
{
is = Class.forName ( resource.getClassName () ).getResourceAsStream ( resource.getSource () );
if ( is == null )
{
final String src = resource.getSource ();
final String cn = resource.getClassName ();
throw new RuntimeException ( "Unable to read XML file \"" + src + "\" near class \"" + cn + "\"" );
}
return XmlUtils.fromXML ( is );
}
catch ( final ClassNotFoundException e )
{
e.printStackTrace ();
return null;
}
catch ( final Throwable e )
{
e.printStackTrace ();
return null;
}
finally
{
try
{
if ( is != null )
{
is.close ();
}
}
catch ( final Throwable e )
{
e.printStackTrace ();
}
}
}
default:
{
return null;
}
}
}
/**
* Returns text which is read from the source.
*
* @param source one of possible sources: URL, String, File, Reader, InputStream
* @return text as String
*/
public static String loadString ( final Object source )
{
return loadString ( loadResourceFile ( source ) );
}
/**
* Returns text which is read from specified ResourceFile.
*
* @param resource file description
* @return text as String
*/
public static String loadString ( final ResourceFile resource )
{
if ( resource.getLocation ().equals ( ResourceLocation.url ) )
{
try
{
return FileUtils
.readToString ( new BufferedReader ( new InputStreamReader ( new URL ( resource.getSource () ).openStream () ) ) );
}
catch ( final IOException e )
{
e.printStackTrace ();
return null;
}
}
if ( resource.getLocation ().equals ( ResourceLocation.filePath ) )
{
return FileUtils.readToString ( new File ( resource.getSource () ) );
}
else if ( resource.getLocation ().equals ( ResourceLocation.nearClass ) )
{
try
{
return FileUtils.readToString ( Class.forName ( resource.getClassName () ), resource.getSource () );
}
catch ( final ClassNotFoundException e )
{
e.printStackTrace ();
return null;
}
}
else
{
return null;
}
}
/**
* Returns ImageIcon which is read from the source.
*
* @param source one of possible sources: URL, String, File, Reader, InputStream
* @return ImageIcon
*/
public static ImageIcon loadImageIcon ( final Object source )
{
return loadImageIcon ( loadResourceFile ( source ) );
}
/**
* Returns ImageIcon which is read from specified ResourceFile.
*
* @param resource file description
* @return ImageIcon
*/
public static ImageIcon loadImageIcon ( final ResourceFile resource )
{
if ( resource.getLocation ().equals ( ResourceLocation.url ) )
{
try
{
return new ImageIcon ( new URL ( resource.getSource () ) );
}
catch ( final MalformedURLException e )
{
e.printStackTrace ();
return null;
}
}
if ( resource.getLocation ().equals ( ResourceLocation.filePath ) )
{
try
{
return new ImageIcon ( new File ( resource.getSource () ).getCanonicalPath () );
}
catch ( final IOException e )
{
e.printStackTrace ();
return null;
}
}
else if ( resource.getLocation ().equals ( ResourceLocation.nearClass ) )
{
try
{
return new ImageIcon ( Class.forName ( resource.getClassName () ).getResource ( resource.getSource () ) );
}
catch ( final ClassNotFoundException e )
{
e.printStackTrace ();
return null;
}
}
else
{
return null;
}
}
/**
* Returns ImageIcon list which is read from the source.
*
* @param source one of possible sources: URL, String, File, Reader, InputStream
* @return ImageIcon list
*/
public static List loadImagesList ( final Object source )
{
return loadImagesList ( loadResourceList ( source ) );
}
/**
* Returns ImageIcon list which is read from specified ResourceList.
*
* @param resourceList ResourceFile list
* @return ImageIcon list
*/
public static List loadImagesList ( final ResourceList resourceList )
{
final List icons = new ArrayList ();
for ( final ResourceFile resource : resourceList.getResources () )
{
final ImageIcon imageIcon = loadImageIcon ( resource );
if ( imageIcon != null )
{
icons.add ( imageIcon );
}
}
return icons;
}
/**
* Returns ResourceMap which is read from the source.
*
* @param source one of possible sources: URL, String, File, Reader, InputStream
* @return ResourceMap
*/
public static ResourceMap loadResourceMap ( final Object source )
{
return fromXML ( source );
}
/**
* Returns ResourceList which is read from the source.
*
* @param source one of possible sources: URL, String, File, Reader, InputStream
* @return ResourceList
*/
public static ResourceList loadResourceList ( final Object source )
{
return fromXML ( source );
}
/**
* Returns ResourceFile which is read from the source.
*
* @param source one of possible sources: URL, String, File, Reader, InputStream
* @return ResourceFile
*/
public static ResourceFile loadResourceFile ( final Object source )
{
return fromXML ( source );
}
}