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.server.util.CauchoSystem;
033: import com.caucho.util.CharBuffer;
034: import com.caucho.util.L10N;
035:
036: import javax.annotation.PostConstruct;
037: import java.lang.reflect.Method;
038: import java.util.ArrayList;
039:
040: /**
041: * Configuration for a function signature.
042: */
043: public class Signature {
044: private static L10N L = new L10N(Signature.class);
045:
046: private String _signature;
047: private String _className;
048: private String _name;
049: private String[] _parameterTypes;
050: private String _returnType;
051:
052: private int _index;
053:
054: public Signature() {
055: }
056:
057: public Signature(String sig) {
058: addText(sig);
059: init();
060: }
061:
062: /**
063: * Returns the signature.
064: */
065: public String getSignature() {
066: return _signature;
067: }
068:
069: /**
070: * Returns the method name.
071: */
072: public String getName() {
073: return _name;
074: }
075:
076: /**
077: * Returns the class name
078: */
079: public String getClassName() {
080: return _className;
081: }
082:
083: /**
084: * Returns the method.
085: */
086: public Method getMethod() {
087: if (_className == null)
088: return null;
089:
090: try {
091: Class cl = CauchoSystem.loadClass(_className);
092: if (cl == null)
093: return null;
094:
095: Method[] methods = cl.getMethods();
096: for (int i = 0; i < methods.length; i++) {
097: if (matches(methods[i])) {
098: return methods[i];
099: }
100: }
101: } catch (Exception e) {
102: }
103:
104: return null;
105: }
106:
107: /**
108: * Returns the return type.
109: */
110: public String getReturnType() {
111: return _returnType;
112: }
113:
114: /**
115: * Returns the method parameters. If null, then the parameters
116: * were not specified.
117: */
118: public String[] getParameterTypes() {
119: return _parameterTypes;
120: }
121:
122: /**
123: * Adds the text value to the signature.
124: */
125: public void addText(String value) {
126: _signature = value;
127: }
128:
129: /**
130: * Initialize the signature.
131: */
132: @PostConstruct
133: public void init() throws ConfigException {
134: // jsp/18v2
135: /*
136: if (signature == null)
137: throw new ConfigException(L.l("A Signature requires the method signature."));
138: */
139:
140: if (_signature != null)
141: parseSignature();
142: }
143:
144: /**
145: * Returns true if the method matches the signature.
146: */
147: public boolean matches(Method method) {
148: if (!method.getName().equals(getName()))
149: return false;
150:
151: Class[] parameterTypes = method.getParameterTypes();
152: String[] sigTypes = getParameterTypes();
153:
154: if (parameterTypes.length != sigTypes.length)
155: return false;
156:
157: for (int i = 0; i < parameterTypes.length; i++) {
158: String param = getName(parameterTypes[i]);
159:
160: if (!param.equals(sigTypes[i])
161: && !param.endsWith("." + sigTypes[i]))
162: return false;
163: }
164:
165: return true;
166: }
167:
168: private String getName(Class cl) {
169: if (cl.isArray())
170: return getName(cl.getComponentType()) + "[]";
171: else
172: return cl.getName();
173: }
174:
175: /**
176: * Parses the function signature.
177: */
178: private void parseSignature() throws ConfigException {
179: _index = 0;
180:
181: _returnType = parseType(skipWhitespace(read()));
182:
183: CharBuffer cb = CharBuffer.allocate();
184: int ch = skipWhitespace(read());
185:
186: if (ch == '(' || ch < 0) {
187: _name = _returnType;
188: _returnType = null;
189: } else {
190: for (; Character.isJavaIdentifierPart((char) ch)
191: || ch == '.'; ch = read())
192: cb.append((char) ch);
193:
194: if (cb.length() == 0)
195: throw new ConfigException(L.l(
196: "unexpected empty function name in `{0}'",
197: _signature));
198:
199: _name = cb.toString();
200:
201: int p = _name.lastIndexOf('.');
202: if (p > 0) {
203: _className = _name.substring(0, p);
204: _name = _name.substring(p + 1);
205: }
206:
207: ch = skipWhitespace(ch);
208: }
209:
210: if (ch != '(')
211: throw new ConfigException(
212: L
213: .l(
214: "function syntax is `ret-type name(arg1, ..., argn)' in `{0}'",
215: _signature));
216:
217: ArrayList<String> argList = new ArrayList<String>();
218:
219: ch = read();
220: while (Character
221: .isJavaIdentifierPart((char) (ch = skipWhitespace(ch)))
222: || ch == '.') {
223: String type = parseType(ch);
224:
225: argList.add(type);
226:
227: ch = skipWhitespace(read());
228:
229: for (; Character.isJavaIdentifierPart((char) ch)
230: || ch == '.'; ch = read()) {
231: }
232:
233: if (ch == ',')
234: ch = read();
235: }
236:
237: _parameterTypes = (String[]) argList.toArray(new String[argList
238: .size()]);
239:
240: if (ch != ')')
241: throw new ConfigException(
242: L
243: .l(
244: "function syntax is `ret-type name(arg1, ..., argn)' in `{0}'",
245: _signature));
246:
247: ch = skipWhitespace(read());
248:
249: if (ch != -1)
250: throw new ConfigException(
251: L
252: .l(
253: "function syntax is `ret-type name(arg1, ..., argn)' in `{0}'",
254: _signature));
255: }
256:
257: /**
258: * Parses the type.
259: */
260: private String parseType(int ch) throws ConfigException {
261: CharBuffer cb = CharBuffer.allocate();
262:
263: for (; Character.isJavaIdentifierPart((char) ch) || ch == '.'; ch = read())
264: cb.append((char) ch);
265:
266: if (cb.length() == 0)
267: throw new ConfigException(L.l(
268: "unexpected empty type in `{0}'", _signature));
269:
270: while (true) {
271: for (; Character.isWhitespace((char) ch); ch = read()) {
272: }
273:
274: if (ch == '[') {
275: ch = read();
276:
277: if (ch != ']')
278: throw new ConfigException(
279: L
280: .l(
281: "function syntax is `ret-type name(arg1, ..., argn)' in `{0}'",
282: _signature));
283:
284: cb.append("[]");
285:
286: ch = read();
287: } else
288: break;
289: }
290:
291: String className = cb.toString();
292:
293: unread(ch);
294:
295: return className;
296: }
297:
298: /**
299: * Skips whitespace to get to the next valid value.
300: */
301: private int skipWhitespace(int ch) {
302: for (; Character.isWhitespace((char) ch); ch = read()) {
303: }
304:
305: return ch;
306: }
307:
308: /**
309: * Reads the next character.
310: */
311: private int read() {
312: if (_index < _signature.length())
313: return _signature.charAt(_index++);
314: else
315: return -1;
316: }
317:
318: /**
319: * Unreads the last character.
320: */
321: private void unread(int ch) {
322: if (ch >= 0)
323: _index--;
324: }
325:
326: public String toString() {
327: return "Signature[" + _signature + "]";
328: }
329: }
|