1 /***
2 * Copyright (C) 2008 rweber <quietgenie@users.sourceforge.net>
3 *
4 * This file is part of CsvObjectMapper.
5 *
6 * CsvObjectMapper is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CsvObjectMapper is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with CsvObjectMapper. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /***
21 *
22 */
23 package com.projectnine.csvmapper;
24
25 import java.util.List;
26 import java.util.Vector;
27
28 import org.apache.commons.jexl.JexlContext;
29 import org.apache.commons.jexl.resolver.FlatResolver;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33 /***
34 * A custom variable resolver that performs default variable resolution.
35 * However, when a JEXL expression of the form '#DEFINE [variableName] =
36 * [fully.qualified.class.Name] [constructor,"args"];' this resolver allows JEXL
37 * to instantiate new instances of objects and add them to the context.
38 *
39 * @author robweber
40 *
41 */
42 public class PoundDefineJexlResolver extends FlatResolver {
43 private static final Log log = LogFactory
44 .getLog(PoundDefineJexlResolver.class);
45
46 public static final String POUND_DEFINE_EXPRESSION_START = "'#DEFINE";
47 public static final String INTERNAL_QUOTATION_MARK = "|";
48
49
50
51
52
53
54
55
56 @SuppressWarnings("unchecked")
57 @Override
58 public Object evaluate(JexlContext context, String rawExpression) {
59 if (rawExpression.startsWith(POUND_DEFINE_EXPRESSION_START)) {
60 String expression = rawExpression.substring(1, rawExpression
61 .length() - 1);
62 String[] expressionParts = expression.split(" ");
63 try {
64 String variableName = expressionParts[1];
65 String className = expressionParts[3];
66 List<Class<? extends Object>> parameterTypes = new Vector<Class<? extends Object>>();
67 List<Object> arguments = new Vector<Object>();
68 if (expressionParts.length >= 4) {
69 if (expression.indexOf(INTERNAL_QUOTATION_MARK) != -1
70 && expression.lastIndexOf(INTERNAL_QUOTATION_MARK) != expression
71 .indexOf(INTERNAL_QUOTATION_MARK)) {
72 expressionParts = massageStringLiterals(expression);
73 }
74 for (int i = 4; i < expressionParts.length; i++) {
75 String argumentReference = expressionParts[i];
76 if (!argumentReference
77 .startsWith(INTERNAL_QUOTATION_MARK)) {
78 Object argument = context.getVars().get(
79 argumentReference);
80 log.debug("Adding an argument called "
81 + argumentReference + " of type "
82 + argument.getClass().getName()
83 + " to the argument list.");
84 arguments.add(argument);
85 parameterTypes.add(argument.getClass());
86 } else {
87 String stringExpression = expressionParts[i]
88 .replace("\0", " ");
89 String argument = stringExpression.substring(1,
90 stringExpression.length() - 1);
91 log.debug("Adding the string argument, " + argument
92 + ", to the argument list.");
93 arguments.add(argument);
94 parameterTypes.add(String.class);
95 }
96 }
97 }
98
99 Object o = Class.forName(className).getConstructor(
100 parameterTypes
101 .toArray(new Class[parameterTypes.size()]))
102 .newInstance(arguments.toArray());
103
104 context.getVars().put(variableName, o);
105 } catch (Throwable t) {
106 throw new RuntimeException(t);
107 }
108 }
109 return super.evaluate(context, rawExpression);
110 }
111
112 private static String[] massageStringLiterals(String rawExpression) {
113 String expression = rawMassageStringLiterals(rawExpression);
114
115 return expression.split(" ");
116 }
117
118 /***
119 * @param expression
120 * @return
121 */
122 private static String rawMassageStringLiterals(String expression) {
123 StringBuffer currentStringLiteralBuffer = new StringBuffer();
124 StringBuffer expressionBuffer = new StringBuffer();
125 boolean inStringLiteral = false;
126 for (int i = 0; i < expression.length(); i++) {
127 if (String.valueOf(expression.charAt(i)).equals(
128 INTERNAL_QUOTATION_MARK)) {
129 if (inStringLiteral) {
130 currentStringLiteralBuffer.append(INTERNAL_QUOTATION_MARK);
131 inStringLiteral = false;
132 String stringLiteral = currentStringLiteralBuffer
133 .toString();
134 String massagedStringLiteral = stringLiteral.replace(" ",
135 "\0");
136 log.debug("Adding the string literal, " + stringLiteral
137 + ", to the expression as: "
138 + massagedStringLiteral + ".");
139
140 expressionBuffer.append(massagedStringLiteral);
141 currentStringLiteralBuffer = new StringBuffer();
142 } else {
143 currentStringLiteralBuffer.append(INTERNAL_QUOTATION_MARK);
144 inStringLiteral = true;
145 }
146 } else {
147 if (inStringLiteral) {
148 currentStringLiteralBuffer.append(expression.charAt(i));
149 } else {
150 expressionBuffer.append(expression.charAt(i));
151 }
152 }
153 }
154 return expressionBuffer.toString();
155 }
156
157 public static void main(String[] args) {
158 System.out
159 .println(PoundDefineJexlResolver
160 .rawMassageStringLiterals("'#DEFINE sdfPlusTime = java.text.SimpleDateFormat |MM/dd/yyyy hh:mm a zzz|'"));
161 }
162
163 }