001package org.andromda.core.profile; 002 003import java.io.Serializable; 004import java.net.URL; 005import java.util.Collection; 006import java.util.LinkedHashMap; 007import java.util.Map; 008import org.andromda.core.common.ComponentContainer; 009import org.andromda.core.common.XmlObjectFactory; 010import org.andromda.core.configuration.NamespaceProperties; 011import org.andromda.core.configuration.Namespaces; 012import org.andromda.core.configuration.Property; 013import org.andromda.core.namespace.BaseNamespaceComponent; 014import org.apache.commons.lang.StringUtils; 015 016/** 017 * Represents an AndroMDA profile applied to a model. 018 * Profiles allow us to extend aspects of a model. 019 * 020 * @author Chad Brandon 021 * @author Bob Fields 022 */ 023public class Profile 024 extends BaseNamespaceComponent 025 implements Serializable 026{ 027 private static final long serialVersionUID = 34L; 028 029 /** 030 * The shared instance of this class. 031 */ 032 private static Profile instance; 033 034 /** 035 * Gets the shared instance of this class. 036 * 037 * @return the shared instance. 038 */ 039 public static Profile instance() 040 { 041 if (instance == null) 042 { 043 instance = new Profile(); 044 } 045 return instance; 046 } 047 048 /** 049 * Stores the elements for the profile (by name). 050 */ 051 private final Map<String, String> elements = new LinkedHashMap<String, String>(); 052 053 /** 054 * Adds a new element to this namespace registry. 055 * @param name 056 * @param value 057 */ 058 public void addElement( 059 final String name, 060 final String value) 061 { 062 this.elements.put( 063 name, 064 value); 065 } 066 067 /** 068 * Gets the profile value (if one is available) 069 * for the given name, otherwise returns name. 070 * 071 * @param name the profile name to retrieve. 072 * @return the value. 073 */ 074 public String get(String name) 075 { 076 name = StringUtils.trim(name); 077 // - attempt to get the profile value from the profile defined 078 // by the profile mappings uri first 079 String value = this.elements.get(name); 080 081 // - if we can't get any profile value from an the override profile 082 // mapping, then we resort to the ones defined in the namespace 083 if (StringUtils.isBlank(value)) 084 { 085 Map<String, String> namespaceElements = this.getNamespaceElements(this.getNamespace()); 086 if (namespaceElements != null) 087 { 088 value = namespaceElements.get(name); 089 } 090 if (value == null) 091 { 092 namespaceElements = this.getNamespaceElements(Namespaces.DEFAULT); 093 if (namespaceElements != null) 094 { 095 value = namespaceElements.get(name); 096 } 097 } 098 } 099 return value != null ? value : name; 100 } 101 102 /** 103 * Initializes this profile instance. 104 */ 105 public void initialize() 106 { 107 final Collection<Profile> profiles = ComponentContainer.instance().findComponentsOfType(Profile.class); 108 for (final Profile profile : profiles) 109 { 110 String namespace = profile.getNamespace(); 111 if (Namespaces.instance().isShared(namespace)) 112 { 113 profile.setNamespace(Namespaces.DEFAULT); 114 } 115 this.addElements(profile); 116 } 117 } 118 119 /** 120 * Refreshes the profile instance. 121 */ 122 public void refresh() 123 { 124 // - clear out the instance's elements 125 this.elements.clear(); 126 try 127 { 128 final Property mappingsUri = 129 Namespaces.instance().getProperty( 130 Namespaces.DEFAULT, 131 NamespaceProperties.PROFILE_MAPPINGS_URI, 132 false); 133 final String mappingsUriValue = mappingsUri != null ? mappingsUri.getValue() : null; 134 if (mappingsUriValue != null) 135 { 136 final XmlObjectFactory factory = XmlObjectFactory.getInstance(Profile.class); 137 final Profile profile = (Profile)factory.getObject(new URL(mappingsUriValue.trim())); 138 this.elements.putAll(profile.elements); 139 } 140 } 141 catch (final Throwable throwable) 142 { 143 throw new ProfileException(throwable); 144 } 145 } 146 147 /** 148 * Stores all elements. 149 */ 150 private final Map<String, Map<String, String>> allElements = new LinkedHashMap<String, Map<String, String>>(); 151 152 /** 153 * Adds the elements to the internal elements map. 154 * @param profile Profile 155 */ 156 private void addElements(final Profile profile) 157 { 158 final Collection<String> elements = profile != null ? profile.elements.keySet() : null; 159 if (elements != null && profile != null) 160 { 161 final String namespace = profile.getNamespace(); 162 final Map<String, String> namespaceElements = this.getNamespaceElements(namespace); 163 for (final String name : elements) 164 { 165 namespaceElements.put( 166 name, 167 profile.elements.get(name)); 168 } 169 } 170 } 171 172 /** 173 * Adds a namespace element for the given namespace with the given name and 174 * value. 175 * @param namespace the namespace for which to add the namespace element. 176 * @param name the element name. 177 * @param value the element value. 178 */ 179 public void addElement( 180 final String namespace, 181 final String name, 182 final String value) 183 { 184 final Map<String, String> namespaceElements = this.getNamespaceElements(namespace); 185 namespaceElements.put( 186 name, 187 value); 188 } 189 190 /** 191 * Retrieves the namespace elements map for the given namespace. 192 * If one doesn't exist, then a new one is created. 193 * @param namespace the namespace for which to retrieve the namespace elements 194 * @return the namespace element map 195 */ 196 private Map<String, String> getNamespaceElements(final String namespace) 197 { 198 Map<String, String> namespaceElements = this.allElements.get(namespace); 199 if (namespaceElements == null) 200 { 201 namespaceElements = new LinkedHashMap<String, String>(); 202 this.allElements.put( 203 namespace, 204 namespaceElements); 205 } 206 return namespaceElements; 207 } 208 209 /** 210 * Shuts down the shared instance and releases any used resources. 211 */ 212 public void shutdown() 213 { 214 Profile.instance = null; 215 } 216}