001package org.andromda.core.common; 002 003import java.io.File; 004import java.net.URL; 005import java.util.ArrayList; 006import java.util.Collection; 007import java.util.LinkedHashMap; 008import java.util.List; 009import java.util.Map; 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.andromda.core.templateengine.TemplateEngine; 015import org.apache.log4j.Logger; 016 017/** 018 * Represents the base plugin of AndroMDA. All Plugin instances inherit from this class. 019 * 020 * @author Chad Brandon 021 */ 022public abstract class BasePlugin 023 extends BaseNamespaceComponent 024 implements Plugin 025{ 026 /** 027 * Property references made available to the plugin 028 */ 029 private final Collection<String> propertyReferences = new ArrayList<String>(); 030 031 /** 032 * The template objects made available to templates of this BasePlugin. 033 */ 034 private final Collection<TemplateObject> templateObjects = new ArrayList<TemplateObject>(); 035 036 /** 037 * @see org.andromda.core.common.Plugin#initialize() 038 */ 039 public void initialize() 040 throws Exception 041 { 042 // set the template engine merge location (this needs to be 043 // set before the template engine is initialized) so that the 044 // merge property can be set once on the template engine. 045 final Property mergeProperty = 046 Namespaces.instance().getProperty( 047 this.getNamespace(), 048 NamespaceProperties.MERGE_LOCATION, 049 false); 050 this.mergeLocation = mergeProperty != null ? new File(mergeProperty.getValue()).toURI().toURL() : null; 051 if (this.mergeLocation != null) 052 { 053 this.getTemplateEngine().setMergeLocation(this.getMergeLocation().getFile()); 054 } 055 this.getTemplateEngine().initialize(this.getNamespace()); 056 for (final TemplateObject templateObject : this.templateObjects) { 057 templateObject.setResource(this.getResource()); 058 templateObject.setNamespace(this.getNamespace()); 059 } 060 } 061 062 /** 063 * The current cartridge merge location. 064 */ 065 private URL mergeLocation; 066 067 /** 068 * Gets the current merge location for this plugin. 069 * 070 * @return the merge location (a file path). 071 */ 072 protected URL getMergeLocation() 073 { 074 return this.mergeLocation; 075 } 076 077 /** 078 * @see org.andromda.core.common.Plugin#shutdown() 079 */ 080 public void shutdown() 081 { 082 this.getTemplateEngine().shutdown(); 083 } 084 085 /** 086 * Adds the <code>templateObject</code> to the collection of template objects that will be made available to the 087 * plugin during processing. 088 * 089 * @param templateObject the TemplateObject to add. 090 */ 091 public void addTemplateObject(final TemplateObject templateObject) 092 { 093 if (templateObject != null) 094 { 095 this.templateObjects.add(templateObject); 096 } 097 } 098 099 /** 100 * Adds a macro library to the TemplateEngine used by this BasePlugin. 101 * 102 * @param macrolibrary 103 */ 104 public void addMacrolibrary(final String macrolibrary) 105 { 106 this.getTemplateEngine().addMacroLibrary(macrolibrary); 107 } 108 109 /** 110 * @see org.andromda.core.common.Plugin#getTemplateObjects() 111 */ 112 public Collection<TemplateObject> getTemplateObjects() 113 { 114 return this.templateObjects; 115 } 116 117 private String templateEngineClass; 118 119 /** 120 * Sets the template engine class for this cartridge. 121 * 122 * @param templateEngineClass the Class of the template engine implementation. 123 */ 124 public void setTemplateEngineClass(final String templateEngineClass) 125 { 126 this.templateEngineClass = templateEngineClass; 127 } 128 129 /** 130 * The template engine that this plugin will use. 131 */ 132 private TemplateEngine templateEngine = null; 133 134 /** 135 * @see org.andromda.core.common.Plugin#getTemplateEngine() 136 */ 137 public TemplateEngine getTemplateEngine() 138 { 139 if (this.templateEngine == null) 140 { 141 this.templateEngine = 142 (TemplateEngine)ComponentContainer.instance().newComponent( 143 this.templateEngineClass, TemplateEngine.class); 144 } 145 return this.templateEngine; 146 } 147 148 /** 149 * @see org.andromda.core.common.Plugin#getPropertyReferences() 150 */ 151 public String[] getPropertyReferences() 152 { 153 return this.propertyReferences.toArray(new String[this.propertyReferences.size()]); 154 } 155 156 /** 157 * Adds a property reference. Property references are those properties that are expected to be supplied by the 158 * calling client. These supplied properties are made available to the template during processing. 159 * 160 * @param reference the namespace of the reference. 161 */ 162 public void addPropertyReference(final String reference) 163 { 164 this.propertyReferences.add(reference); 165 } 166 167 /** 168 * Populates the <code>templateContext</code> with the properties and template objects defined in the 169 * <code>plugin</code>'s descriptor. If the <code>templateContext</code> is null, a new Map instance will be created 170 * before populating the context. 171 * 172 * @param templateContext the context of the template to populate. 173 */ 174 protected void populateTemplateContext(Map<String, Object> templateContext) 175 { 176 if (templateContext == null) 177 { 178 templateContext = new LinkedHashMap<String, Object>(); 179 } 180 this.addTemplateObjectsToContext(templateContext); 181 this.addPropertyReferencesToContext(templateContext); 182 } 183 184 /** 185 * Takes all the template objects defined in the plugin's descriptor and places them in the 186 * <code>templateContext</code>. 187 * 188 * @param templateContext the template context 189 */ 190 private void addTemplateObjectsToContext(final Map<String, Object> templateContext) 191 { 192 // add all the TemplateObject objects to the template context 193 final Collection<TemplateObject> templateObjects = this.getTemplateObjects(); 194 if (templateObjects != null && !templateObjects.isEmpty()) 195 { 196 for (TemplateObject templateObject : templateObjects) 197 { 198 templateContext.put( 199 templateObject.getName(), 200 templateObject.getObject()); 201 } 202 } 203 } 204 205 /** 206 * Takes all the property references defined in the plugin's descriptor and looks up the corresponding values 207 * supplied by the calling client and supplies them to the <code>templateContext</code>. 208 * 209 * @param templateContext the template context 210 */ 211 private void addPropertyReferencesToContext(final Map<String, Object> templateContext) 212 { 213 final String[] propertyReferences = this.getPropertyReferences(); 214 if (propertyReferences != null && propertyReferences.length > 0) 215 { 216 final Namespaces namespaces = Namespaces.instance(); 217 for (final String reference : propertyReferences) { 218 templateContext.put( 219 reference, 220 namespaces.getPropertyValue( 221 this.getNamespace(), 222 reference)); 223 } 224 } 225 } 226 227 /** 228 * Stores the contents of the plugin. 229 */ 230 private List<String> contents = null; 231 232 /** 233 * @see org.andromda.core.common.Plugin#getContents() 234 */ 235 public List<String> getContents() 236 { 237 if (this.contents == null) 238 { 239 if (ResourceUtils.isArchive(this.getResource())) 240 { 241 this.contents = ResourceUtils.getClassPathArchiveContents(this.getResource()); 242 if (this.getMergeLocation() != null) 243 { 244 final Collection<String> mergeContents = ResourceUtils.getDirectoryContents( 245 this.getMergeLocation(), 246 0); 247 if (mergeContents != null && !mergeContents.isEmpty()) 248 { 249 this.contents.addAll(mergeContents); 250 } 251 } 252 } 253 else 254 { 255 // we step down 1 level if its a directory (instead of an 256 // archive since we get the contents relative to the plugin 257 // resource which is in the META-INF directory 258 this.contents = ResourceUtils.getDirectoryContents( 259 this.getResource(), 260 2); 261 } 262 } 263 return contents; 264 } 265 266 /** 267 * Retrieves the logger instance that should be used for logging output for the plugin sub classes. 268 * 269 * @return the logger. 270 */ 271 protected Logger getLogger() 272 { 273 return AndroMDALogger.getNamespaceLogger(this.getNamespace()); 274 } 275 276 /** 277 * @see Object#toString() 278 */ 279 public String toString() 280 { 281 return super.toString() + '[' + this.getNamespace() + ']'; 282 } 283}