/* * GNU LESSER GENERAL PUBLIC LICENSE Copyright (C) 2006 The Lobo Project * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Contact info: lobochief@users.sourceforge.net */ package com.nvarghese.beowulf.common.cobra.js; import java.io.Serializable; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.mozilla.javascript.Function; public class JavaClassWrapper implements Serializable { private final Class javaClass; private final Map functions = new HashMap(); private final Map properties = new HashMap(); private PropertyInfo nameIndexer; private PropertyInfo integerIndexer; public JavaClassWrapper(final Class class1) { super(); this.javaClass = class1; this.scanMethods(); } public Object newInstance() throws InstantiationException, IllegalAccessException { return this.javaClass.newInstance(); } public String getClassName() { String className = this.javaClass.getName(); int lastDotIdx = className.lastIndexOf('.'); return lastDotIdx == -1 ? className : className.substring(lastDotIdx + 1); } public Function getFunction(final String name) { /* methods are not persisted when stored to DB */ scanMethods(); return (Function) this.functions.get(name); } public PropertyInfo getProperty(final String name) { return (PropertyInfo) this.properties.get(name); } private void scanMethods() { Method[] methods = this.javaClass.getMethods(); int len = methods.length; for (int i = 0; i < len; i++) { Method method = methods[i]; String name = method.getName(); if (isPropertyMethod(name, method)) { this.ensurePropertyKnown(name, method); } else { if (isNameIndexer(name, method)) { this.updateNameIndexer(name, method); } else if (this.isIntegerIndexer(name, method)) { this.updateIntegerIndexer(name, method); } JavaFunctionObject f = (JavaFunctionObject) this.functions.get(name); if (f == null) { f = new JavaFunctionObject(name); this.functions.put(name, f); } f.addMethod(method); } } } private boolean isNameIndexer(final String name, final Method method) { return ("namedItem".equals(name) && method.getParameterTypes().length == 1) || ("setNamedItem".equals(name) && method.getParameterTypes().length == 2); } private boolean isIntegerIndexer(final String name, final Method method) { return ("item".equals(name) && method.getParameterTypes().length == 1) || ("setItem".equals(name) && method.getParameterTypes().length == 2); } private void updateNameIndexer(final String methodName, final Method method) { boolean getter = true; if (methodName.startsWith("set")) { getter = false; } PropertyInfo indexer = this.nameIndexer; if (indexer == null) { indexer = new PropertyInfo("$item", Object.class); this.nameIndexer = indexer; } if (getter) { indexer.setGetter(method); } else { indexer.setSetter(method); } } private void updateIntegerIndexer(final String methodName, final Method method) { boolean getter = true; if (methodName.startsWith("set")) { getter = false; } PropertyInfo indexer = this.integerIndexer; if (indexer == null) { Class pt = getter ? method.getReturnType() : method.getParameterTypes()[1]; indexer = new PropertyInfo("$item", pt); this.integerIndexer = indexer; } if (getter) { indexer.setGetter(method); } else { indexer.setSetter(method); } } public PropertyInfo getIntegerIndexer() { return this.integerIndexer; } public PropertyInfo getNameIndexer() { return this.nameIndexer; } private boolean isPropertyMethod(final String name, final Method method) { if (name.startsWith("get") || name.startsWith("is")) { return method.getParameterTypes().length == 0; } else if (name.startsWith("set")) { return method.getParameterTypes().length == 1; } else { return false; } } private String propertyUncapitalize(final String text) { try { if (text.length() > 1 && Character.isUpperCase(text.charAt(1))) { // If second letter is capitalized, don't uncapitalize, // e.g. getURL. return text; } return Character.toLowerCase(text.charAt(0)) + text.substring(1); } catch (IndexOutOfBoundsException iob) { return text; } } private void ensurePropertyKnown(final String methodName, final Method method) { String capPropertyName; String propertyName; boolean getter = false; if (methodName.startsWith("get")) { capPropertyName = methodName.substring(3); propertyName = propertyUncapitalize(capPropertyName); getter = true; } else if (methodName.startsWith("set")) { capPropertyName = methodName.substring(3); propertyName = propertyUncapitalize(capPropertyName); } else if (methodName.startsWith("is")) { capPropertyName = methodName.substring(2); propertyName = propertyUncapitalize(capPropertyName); getter = true; } else { throw new IllegalArgumentException("methodName=" + methodName); } PropertyInfo pinfo = (PropertyInfo) this.properties.get(propertyName); if (pinfo == null) { Class pt = getter ? method.getReturnType() : method.getParameterTypes()[0]; pinfo = new PropertyInfo(propertyName, pt); this.properties.put(propertyName, pinfo); } if (getter) { pinfo.setGetter(method); } else { pinfo.setSetter(method); } } public String toString() { return this.javaClass.getName(); } }