/* GNU GENERAL LICENSE Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either verion 3 of the License, or (at your option) any later version. This program 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 General License for more details. You should have received a copy of the GNU General Public along with this program. If not, see <http://www.gnu.org/licenses/>. Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it */ package org.lobobrowser.js; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.lobobrowser.html.info.PropertyInfo; import org.mozilla.javascript.Function; /** * The Class JavaClassWrapper. */ public class JavaClassWrapper { /** The java class. */ private final Class javaClass; /** The functions. */ private final Map<String, JavaFunctionObject> functions = new HashMap<String, JavaFunctionObject>(); /** The properties. */ private final Map<String, PropertyInfo> properties = new HashMap<String, PropertyInfo>(); /** The name indexer. */ private PropertyInfo nameIndexer; /** The integer indexer. */ private PropertyInfo integerIndexer; /** * Instantiates a new java class wrapper. * * @param class1 * the class1 */ public JavaClassWrapper(Class class1) { super(); this.javaClass = class1; this.scanMethods(); } /** * New instance. * * @return the object * @throws InstantiationException * the instantiation exception * @throws IllegalAccessException * the illegal access exception */ public Object newInstance() throws InstantiationException, IllegalAccessException { return this.javaClass.newInstance(); } /** Gets the class name. * * @return the class name */ public String getClassName() { String className = this.javaClass.getName(); int lastDotIdx = className.lastIndexOf('.'); return lastDotIdx == -1 ? className : className .substring(lastDotIdx + 1); } /** * Gets the function. * * @param name * the name * @return the function */ public Function getFunction(String name) { return this.functions.get(name); } /** * Gets the property. * * @param name * the name * @return the property */ public PropertyInfo getProperty(String name) { return this.properties.get(name); } /** * Scan methods. */ 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 = this.functions.get(name); if (f == null) { f = new JavaFunctionObject(name); this.functions.put(name, f); } f.addMethod(method); } } } /** * Checks if is name indexer. * * @param name * the name * @param method * the method * @return true, if is name indexer */ private boolean isNameIndexer(String name, Method method) { return ("namedItem".equals(name) && (method.getParameterTypes().length == 1)) || ("setNamedItem".equals(name) && (method.getParameterTypes().length == 2)); } /** * Checks if is integer indexer. * * @param name * the name * @param method * the method * @return true, if is integer indexer */ private boolean isIntegerIndexer(String name, Method method) { return ("item".equals(name) && (method.getParameterTypes().length == 1)) || ("setItem".equals(name) && (method.getParameterTypes().length == 2)); } /** * Update name indexer. * * @param methodName * the method name * @param method * the method */ private void updateNameIndexer(String methodName, 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); } } /** * Update integer indexer. * * @param methodName * the method name * @param method * the method */ private void updateIntegerIndexer(String methodName, 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); } } /** Gets the integer indexer. * * @return the integer indexer */ public PropertyInfo getIntegerIndexer() { return this.integerIndexer; } /** Gets the name indexer. * * @return the name indexer */ public PropertyInfo getNameIndexer() { return this.nameIndexer; } /** * Checks if is property method. * * @param name * the name * @param method * the method * @return true, if is property method */ private boolean isPropertyMethod(String name, 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; } } /** * Property uncapitalize. * * @param text * the text * @return the string */ private String propertyUncapitalize(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; } } /** * Ensure property known. * * @param methodName * the method name * @param method * the method */ private void ensurePropertyKnown(String methodName, 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 = 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); } } /* * (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return this.javaClass.getName(); } }