001: /*
002: * transformica 2
003: * Code generator
004: * Copyright (C) 2004 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.pavelvlasov.com/pv/content/menu.show@id=products.transformica.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.transformica;
024:
025: import java.io.BufferedReader;
026: import java.io.IOException;
027: import java.io.StringReader;
028: import java.io.StringWriter;
029: import java.util.HashMap;
030: import java.util.HashSet;
031: import java.util.Iterator;
032: import java.util.Map;
033: import java.util.Set;
034:
035: import org.apache.commons.jxpath.JXPathContext;
036: import org.apache.tools.ant.Project;
037: import org.apache.velocity.VelocityContext;
038: import org.apache.velocity.app.Velocity;
039: import org.apache.velocity.context.Context;
040:
041: import biz.hammurapi.transformica.helpers.OgnlEvaluator;
042: import biz.hammurapi.util.Visitable;
043: import biz.hammurapi.util.VisitableBase;
044:
045: /**
046: * @author Pavel Vlasov
047: * @version $Revision: 1.1 $
048: */
049: public class TransformSession {
050:
051: private Visitable root;
052: private TransformTask task;
053:
054: TransformSession(TransformTask task) {
055: super ();
056: this .task = task;
057: }
058:
059: public Visitable getRoot() {
060: return root;
061: }
062:
063: public TransformTask getTask() {
064: return task;
065: }
066:
067: void setRoot(Visitable root) {
068: this .root = root;
069: }
070:
071: public void debug(String msg) {
072: log(msg, Project.MSG_DEBUG);
073: }
074:
075: public void info(String msg) {
076: log(msg, Project.MSG_INFO);
077: }
078:
079: public void verbose(String msg) {
080: log(msg, Project.MSG_VERBOSE);
081: }
082:
083: public void error(String msg) {
084: log(msg, Project.MSG_ERR);
085: }
086:
087: public void warn(String msg) {
088: log(msg, Project.MSG_WARN);
089: }
090:
091: public void log(String msg, int level) {
092: task.log(msg, level);
093: }
094:
095: public void log(String msg) {
096: task.log(msg);
097: }
098:
099: /**
100: * Includes element processed with first matched channel
101: * @return
102: */
103: public String include(Object modelElement)
104: throws TransformicaException {
105: return include(modelElement, (String) null);
106: }
107:
108: /**
109: * Includes element processed with first matched channel
110: * @return
111: */
112: public String include(Object modelElement, int indent)
113: throws TransformicaException {
114: return indent(include(modelElement), indent);
115: }
116:
117: /**
118: * Includes element processed by a named channel
119: */
120: public String include(Object modelElement, String channelName)
121: throws TransformicaException {
122: Iterator it = task.getChannels().iterator();
123: while (it.hasNext()) {
124: Channel channel = (Channel) it.next();
125: if (channel.getCompositeAcceptor().accept(modelElement)
126: && (channelName == null || (channel.getName() != null && channelName
127: .equals(channel.getName())))) {
128: return channel.include(modelElement);
129: }
130: }
131: warn("No channel mactched " + modelElement + " ["
132: + modelElement.getClass().getName() + "]");
133: return "";
134: }
135:
136: /**
137: * Includes element processed by a named channel
138: */
139: public String include(Object modelElement, String channelName,
140: int indent) throws TransformicaException {
141: return indent(include(modelElement, channelName), indent);
142:
143: }
144:
145: /**
146: * Includes element processed by a named template
147: * @param element
148: * @param templateName
149: * @return
150: */
151: public String includeTemplate(Object element, String templateName)
152: throws TransformicaException {
153: StringWriter sw = new StringWriter();
154: VelocityContext context = newContext();
155: try {
156: context.put("element", element);
157:
158: JXPathContext jxPath = JXPathContext.newContext(element);
159: context.put("jxpath", jxPath);
160:
161: OgnlEvaluator ognl = new OgnlEvaluator(element);
162: context.put("ognl", ognl);
163:
164: debug("Loading template: " + templateName);
165: Velocity.getTemplate(templateName).merge(context, sw);
166: sw.close();
167: return sw.toString();
168: } catch (Exception e) {
169: error("Exception " + e + " while processing " + element
170: + " [" + element.getClass().getName() + "]");
171: throw new TransformicaException(e);
172: } finally {
173: releaseContext(context);
174: }
175: }
176:
177: /**
178: * Includes element processed by a named template
179: * @param element
180: * @param templateName
181: * @return
182: */
183: public String includeTemplate(Object element, String templateName,
184: int indent) throws TransformicaException {
185: return indent(includeTemplate(element, templateName), indent);
186: }
187:
188: /**
189: * Evaluates text and includes it into output
190: * @param element "element" context object
191: * @param text to evaluate
192: * @return
193: */
194: public String evaluate(Object element, String text)
195: throws TransformicaException {
196: if (text == null) {
197: return "";
198: } else {
199: VelocityContext context = newContext();
200: try {
201: context.put("element", element);
202:
203: JXPathContext jxPath = JXPathContext
204: .newContext(element);
205: context.put("jxpath", jxPath);
206:
207: OgnlEvaluator ognl = new OgnlEvaluator(element);
208: context.put("ognl", ognl);
209:
210: StringWriter sw = new StringWriter();
211: Velocity.evaluate(context, sw, element + " ["
212: + element.getClass().getName() + "]", text);
213: sw.close();
214: return sw.toString();
215: } catch (Exception e) {
216: error("Exception " + e + " while processing " + element
217: + " [" + element.getClass().getName() + "]");
218: throw new TransformicaException(e);
219: } finally {
220: releaseContext(context);
221: }
222: }
223: }
224:
225: /**
226: * Includes element processed by a named template
227: * @param element
228: * @param templateName
229: * @return
230: */
231: public String evaluate(Object element, String text, int indent)
232: throws TransformicaException {
233: return indent(evaluate(element, text), indent);
234: }
235:
236: /**
237: * Navigates through model tree and collects output from a named
238: * channel. Use this method to generate one file from many elements,
239: * for example, deployment descriptor.
240: * @param root ModelElement to start traversing from.
241: * @param channelName Channel name
242: * @return
243: */
244: public String includeRecursive(Object root, String channelName)
245: throws TransformicaException {
246: try {
247: Channel channel = task.lookupChannel(channelName);
248: if (channel == null) {
249: warn("Channel not found: " + channelName);
250: return "";
251: }
252:
253: StringWriter sw = new StringWriter();
254: IncludeVisitor iv = new IncludeVisitor(this , channel, sw);
255: VisitableBase.object2visitor(root, iv);
256: sw.close();
257: return sw.toString();
258: } catch (IOException e) {
259: error("Error in includeRecursive() for " + root);
260: throw new TransformicaException(e);
261: }
262:
263: }
264:
265: /**
266: * Navigates through model tree and collects output from a named
267: * channel. Use this method to generate one file from many elements,
268: * for example, deployment descriptor.
269: * @param root ModelElement to start traversing from.
270: * @param channelName Channel name
271: * @return
272: */
273: public String includeRecursive(Object root, String channelName,
274: int indent) throws TransformicaException {
275: return indent(includeRecursive(root, channelName), indent);
276: }
277:
278: private Map attributes = new HashMap();
279:
280: public Object setAttribute(String name, Object value) {
281: return attributes.put(name, value);
282: }
283:
284: public Object getAttribute(String name) {
285: return attributes.get(name);
286: }
287:
288: public Object removeAttribute(String name) {
289: return attributes.remove(name);
290: }
291:
292: /**
293: * Breaks string into lines, indents every line
294: * and concantenates them back.
295: * If indent is negative - removes first "indent"
296: * characters from each line.
297: */
298: public String indent(String text, int indent)
299: throws TransformicaException {
300: try {
301: if (indent == 0) {
302: return text;
303: } else {
304: StringBuffer indentBuf = new StringBuffer();
305: while (indentBuf.length() < indent) {
306: indentBuf.append(" ");
307: }
308: String indentString = indentBuf.toString();
309: StringBuffer ret = new StringBuffer();
310: BufferedReader br = new BufferedReader(
311: new StringReader(text));
312: String line;
313: while ((line = br.readLine()) != null) {
314: if (ret.length() > 0) {
315: ret
316: .append(System
317: .getProperty("line.separator"));
318: }
319:
320: if (indent > 0) {
321: ret.append(indentString);
322: ret.append(line);
323: } else if (line.length() > indent) {
324: ret.append(line.substring(indent));
325: }
326: }
327: return ret.toString();
328: }
329: } catch (Exception e) {
330: error("Indent exception");
331: throw new TransformicaException(e);
332: }
333: }
334:
335: private ThreadLocal currentContext = new ThreadLocal();
336:
337: /**
338: * Creates a new Velocity context. Chains it with current
339: * thread context if any.
340: * @return Velocity context for the thread
341: */
342: public VelocityContext newContext() {
343: Context cc = (Context) currentContext.get();
344: VelocityContext ret = cc == null ? new VelocityContext()
345: : new VelocityContext(cc);
346: ret.put("session", this );
347: currentContext.set(ret);
348: return ret;
349: }
350:
351: /**
352: * Restores previous velocity context
353: * @param context
354: */
355: public void releaseContext(VelocityContext context) {
356: if (context != null) {
357: currentContext.set(context.getChainedContext());
358: }
359: }
360:
361: void reset() {
362: attributes.clear();
363: currentContext.set(null);
364: root = null;
365: matched.clear();
366: }
367:
368: private Set matched = new HashSet();
369:
370: public void setMatched(Object element) {
371: matched.add(element);
372: }
373:
374: public boolean isMatched(Object element) {
375: return matched.contains(element);
376: }
377: }
|