// $Id: NotationProviderFactory2.java 132 2010-09-26 23:32:33Z marcusvnac $ // Copyright (c) 2005-2008 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph appear in all copies. This software program and // documentation are copyrighted by The Regents of the University of // California. The software program and documentation are supplied "AS // IS", without any accompanying services from The Regents. The Regents // does not warrant that the operation of the program will be // uninterrupted or error-free. The end-user understands that the program // was developed for research purposes and is advised not to rely // exclusively on the program for any reason. IN NO EVENT SHALL THE // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. package org.argouml.notation; import java.beans.PropertyChangeListener; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; //#if defined(LOGGING) //@#$LPS-LOGGING:GranularityType:Import import org.apache.log4j.Logger; //#endif /** * The NotationProviderFactory2 is a singleton, * since it is the accesspoint for all Figs * to access the textual representation of modelobjects, * and since plugin modules can add extra languages. * * @author Michiel */ public final class NotationProviderFactory2 { //#if defined(LOGGING) //@#$LPS-LOGGING:GranularityType:Field private static final Logger LOG = Logger.getLogger(NotationProviderFactory2.class); //#endif // TODO: The concept of a single global notation language isn't going to // work with multiple projects (or diagrams with different languages in // the same project) private static String currentLanguage; /** * TYPE_NAME the name of the modelelement, e.g. class, package, state */ public static final int TYPE_NAME = 1; /** * TYPE_TRANSITION the main text shown above the transition. */ public static final int TYPE_TRANSITION = 2; //#if defined(STATEDIAGRAM) or defined(ACTIVITYDIAGRAM) //@#$LPS-STATEDIAGRAM:GranularityType:Field //@#$LPS-ACTIVITYDIAGRAM:GranularityType:Field /** * TYPE_STATEBODY the multiline text shown inside the state body. */ public static final int TYPE_STATEBODY = 3; //#endif /** * TYPE_ACTIONSTATE the text shown in an actionstate. */ public static final int TYPE_ACTIONSTATE = 4; /** * TYPE_ATTRIBUTE the text shown in a attribute compartment (1 attrib only). */ public static final int TYPE_ATTRIBUTE = 5; /** * TYPE_OPERATION the text shown in a operation compartment (1 oper only). */ public static final int TYPE_OPERATION = 6; /** * TYPE_OBJECT the text shown on an object. */ public static final int TYPE_OBJECT = 7; /** * TYPE_COMPONENTINSTANCE the text shown on a componentInstance. */ public static final int TYPE_COMPONENTINSTANCE = 8; /** * TYPE_NODEINSTANCE the text shown on a componentInstance. */ public static final int TYPE_NODEINSTANCE = 9; /** * TYPE_TYPE_OBJECTFLOWSTATE_TYPE the text shown on a * objectflowstate's type, i.e. its classifier name. */ public static final int TYPE_OBJECTFLOWSTATE_TYPE = 10; /** * TYPE_OBJECTFLOWSTATE_STATE the text shown on a * objectflowstate's state. */ public static final int TYPE_OBJECTFLOWSTATE_STATE = 11; /** * TYPE_CALLSTATE the text shown on a * callstate's state. */ public static final int TYPE_CALLSTATE = 12; /** * TYPE_CLASSIFIERROLE the text shown on a * classifierrole. */ public static final int TYPE_CLASSIFIERROLE = 13; /** * TYPE_MESSAGE the text shown on a Message * in a Collaborations diagram. */ public static final int TYPE_MESSAGE = 14; /** * TYPE_EXTENSION_POINT the text shown on a usecase * representing the extensionpoint. */ public static final int TYPE_EXTENSION_POINT = 15; /** * The text shown at the association end that represents the role. */ public static final int TYPE_ASSOCIATION_END_NAME = 16; /** * The text shown for the association role name. */ public static final int TYPE_ASSOCIATION_ROLE = 17; /** * The text shown for the association role name. */ public static final int TYPE_ASSOCIATION_NAME = 18; /** * The text shown for a multiplicity. */ public static final int TYPE_MULTIPLICITY = 19; /** * The text shown for an enumeration literal. */ public static final int TYPE_ENUMERATION_LITERAL = 20; /** * TYPE_MESSAGE the text shown on a Message * in a Collaborations diagram. */ public static final int TYPE_SD_MESSAGE = 21; /** * defaultLanguage the Notation language used by default, i.e. UML */ private NotationName defaultLanguage; /** * allLanguages is a HashMap with as key the notationName, * and as value a second HashMap. This latter HashMap has as key the "type" * converted to Integer, and as value the provider (NotationProvider). */ private Map<NotationName, Map<Integer, Class>> allLanguages; /** * The instance is the singleton. */ private static NotationProviderFactory2 instance; /** * The constructor. */ private NotationProviderFactory2() { super(); allLanguages = new HashMap<NotationName, Map<Integer, Class>>(); } /** * @return returns the singleton instance */ public static NotationProviderFactory2 getInstance() { if (instance == null) { instance = new NotationProviderFactory2(); } return instance; } /** * Get a NotationProvider for the given language. * * @param type the provider type * @return the provider * @param object the constructor parameter * @deprecated for 0.27.2 by tfmorris. Use * {@link #getNotationProvider(int, Object, NotationName)}. */ @Deprecated public NotationProvider getNotationProvider(int type, Object object) { NotationName name = Notation.findNotation(currentLanguage); return getNotationProvider(type, object, name); } /** * Get a NotationProvider for the current project. * <p> * If there is any reason for failure, null is returned - no * exception is thrown. * The caller is supposed to deal with receiving null. * * @param type the provider type * @param object the constructor parameter * @param name the name of the notation language to use * @return the provider, or null if there was any failure */ public NotationProvider getNotationProvider(int type, Object object, NotationName name) { Class clazz = getNotationProviderClass(type, name); if (clazz != null) { try { try { Class[] mp = {}; Method m = clazz.getMethod("getInstance", mp); return (NotationProvider) m.invoke(null, (Object[]) mp); } catch (Exception e) { Class[] cp = {Object.class}; Constructor constructor = clazz.getConstructor(cp); Object[] params = { object, }; return (NotationProvider) constructor.newInstance(params); } } catch (SecurityException e) { // TODO: Why aren't we throwing an exception here? // Returning null results in NPE and no explanation why. //#if defined(LOGGING) //@#$LPS-LOGGING:GranularityType:Statement //@#$LPS-LOGGING:Localization:NestedStatement LOG.error("Exception caught", e); //#endif } catch (NoSuchMethodException e) { // TODO: Why aren't we throwing an exception here? // Returning null results in NPE and no explanation why. //#if defined(LOGGING) //@#$LPS-LOGGING:GranularityType:Statement //@#$LPS-LOGGING:Localization:NestedStatement LOG.error("Exception caught", e); //#endif } catch (IllegalArgumentException e) { // TODO: Why aren't we throwing an exception here? // Returning null results in NPE and no explanation why. //#if defined(LOGGING) //@#$LPS-LOGGING:GranularityType:Statement //@#$LPS-LOGGING:Localization:NestedStatement LOG.error("Exception caught", e); //#endif } catch (InstantiationException e) { // TODO: Why aren't we throwing an exception here? // Returning null results in NPE and no explanation why. //#if defined(LOGGING) //@#$LPS-LOGGING:GranularityType:Statement //@#$LPS-LOGGING:Localization:NestedStatement LOG.error("Exception caught", e); //#endif } catch (IllegalAccessException e) { // TODO: Why aren't we throwing an exception here? // Returning null results in NPE and no explanation why. //#if defined(LOGGING) //@#$LPS-LOGGING:GranularityType:Statement //@#$LPS-LOGGING:Localization:NestedStatement LOG.error("Exception caught", e); //#endif } catch (InvocationTargetException e) { // TODO: Why aren't we throwing an exception here? // Returning null results in NPE and no explanation why. //#if defined(LOGGING) //@#$LPS-LOGGING:GranularityType:Statement //@#$LPS-LOGGING:Localization:NestedStatement LOG.error("Exception caught", e); //#endif } } return null; } /** * Create a new NotationProvider. * * @param type the provider type * @return the provider * @param object the constructor parameter * @param listener the fig * that refreshes after the NotationProvider has changed * @deprecated for 0.27.2 by tfmorris. Use * {@link #getNotationProvider(int, Object, PropertyChangeListener, NotationName)}. */ @Deprecated public NotationProvider getNotationProvider(int type, Object object, PropertyChangeListener listener) { NotationName name = Notation.findNotation(currentLanguage); return getNotationProvider(type, object, listener, name); } /** * Get a NotationProvider for the current project. * * @param type the provider type * @param object the constructor parameter * @param listener the fig * that refreshes after the NotationProvider has changed * @param name the name of the notation language to use * @return the provider */ public NotationProvider getNotationProvider(int type, Object object, PropertyChangeListener listener, NotationName name) { NotationProvider p = getNotationProvider(type, object, name); p.initialiseListener(listener, object); return p; } /** * This function looks for the requested notation provider type. * It is guaranteed to deliver:<ul> * <li>the requested type of the requested notation language, * <li>the requested type of the default notation, or * <li><code>null</code>. * </ul> * * @param type the provider type * @param name the context (i.e. the notation name) * @return the provider */ private Class getNotationProviderClass(int type, NotationName name) { if (allLanguages.containsKey(name)) { Map<Integer, Class> t = allLanguages.get(name); if (t.containsKey(Integer.valueOf(type))) { return t.get(Integer.valueOf(type)); } } Map<Integer, Class> t = allLanguages.get(defaultLanguage); if (t != null && t.containsKey(Integer.valueOf(type))) { return t.get(Integer.valueOf(type)); } return null; } /** * @param type the provider type * @param notationName the name of the notation (language) * @param provider the provider */ public void addNotationProvider(int type, NotationName notationName, Class provider) { if (allLanguages.containsKey(notationName)) { Map<Integer, Class> t = allLanguages.get(notationName); t.put(Integer.valueOf(type), provider); } else { Map<Integer, Class> t = new HashMap<Integer, Class>(); t.put(Integer.valueOf(type), provider); allLanguages.put(notationName, t); } } /** * @param notationName the UML notation that is to be used as default * if no other is found */ public void setDefaultNotation(NotationName notationName) { if (allLanguages.containsKey(notationName)) { defaultLanguage = notationName; } } /** * We need this to remove modules. * * @param notationName the notation to be removed * @return true if the notation was removed */ public boolean removeNotation(NotationName notationName) { if (defaultLanguage == notationName) { return false; } if (allLanguages.containsKey(notationName)) { return allLanguages.remove(notationName) != null && Notation.removeNotation(notationName); } return false; } /** * Set the default notation language for all users of this factory. * * @param theCurrentLanguage the currentLanguage to set * @deprecated for 0.27.2 by tfmorris. Callers should manage the language * that they want explicitly. */ @Deprecated public static void setCurrentLanguage(String theCurrentLanguage) { NotationProviderFactory2.currentLanguage = theCurrentLanguage; } }