001: package org.andromda.core.translation.library;
002:
003: import java.io.BufferedReader;
004: import java.io.Reader;
005: import java.io.StringReader;
006: import java.io.StringWriter;
007: import java.lang.reflect.Method;
008: import java.util.LinkedHashMap;
009: import java.util.Map;
010:
011: import org.andromda.core.common.ComponentContainer;
012: import org.andromda.core.common.ExceptionUtils;
013: import org.andromda.core.common.XmlObjectFactory;
014: import org.andromda.core.templateengine.TemplateEngine;
015: import org.andromda.core.translation.Translator;
016: import org.apache.commons.lang.StringUtils;
017: import org.apache.commons.lang.builder.ToStringBuilder;
018: import org.apache.log4j.Logger;
019:
020: /**
021: * The LibraryTranslation object which is the intermediary object between the Library and the child Translation
022: * instances.
023: *
024: * @author Chad Brandon
025: */
026: public class LibraryTranslation {
027: private static final Logger logger = Logger
028: .getLogger(LibraryTranslation.class);
029:
030: /**
031: * The parent library to which this LibraryTranslation belongs.
032: */
033: private Library library;
034:
035: /**
036: * After processing by the CartridgeTemplate engine, will contain the processed translation.
037: */
038: private Translation translation;
039:
040: /**
041: * The name of this library translation instance.
042: */
043: private String name;
044:
045: /**
046: * Gets the name of this LibraryTranslation.
047: *
048: * @return String
049: */
050: public String getName() {
051: return name;
052: }
053:
054: /**
055: * Sets the name.
056: *
057: * @param name
058: */
059: public void setName(final String name) {
060: this .name = name;
061: }
062:
063: /**
064: * The path to the template.
065: */
066: private String template;
067:
068: /**
069: * Gets the path to the template for this instance.
070: *
071: * @return String
072: */
073: public String getTemplate() {
074: return template;
075: }
076:
077: /**
078: * Sets the path to the template.
079: *
080: * @param template
081: */
082: public void setTemplate(final String template) {
083: this .template = template;
084: }
085:
086: /**
087: * Returns the Library that this LibraryTranslation belongs too.
088: *
089: * @return Library
090: */
091: public Library getLibrary() {
092: return library;
093: }
094:
095: /**
096: * Sets the {@link Library} to which this LibraryInstance belongs.
097: *
098: * @param library
099: */
100: public void setLibrary(final Library library) {
101: this .library = library;
102: }
103:
104: /**
105: * The name given to the variable containing the context element.
106: */
107: private String variable;
108:
109: /**
110: * Gets the variable name which is made available to the translation template.
111: *
112: * @return the variable name.
113: */
114: public String getVariable() {
115: return this .variable;
116: }
117:
118: /**
119: * Sets the variable name which is made available to the translation template.
120: *
121: * @param variable the variable name.
122: */
123: public void setVariable(final String variable) {
124: this .variable = variable;
125: }
126:
127: /**
128: * The Translator implementation to use. This is required.
129: */
130: private String translatorClass;
131:
132: /**
133: * Sets the Translator class that will perform the translation processing.
134: *
135: * @param translatorClass the class of the translator.
136: */
137: public void setTranslator(final String translatorClass) {
138: this .translatorClass = translatorClass;
139: final ComponentContainer container = ComponentContainer
140: .instance();
141: container.unregisterComponent(translatorClass);
142: container.registerComponentType(translatorClass);
143: }
144:
145: /**
146: * Gets the Translator instance that will perform processing of the template.
147: *
148: * @return Translator
149: */
150: public Translator getTranslator() {
151: final String methodName = "LibraryTranslation.getTranslator";
152: final Translator translator = (Translator) ComponentContainer
153: .instance().findComponent(this .translatorClass,
154: Translator.class);
155: if (translator == null) {
156: throw new LibraryException(
157: methodName
158: + " - a translator implementation must be defined, "
159: + " please check your translator library --> '"
160: + this .library.getResource() + "'");
161: }
162: return translator;
163: }
164:
165: /**
166: * Calls the handlerMethod from a translation fragment. Each handle method must take a java.lang.String as the first
167: * argument (the body of the fragment from the translation template) and a java.lang.Object for the second argument
168: * (the node being parsed that we may need to retrieve any additional information from).
169: *
170: * @param name the name of the fragment to retrieve.
171: * @param node the node Object which from the parsed expression.
172: * @param kind the kind of the translation fragment to handle.
173: */
174: public void handleTranslationFragment(final String name,
175: final String kind, final Object node) {
176: ExceptionUtils.checkNull("node", node);
177: if (this .translation != null && this .getTranslator() != null) {
178: final String translation = this .getTranslationFragment(
179: name, kind);
180: final Fragment fragment = this .translation
181: .getFragment(name);
182: if (fragment != null) {
183: String handlerMethod = fragment.getHandlerMethod();
184: if (StringUtils.isNotEmpty(handlerMethod)) {
185: Class[] argTypes = new Class[] {
186: java.lang.String.class,
187: java.lang.Object.class };
188:
189: try {
190: final Method method = this .getTranslator()
191: .getClass().getMethod(handlerMethod,
192: argTypes);
193:
194: // add the translation as the first arg
195: final Object[] args = new Object[] {
196: translation, node };
197:
198: method.invoke(this .getTranslator(), args);
199: } catch (final NoSuchMethodException exception) {
200: String errMsg = "the translator '"
201: + this .getTranslator().getClass()
202: + "' must implement the method '"
203: + handlerMethod
204: + "'"
205: + StringUtils.join(argTypes, ",")
206: + "'"
207: + " in order to handle processing of the fragment --> '"
208: + name + "'";
209: logger.error(errMsg);
210: } catch (final Throwable throwable) {
211: throw new LibraryException(throwable);
212: }
213: }
214: }
215: }
216: }
217:
218: /**
219: * Gets the current "translated" value of this fragmentName for resulting from the last processTranslation method
220: *
221: * @param name the name of the fragment to retrieve.
222: * @param kind the kind or type of fragment to retrieve (this is the based on the expression type: body, inv, post,
223: * pre, etc).
224: * @return String the value of the translated fragment or null of one wasn't found with the specified name.
225: */
226: public String getTranslationFragment(final String name,
227: final String kind) {
228: String fragment = null;
229: if (this .translation != null) {
230: fragment = this .translation.getTranslated(name, kind);
231: }
232: return fragment;
233: }
234:
235: /**
236: * The processed translation template as a Reader.
237: *
238: * @param translationInput
239: */
240: protected void setTranslation(final Reader translationInput) {
241: ExceptionUtils.checkNull("translationInput", translationInput);
242: try {
243: this .translation = (Translation) XmlObjectFactory
244: .getInstance(Translation.class).getObject(
245: translationInput);
246: this .translation.setLibraryTranslation(this );
247: } catch (final Throwable throwable) {
248: throw new LibraryException(throwable);
249: }
250: }
251:
252: /**
253: * Processes the template belonging to this LibraryTranslation and returns the Translation objects. If
254: * <code>template</code> hasn't been set (i.e. is null, then this method won't do anything but return a null
255: * value).
256: *
257: * @param templateContext any key/value pairs that should be passed to the TemplateEngine while processing the
258: * translation template.
259: * @return Translation the Translation created from the processing the translation template.
260: */
261: public Translation processTranslation(Map templateContext) {
262: logger.debug("processing translation template --> '"
263: + this .getTemplate() + "'"
264: + "' with templateContext --> '" + templateContext
265: + "'");
266: if (this .getTemplate() != null) {
267: if (templateContext == null) {
268: templateContext = new LinkedHashMap();
269: }
270: this .getLibrary().populateTemplateContext(templateContext);
271:
272: try {
273: final TemplateEngine engine = this .getLibrary()
274: .getTemplateEngine();
275:
276: final StringWriter output = new StringWriter();
277: engine.processTemplate(this .getTemplate(),
278: templateContext, output);
279: final String outputString = output.toString();
280: final BufferedReader input = new BufferedReader(
281: new StringReader(outputString));
282: if (logger.isDebugEnabled()) {
283: logger.debug("processed output --> '"
284: + outputString + "'");
285: }
286:
287: // load Reader into the translation
288: this .setTranslation(input);
289: } catch (final Throwable throwable) {
290: throw new LibraryException(throwable);
291: }
292: }
293: return this .translation;
294: }
295:
296: /**
297: * @see java.lang.Object#toString()
298: */
299: public String toString() {
300: return ToStringBuilder.reflectionToString(this);
301: }
302: }
|