/** * $Id: mxCodecRegistry.java,v 1.1 2012/11/15 13:26:47 gaudenz Exp $ * Copyright (c) 2007, Gaudenz Alder */ package com.mxgraph.io; import java.util.ArrayList; import java.util.Collection; import java.util.Hashtable; import java.util.List; import java.util.Map; import com.mxgraph.model.mxGraphModel.mxCollapseChange; import com.mxgraph.model.mxGraphModel.mxGeometryChange; import com.mxgraph.model.mxGraphModel.mxStyleChange; import com.mxgraph.model.mxGraphModel.mxValueChange; import com.mxgraph.model.mxGraphModel.mxVisibleChange; /** * Singleton class that acts as a global registry for codecs. See * {@link mxCodec} for an example. */ public class mxCodecRegistry { /** * Maps from constructor names to codecs. */ protected static Hashtable<String, mxObjectCodec> codecs = new Hashtable<String, mxObjectCodec>(); /** * Maps from classnames to codecnames. */ protected static Hashtable<String, String> aliases = new Hashtable<String, String>(); /** * Holds the list of known packages. Packages are used to prefix short * class names (eg. mxCell) in XML markup. */ protected static List<String> packages = new ArrayList<String>(); // Registers the known codecs and package names static { addPackage("com.mxgraph"); addPackage("com.mxgraph.util"); addPackage("com.mxgraph.model"); addPackage("com.mxgraph.view"); addPackage("java.lang"); addPackage("java.util"); register(new mxObjectCodec(new ArrayList<Object>())); register(new mxModelCodec()); register(new mxCellCodec()); register(new mxStylesheetCodec()); register(new mxRootChangeCodec()); register(new mxChildChangeCodec()); register(new mxTerminalChangeCodec()); register(new mxGenericChangeCodec(new mxValueChange(), "value")); register(new mxGenericChangeCodec(new mxStyleChange(), "style")); register(new mxGenericChangeCodec(new mxGeometryChange(), "geometry")); register(new mxGenericChangeCodec(new mxCollapseChange(), "collapsed")); register(new mxGenericChangeCodec(new mxVisibleChange(), "visible")); } /** * Registers a new codec and associates the name of the template constructor * in the codec with the codec object. Automatically creates an alias if the * codename and the classname are not equal. */ public static mxObjectCodec register(mxObjectCodec codec) { if (codec != null) { String name = codec.getName(); codecs.put(name, codec); String classname = getName(codec.getTemplate()); if (!classname.equals(name)) { addAlias(classname, name); } } return codec; } /** * Adds an alias for mapping a classname to a codecname. */ public static void addAlias(String classname, String codecname) { aliases.put(classname, codecname); } /** * Returns a codec that handles the given object, which can be an object * instance or an XML node. * * @param name Java class name. */ public static mxObjectCodec getCodec(String name) { String tmp = aliases.get(name); if (tmp != null) { name = tmp; } mxObjectCodec codec = codecs.get(name); // Registers a new default codec for the given name // if no codec has been previously defined. if (codec == null) { Object instance = getInstanceForName(name); if (instance != null) { try { codec = new mxObjectCodec(instance); register(codec); } catch (Exception e) { // ignore } } } return codec; } /** * Adds the given package name to the list of known package names. * * @param packagename Name of the package to be added. */ public static void addPackage(String packagename) { packages.add(packagename); } /** * Creates and returns a new instance for the given class name. * * @param name Name of the class to be instantiated. * @return Returns a new instance of the given class. */ public static Object getInstanceForName(String name) { Class<?> clazz = getClassForName(name); if (clazz != null) { if (clazz.isEnum()) { // For an enum, use the first constant as the default instance return clazz.getEnumConstants()[0]; } else { try { return clazz.newInstance(); } catch (Exception e) { // ignore } } } return null; } /** * Returns a class that corresponds to the given name. * * @param name * @return Returns the class for the given name. */ public static Class<?> getClassForName(String name) { try { return Class.forName(name); } catch (Exception e) { // ignore } for (int i = 0; i < packages.size(); i++) { try { String s = packages.get(i); return Class.forName(s + "." + name); } catch (Exception e) { // ignore } } return null; } /** * Returns the name that identifies the codec associated * with the given instance.. * * The I/O system uses unqualified classnames, eg. for a * <code>com.mxgraph.model.mxCell</code> this returns * <code>mxCell</code>. * * @param instance Instance whose node name should be returned. * @return Returns a string that identifies the codec. */ public static String getName(Object instance) { Class<? extends Object> type = instance.getClass(); if (type.isArray() || Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type)) { return "Array"; } else { if (packages.contains(type.getPackage().getName())) { return type.getSimpleName(); } else { return type.getName(); } } } }