/******************************************************************************* * Copyright (c) 2003, 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jem.internal.beaninfo.core; /* */ import java.util.Iterator; import org.eclipse.core.runtime.CoreException; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.*; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.jem.internal.beaninfo.*; import org.eclipse.jem.internal.beaninfo.adapters.BeaninfoNature; import org.eclipse.jem.internal.beaninfo.adapters.BeaninfoProxyConstants; import org.eclipse.jem.internal.java.adapters.ReflectionAdaptor; import org.eclipse.jem.internal.proxy.core.*; import org.eclipse.jem.java.*; /** * Beaninfo (introspection) utilities methods */ public final class Utilities { private Utilities() { } /** * Utility to return the class as a JavaClass. If it actually is a JavaType this will * fail with a ClassCastException. * @param className * @param rset * @return java class * * @throws ClassCastException if not a java class, but instead a java primitive. * @since 1.1.0 */ public static JavaClass getJavaClass(String className, ResourceSet rset) { return (JavaClass) getJavaType(className, rset); } /** * Utility to return the class as a JavaHelpers. * * @param className * @param rset * @return java helpers. * * @since 1.1.0 */ public static JavaHelpers getJavaType(String className, ResourceSet rset) { return (JavaHelpers) rset.getEObject(getJavaClassURI(className), true); } /** * Create a URI to the given classname. * <p> * Note: It must be in normal form, i.e. fully-qualified, if primitive spelled out (e.g. "int" not I), and if * arrays it must readable form (e.g. "java.lang.String[]" and not "[Ljava.lang.String;"). * * @param className * @return * * @since 1.1.0 */ public static URI getJavaClassURI(String className) { return JavaRefFactory.eINSTANCE.createTypeURI(className); } /** * Utility to return the EClassifier from the given IBeanTypeProxy. */ public static EClassifier getJavaClass(IBeanTypeProxy type, ResourceSet rset) { if (type != null) { return getJavaType(type.getFormalTypeName(), rset); } else return null; } /** * Utility to return the Method from the given IMethodProxy. */ public static Method getMethod(IMethodProxy method, ResourceSet rset) { return method != null ? (Method) rset.getEObject(URI.createURI(getMethodURL(method)), true) : null; } /** * Answer the URL String for Method from the given IMethodProxy */ public static String getMethodURL(IMethodProxy method) { String className = method.getClassType().getTypeName(); IBeanTypeProxy[] parms = method.getParameterTypes(); String[] parmTypes = parms.length > 0 ? new String[parms.length] : null; for (int i = 0; i < parms.length; i++) { parmTypes[i] = parms[i].getFormalTypeName(); } return computeMethodURL(className, method.getName(), parmTypes); } protected static String computeMethodURL(String fullyQualifiedClassName, String methodName, String[] parmTypes) { int classStart = fullyQualifiedClassName.lastIndexOf('.'); StringBuffer url = new StringBuffer(50); url.append("java:/"); //$NON-NLS-1$ if (classStart > -1) url.append(fullyQualifiedClassName.substring(0, classStart)); url.append('#'); url.append(computeMethodID(fullyQualifiedClassName.substring(classStart + 1), methodName, parmTypes)); return url.toString(); } protected static String computeFieldURL(String fullyQualifiedClassName, String fieldName) { int classStart = fullyQualifiedClassName.lastIndexOf('.'); StringBuffer url = new StringBuffer(50); url.append("java:/"); //$NON-NLS-1$ if (classStart > -1) url.append(fullyQualifiedClassName.substring(0, classStart)); url.append('#'); url.append(fullyQualifiedClassName.substring(classStart + 1)); url.append(ReflectionAdaptor.C_CLASS_MEMBER_DELIMITER); url.append(fieldName); return url.toString(); } /** * Return the field uri for the given classname, fieldname. * @param fullyQualifiedClassName * @param fieldName * @return * * @since 1.1.0 */ public static URI getFieldURI(String fullyQualifiedClassName, String fieldName) { return URI.createURI(computeFieldURL(fullyQualifiedClassName, fieldName)); } /** * Return the method uri for the given classname, methodname, parm types. * @param fullyQualifiedClassName * @param methodName * @param parmTypes <code>null</code> if there are no parms. * @return * * @since 1.1.0 */ public static URI getMethodURI(String fullyQualifiedClassName, String methodName, String[] parmTypes) { return URI.createURI(computeMethodURL(fullyQualifiedClassName, methodName, parmTypes)); } /** * Turn it into an URI. */ public static URI getMethodURI(IMethodProxy method) { return URI.createURI(getMethodURL(method)); } /** * Utility to compute the Java Modeling METHODID from method declaring class name, * method name, and parameter class names. */ public static String computeMethodID(String className, String methodName, String[] parameterTypes) { StringBuffer out = new StringBuffer(50); out.append(className); out.append(ReflectionAdaptor.C_CLASS_MEMBER_DELIMITER); out.append(methodName); out.append(ReflectionAdaptor.C_METHOD_PARM_DELIMITER); if (parameterTypes != null) for (int i = 0; i < parameterTypes.length; i++) { out.append(parameterTypes[i]); if (i < parameterTypes.length - 1) out.append(ReflectionAdaptor.C_PARM_PARM_DELIMITER); } if (className.equals(methodName)) out.append(ReflectionAdaptor.S_CONSTRUCTOR_TOKEN); //It's a constructor return out.toString(); } /** * Utility to retrieve the BeanDecorator. */ public static BeanDecorator getBeanDecorator(EModelElement model) { return (BeanDecorator) getDecorator(model, BeanDecorator.class); } /** * Utility to retrieve a decorator of the specified class. */ public static EAnnotation getDecorator(EModelElement model, Class decoratorClass) { Iterator itr = model.getEAnnotations().iterator(); while (itr.hasNext()) { EAnnotation decr = (EAnnotation) itr.next(); if (decoratorClass.isInstance(decr)) return decr; } return null; } /** * Utility to retrieve the EventSetDecorator. */ public static EventSetDecorator getEventSetDecorator(EModelElement model) { return (EventSetDecorator) getDecorator(model, EventSetDecorator.class); } /** * Utility to retrieve the MethodDecorator. */ public static MethodDecorator getMethodDecorator(EModelElement model) { return (MethodDecorator) getDecorator(model, MethodDecorator.class); } /** * Utility to retrieve the PropertyDecorator. */ public static PropertyDecorator getPropertyDecorator(EModelElement model) { return (PropertyDecorator) getDecorator(model, PropertyDecorator.class); } /** * Utility to return an iterator on the list which will return the property decorators * of only the properties in the EList passed in. If the property does not have a * property decorator, then it is not a beaninfo property. */ public static Iterator getPropertiesIterator(final EList properties) { return new Iterator() { private Iterator itr = properties.iterator(); private boolean hasNext = true; private PropertyDecorator next; { findNext(); } public boolean hasNext() { return hasNext; } public Object next() { PropertyDecorator temp = next; findNext(); return temp; } public void remove() { throw new UnsupportedOperationException(); } private void findNext() { while (itr.hasNext()) { EModelElement nextOne = (EModelElement) itr.next(); next = getPropertyDecorator(nextOne); if (next != null) { return; } } hasNext = false; } }; } /** * Utility to return an iterator on the list which will return the EventSet decorators * of only the BeanEvents in the EList passed in. */ public static Iterator getEventSetsIterator(final EList events) { return new Iterator() { private Iterator itr = events.iterator(); private boolean hasNext = true; private EventSetDecorator next; { findNext(); } public boolean hasNext() { return hasNext; } public Object next() { EventSetDecorator temp = next; findNext(); return temp; } public void remove() { throw new UnsupportedOperationException(); } private void findNext() { while (itr.hasNext()) { EModelElement nextOne = (EModelElement) itr.next(); next = getEventSetDecorator(nextOne); if (next != null) { return; } } hasNext = false; } }; } /** * Utility to return an iterator on the list which will return the Method decorators * of only the Methods in the EList passed in. */ public static Iterator getMethodsIterator(final EList methods) { return new Iterator() { private Iterator itr = methods.iterator(); private boolean hasNext = true; private MethodDecorator next; { findNext(); } public boolean hasNext() { return hasNext; } public Object next() { MethodDecorator temp = next; findNext(); return temp; } public void remove() { throw new UnsupportedOperationException(); } private void findNext() { while (itr.hasNext()) { EModelElement nextOne = (EModelElement) itr.next(); next = getMethodDecorator(nextOne); if (next != null) { return; } } hasNext = false; } }; } /** * Get the search path from the remote vm. * * Note: This shouldn't be used when working with a BeaninfoNature. Use the * accessors taking the nature instead. Otherwise there will be inconsistencies since the search path won't be * saved across invocations of the workspace if it is not updated through the nature). */ public static IArrayBeanProxy getBeanInfoSearchPath(ProxyFactoryRegistry registry) { BeaninfoProxyConstants biconstants = BeaninfoProxyConstants.getConstants(registry); if (biconstants != null) return (IArrayBeanProxy) biconstants .getGetBeanInfoSearchPathProxy() .invokeCatchThrowableExceptions( null); else return null; } /** * Set the search path to the array of strings passed in on the remote vm. * * Note: This shouldn't be used when working with a BeaninfoNature. Use the * accessors taking the nature instead. Otherwise there will be inconsistencies since the search path won't be * saved across invocations of the workspace if it is not updated through the nature). */ public static void setBeanInfoSearchPath(ProxyFactoryRegistry registry, String[] paths) { try { BeaninfoProxyConstants biConstants = BeaninfoProxyConstants.getConstants(registry); if (biConstants != null) { JavaStandardBeanProxyConstants jConstants = JavaStandardBeanProxyConstants.getConstants(registry); IStandardBeanProxyFactory proxyFactory = registry.getBeanProxyFactory(); IArrayBeanProxy newPath = proxyFactory.createBeanProxyWith(jConstants.getStringType(), paths != null ? paths.length : 0); if (paths != null) for (int i = 0; i < paths.length; i++) newPath.set(proxyFactory.createBeanProxyWith(paths[i]), i); biConstants.getSetBeanInfoSearchPathProxy().invoke(null, newPath); } } catch (ThrowableProxy e) { } } /** * From the Beaninfo Nature, insert a path to the beaninfo path at the given index, -1 means at the end. * If index is larger than the current path, it will also add at the end. */ public static void insertBeanInfoSearchPath(BeaninfoNature nature, IBeaninfosDocEntry path, int index) throws CoreException { BeaninfosDoc infoPath = nature.getSearchPath(); IBeaninfosDocEntry[] oldPath = infoPath.getSearchpath(); IBeaninfosDocEntry[] newPath = new IBeaninfosDocEntry[oldPath.length + 1]; if (index == -1 || index >= oldPath.length) { // At the end or past end System.arraycopy(oldPath, 0, newPath, 0, oldPath.length); newPath[oldPath.length] = path; } else { // In the middle System.arraycopy(oldPath, 0, newPath, 0, index); newPath[index] = path; System.arraycopy(oldPath, index, newPath, index + 1, oldPath.length - index); } infoPath.setSearchpath(newPath); nature.setSearchPath(infoPath); } /** * Insert a path to the beaninfo path at the given index, -1 means at the end. * If index is larger than the current path, it will also add at the end. * * Note: This shouldn't be used when working with a BeaninfoNature. Use the * accessors taking the nature instead. Otherwise there will be inconsistencies since the search path won't be * saved across invocations of the workspace if it is not updated through the nature). */ public static void insertBeanInfoSearchPath(ProxyFactoryRegistry registry, String path, int index) { try { BeaninfoProxyConstants biConstants = BeaninfoProxyConstants.getConstants(registry); if (biConstants != null) { IArrayBeanProxy infoPath = (IArrayBeanProxy) biConstants.getGetBeanInfoSearchPathProxy().invoke(null); int pathLength = infoPath.getLength(); IStandardBeanProxyFactory proxyFactory = registry.getBeanProxyFactory(); IArrayBeanProxy newPath = proxyFactory.createBeanProxyWith(infoPath.getTypeProxy(), pathLength + 1); IBeanProxy stringProxy = proxyFactory.createBeanProxyWith(path); JavaStandardBeanProxyConstants constants = JavaStandardBeanProxyConstants.getConstants(registry); if (index == -1 || index >= pathLength) { // At the end or past end constants.arraycopy(infoPath, 0, newPath, 0, infoPath.getLength()); newPath.set(stringProxy, pathLength); } else { // In the middle constants.arraycopy(infoPath, 0, newPath, 0, index); newPath.set(stringProxy, index); constants.arraycopy(infoPath, index, newPath, index + 1, pathLength - index); } biConstants.getSetBeanInfoSearchPathProxy().invoke(null, newPath); } } catch (ThrowableProxy e) { } } /** * From the Beaninfo Nature, remove the specified path from the beaninfo search path. * Not an error if not found. */ public static void removeBeanInfoPath(BeaninfoNature nature, IBeaninfosDocEntry path) throws CoreException { BeaninfosDoc infoPath = nature.getSearchPath(); IBeaninfosDocEntry[] oldPath = infoPath.getSearchpath(); for (int i = 0; i < oldPath.length; i++) { if (path.equals(oldPath[i])) { // We found it, so remove it. IBeaninfosDocEntry[] newPath = new IBeaninfosDocEntry[oldPath.length - 1]; System.arraycopy(oldPath, 0, newPath, 0, i); if (i < oldPath.length - 1) System.arraycopy(oldPath, i + 1, newPath, i, oldPath.length - i - 1); infoPath.setSearchpath(newPath); nature.setSearchPath(infoPath); return; } } } /** * Remove the specified path from the beaninfo search path. * Not an error if not found. * * Note: This shouldn't be used when working with a BeaninfoNature. Use the * accessors taking the nature instead. Otherwise there will be inconsistencies since the search path won't be * saved across invocations of the workspace if it is not updated through the nature). */ public static void removeBeanInfoPath(ProxyFactoryRegistry registry, String path) { try { BeaninfoProxyConstants biConstants = BeaninfoProxyConstants.getConstants(registry); if (biConstants != null) { IArrayBeanProxy infoPath = (IArrayBeanProxy) biConstants.getGetBeanInfoSearchPathProxy().invoke(null); int pathLength = infoPath.getLength(); for (int i = 0; i < pathLength; i++) { IStringBeanProxy aPath = (IStringBeanProxy) infoPath.get(i); if (path.equals(aPath.stringValue())) { // We found it, so remove it. IArrayBeanProxy newPath = registry.getBeanProxyFactory().createBeanProxyWith(infoPath.getTypeProxy(), pathLength - 1); JavaStandardBeanProxyConstants constants = JavaStandardBeanProxyConstants.getConstants(registry); constants.arraycopy(infoPath, 0, newPath, 0, i); if (i < pathLength - 1) constants.arraycopy(infoPath, i + 1, newPath, i, pathLength - i - 1); biConstants.getSetBeanInfoSearchPathProxy().invoke(null, newPath); return; } } } } catch (ThrowableProxy e) { } }; }