001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.config.types;
030:
031: import com.caucho.config.ConfigException;
032: import com.caucho.el.EL;
033: import com.caucho.util.CharBuffer;
034: import com.caucho.util.L10N;
035:
036: import javax.annotation.PostConstruct;
037: import java.lang.reflect.Constructor;
038: import java.util.ArrayList;
039:
040: /**
041: * Configuration for an instantiation
042: */
043: public class InstantiationConfig {
044: private static L10N L = new L10N(InstantiationConfig.class);
045:
046: private String _value;
047: private Class _type;
048:
049: private ArrayList<Object> _args = new ArrayList<Object>();
050:
051: private int _index;
052:
053: /**
054: * Returns the type.
055: */
056: public Class getType() {
057: return _type;
058: }
059:
060: /**
061: * Adds the text value to the signature.
062: */
063: public void addText(String value) {
064: _value = value;
065: }
066:
067: /**
068: * Adds an argument.
069: */
070: public void addArg(Object value) {
071: _args.add(value);
072: }
073:
074: /**
075: * Initialize the signature.
076: */
077: @PostConstruct
078: public void init() throws Exception {
079: if (_value == null)
080: throw new ConfigException(L
081: .l("An instantiation requires the class name."));
082:
083: parseSignature();
084: }
085:
086: /**
087: * Instantiates the object.
088: */
089: public Object create() throws Exception {
090: Object[] args = new Object[_args.size()];
091:
092: Class[] paramTypes = new Class[args.length];
093:
094: for (int i = 0; i < _args.size(); i++) {
095: Object arg = _args.get(i);
096:
097: args[i] = arg;
098: if (arg == null)
099: paramTypes[i] = Object.class;
100: else
101: paramTypes[i] = arg.getClass();
102: }
103:
104: Constructor constructor = getConstructor(_type, paramTypes);
105:
106: if (constructor == null)
107: throw new ConfigException(L.l(
108: "Can't find public constructor for `{0}'.", _type
109: .getName()));
110:
111: return constructor.newInstance(args);
112: }
113:
114: private Constructor getConstructor(Class cl, Class[] types) {
115: Constructor[] constructors = cl.getConstructors();
116:
117: for (int i = 0; i < constructors.length; i++) {
118: Class[] args = constructors[i].getParameterTypes();
119:
120: if (args.length == types.length)
121: return constructors[i];
122: }
123:
124: return null;
125: }
126:
127: /**
128: * Parses the constructor.
129: */
130: private void parseSignature() throws Exception {
131: _index = 0;
132:
133: String type = parseType(skipWhitespace(read()));
134:
135: ClassLoader loader = Thread.currentThread()
136: .getContextClassLoader();
137:
138: _type = Class.forName(type, false, loader);
139:
140: int ch = skipWhitespace(read());
141:
142: if (ch < 0)
143: return;
144:
145: if (ch != '(')
146: throw new ConfigException(L.l(
147: "expected `(' in constructor `{0}'", _value));
148:
149: CharBuffer cb = CharBuffer.allocate();
150:
151: ch = ',';
152: while (ch == ',') {
153: ch = skipWhitespace(read());
154:
155: cb.clear();
156:
157: if (ch == '\'' || ch == '"') {
158: int end = ch;
159:
160: for (ch = read(); ch > 0 && ch != end; ch = read()) {
161: if (ch == '\\')
162: cb.append(read());
163: else
164: cb.append((char) ch);
165: }
166:
167: _args.add(cb.toString());
168: } else if (ch == '$') {
169: ch = read();
170:
171: if (ch != '{')
172: throw new ConfigException(L.l(
173: "expected EL-expression at $ in `{0}'",
174: _value));
175:
176: for (ch = read(); ch > 0 && ch != '}'; ch = read()) {
177: cb.append((char) ch);
178: }
179:
180: _args.add(EL.evalObject(cb.toString()));
181: } else
182: throw new ConfigException(L.l(
183: "expected string or EL-expression in `{0}'",
184: _value));
185: }
186: }
187:
188: /**
189: * Parses the type.
190: */
191: private String parseType(int ch) throws ConfigException {
192: CharBuffer cb = CharBuffer.allocate();
193:
194: for (; Character.isJavaIdentifierPart((char) ch) || ch == '.'; ch = read())
195: cb.append((char) ch);
196:
197: if (cb.length() == 0)
198: throw new ConfigException(L.l(
199: "unexpected empty type in `{0}'", _value));
200:
201: String className = cb.toString();
202:
203: unread(ch);
204:
205: return className;
206: }
207:
208: /**
209: * Skips whitespace to get to the next valid value.
210: */
211: private int skipWhitespace(int ch) {
212: for (; Character.isWhitespace((char) ch); ch = read()) {
213: }
214:
215: return ch;
216: }
217:
218: /**
219: * Reads the next character.
220: */
221: private int read() {
222: if (_index < _value.length())
223: return _value.charAt(_index++);
224: else
225: return -1;
226: }
227:
228: /**
229: * Unreads the last character.
230: */
231: private void unread(int ch) {
232: if (ch >= 0)
233: _index--;
234: }
235: }
|