| /******************************************************************************* |
| * Copyright (c) 2003, 2007 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.jst.j2ee.internal.common.operations; |
| |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.ABSTRACT_METHODS; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.CLASS_NAME; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.CONSTRUCTOR; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.INTERFACES; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.JAVA_PACKAGE; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.JAVA_PACKAGE_FRAGMENT_ROOT; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.MODIFIER_ABSTRACT; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.MODIFIER_FINAL; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.MODIFIER_PUBLIC; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.SOURCE_FOLDER; |
| import static org.eclipse.jst.j2ee.internal.common.operations.INewJavaClassDataModelProperties.SUPERCLASS; |
| |
| import java.io.ByteArrayInputStream; |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.commands.operations.AbstractOperation; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.jdt.core.Flags; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IPackageFragmentRoot; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.ITypeHierarchy; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.Signature; |
| import org.eclipse.jem.util.emf.workbench.ProjectUtilities; |
| import org.eclipse.jem.util.logger.proxy.Logger; |
| import org.eclipse.jem.workbench.utility.JemProjectUtilities; |
| import org.eclipse.wst.common.componentcore.internal.operation.IArtifactEditOperationDataModelProperties; |
| import org.eclipse.wst.common.frameworks.datamodel.AbstractDataModelOperation; |
| import org.eclipse.wst.common.frameworks.datamodel.IDataModel; |
| |
| /** |
| * NewJavaClassOperation is a data model operation that is used to create a default instance of a new java class |
| * based on the input and properties set in the NewJavaClassDataModelProvider. |
| * @see org.eclipse.jst.j2ee.internal.common.operations.NewJavaClassDataModelProvider |
| * |
| * It is a subclass of ArtifactEditProviderOperation and clients can invoke this operation as is or it may be subclassed to |
| * add additional or modify behaviour. The execute() method can be extended to drive this behaviour. |
| * @see org.eclipse.wst.common.componentcore.internal.operation.ArtifactEditProviderOperation |
| * |
| * The new java class is generated through the use of adding a series of static tokens defined within to |
| * an ongoing string buffer. |
| * |
| * The use of this class is EXPERIMENTAL and is subject to substantial changes. |
| * |
| * This needs to be removed as it is legacy inherited from another team |
| */ |
| public class NewJavaClassOperation extends AbstractDataModelOperation { |
| |
| // Tokens for string buffer creation of default java class |
| protected static final String EMPTY_STRING = ""; //$NON-NLS-1$ |
| protected static final String TAB = "\t"; //$NON-NLS-1$ |
| protected static final String SPACE = " "; //$NON-NLS-1$ |
| protected static final String DOT = "."; //$NON-NLS-1$ |
| protected static final String COMMA = ","; //$NON-NLS-1$ |
| protected static final String SEMICOLON = ";"; //$NON-NLS-1$ |
| protected static final String POUND = "#"; //$NON-NLS-1$ |
| protected static final String OPEN_PAR = "("; //$NON-NLS-1$ |
| protected static final String CLOSE_PAR = ")"; //$NON-NLS-1$ |
| protected static final String OPEN_BRA = "{"; //$NON-NLS-1$ |
| protected static final String CLOSE_BRA = "}"; //$NON-NLS-1$ |
| protected static final String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$ |
| |
| protected static final String JAVA_LANG_OBJECT = "java.lang.Object"; //$NON-NLS-1$ |
| protected static final String PACKAGE = "package "; //$NON-NLS-1$ |
| protected static final String CLASS = "class "; //$NON-NLS-1$ |
| protected static final String IMPORT = "import "; //$NON-NLS-1$ |
| protected static final String EXTENDS = "extends "; //$NON-NLS-1$ |
| protected static final String IMPLEMENTS = "implements "; //$NON-NLS-1$ |
| protected static final String THROWS = "throws "; //$NON-NLS-1$ |
| protected static final String SUPER = "super"; //$NON-NLS-1$ |
| protected static final String PUBLIC = "public "; //$NON-NLS-1$ |
| protected static final String PROTECTED = "protected "; //$NON-NLS-1$ |
| protected static final String PRIVATE = "private "; //$NON-NLS-1$ |
| protected static final String STATIC = "static "; //$NON-NLS-1$ |
| protected static final String ABSTRACT = "abstract "; //$NON-NLS-1$ |
| protected static final String FINAL = "final "; //$NON-NLS-1$ |
| protected static final String VOID = "void"; //$NON-NLS-1$ |
| protected static final String INT = "int"; //$NON-NLS-1$ |
| protected static final String BOOLEAN = "boolean"; //$NON-NLS-1$ |
| protected static final String MAIN_METHOD = "\tpublic static void main(String[] args) {"; //$NON-NLS-1$ |
| protected static final String TODO_COMMENT = "\t\t// TODO Auto-generated method stub"; //$NON-NLS-1$ |
| protected static final String RETURN_NULL = "\t\treturn null;"; //$NON-NLS-1$ |
| protected static final String RETURN_0 = "\t\treturn 0;"; //$NON-NLS-1$ |
| protected static final String RETURN_FALSE = "\t\treturn false;"; //$NON-NLS-1$ |
| |
| /** |
| * This is a list of all the calculated import statements that will need to be added |
| */ |
| private List importStatements; |
| |
| /** |
| * This is a NewJavaClassOperation constructor. Data models passed in should be instances |
| * of NewJavaClassDataModel. This method does not accept null. It will not return null. |
| * @see NewJavaClassDataModelProvider |
| * |
| * @param dataModel |
| * @return NewJavaClassOperation |
| */ |
| public NewJavaClassOperation(IDataModel dataModel) { |
| super(dataModel); |
| importStatements = new ArrayList(); |
| } |
| |
| /** |
| * Subclasses may extend this method to add their own actions during execution. |
| * The implementation of the execute method drives the running of the operation. This |
| * method will create the source folder, the java package, and then create the java file. |
| * This method will accept null. |
| * @see AbstractOperation#execute(org.eclipse.core.runtime.IProgressMonitor, org.eclipse.core.runtime.IAdaptable) |
| * |
| * @param monitor ProgressMonitor |
| * @throws CoreException |
| * @throws InterruptedException |
| * @throws InvocationTargetException |
| */ |
| public IStatus doExecute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { |
| // Ensure source folder exists |
| IFolder sourceFolder = createJavaSourceFolder(); |
| // Ensure java package exists |
| IPackageFragment pack = createJavaPackage(); |
| // Create java class |
| createJavaFile(sourceFolder, pack); |
| return OK_STATUS; |
| } |
| |
| /** |
| * This method will return the java source folder as specified in the java class data model. |
| * It will create the java source folder if it does not exist. This method may return null. |
| * @see #SOURCE_FOLDER |
| * @see IFolder#create(boolean, boolean, org.eclipse.core.runtime.IProgressMonitor) |
| * |
| * @return IFolder the java source folder |
| */ |
| protected final IFolder createJavaSourceFolder() { |
| // Get the source folder name from the data model |
| String folderFullPath = model.getStringProperty(SOURCE_FOLDER); |
| IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); |
| IFolder folder = root.getFolder(new Path(folderFullPath)); |
| // If folder does not exist, create the folder with the specified path |
| if (!folder.exists()) { |
| try { |
| folder.create(true, true, null); |
| } catch (CoreException e) { |
| Logger.getLogger().log(e); |
| } |
| } |
| // Return the source folder |
| return folder; |
| } |
| |
| /** |
| * This method will return the java package as specified by the new java class data model. |
| * If the package does not exist, it will create the package. This method should not return |
| * null. |
| * @see #JAVA_PACKAGE |
| * @see IPackageFragmentRoot#createPackageFragment(java.lang.String, boolean, org.eclipse.core.runtime.IProgressMonitor) |
| * |
| * @return IPackageFragment the java package |
| */ |
| protected final IPackageFragment createJavaPackage() { |
| // Retrieve the package name from the java class data model |
| String packageName = model.getStringProperty(JAVA_PACKAGE); |
| IPackageFragmentRoot packRoot = (IPackageFragmentRoot) model.getProperty(JAVA_PACKAGE_FRAGMENT_ROOT); |
| IPackageFragment pack = packRoot.getPackageFragment(packageName); |
| // Handle default package |
| if (pack == null) { |
| pack = packRoot.getPackageFragment(""); //$NON-NLS-1$ |
| } |
| // Create the package fragment if it does not exist |
| if (!pack.exists()) { |
| String packName = pack.getElementName(); |
| try { |
| pack = packRoot.createPackageFragment(packName, true, null); |
| } catch (JavaModelException e) { |
| Logger.getLogger().log(e); |
| } |
| } |
| // Return the package |
| return pack; |
| } |
| |
| /** |
| * Subclasses may extend this method to provide their own java file creation path. |
| * This implementation will use the properties specified in the data model to create |
| * a default java class. The class will be built using pre-defined tokens and will be |
| * built up using a string buffer. The method getJavaFileContent will handle the building |
| * of the string buffer while this method will write those contents to the file. |
| * This method does not accept null parameters. |
| * @see #CLASS_NAME |
| * @see NewJavaClassOperation#getJavaFileContent(IPackageFragment, String) |
| * |
| * @param sourceFolder |
| * @param pack |
| */ |
| protected void createJavaFile(IFolder sourceFolder, IPackageFragment pack) { |
| // Retrieve properties from the java class data model |
| String packageName = model.getStringProperty(JAVA_PACKAGE); |
| String className = model.getStringProperty(CLASS_NAME); |
| String fileName = className + ".java"; //$NON-NLS-1$ |
| //ICompilationUnit cu = null; |
| try { |
| // Get the java file content from the string buffer |
| String content = getJavaFileContent(pack, className); |
| // Create the compilation unit |
| pack.createCompilationUnit(fileName, content, true, null); |
| byte[] contentBytes = content.getBytes(); |
| IPath packageFullPath = new Path(packageName.replace('.', IPath.SEPARATOR)); |
| IPath javaFileFullPath = packageFullPath.append(fileName); |
| IFile file = sourceFolder.getFile(javaFileFullPath); |
| // Set the contents in the file if it already exists |
| if (file != null && file.exists()) { |
| file.setContents(new ByteArrayInputStream(contentBytes), false, true, null); |
| } // If the file does not exist, create it with the contents |
| else if (file != null) { |
| file.create(new ByteArrayInputStream(contentBytes), false, null); |
| } |
| // editModel.getWorkingCopy(cu, true); //Track CU. |
| } catch (Exception ex) { |
| ex.printStackTrace(); |
| } |
| } |
| |
| /** |
| * This is intended for internal use only. This is where the string buffer for the contents |
| * of the java file is built up using the properties in the data model and the predefined tokens. |
| * This method will not accept null parameters. It will not return null. |
| * @see NewJavaClassDataModelProvider |
| * @see NewJavaClassOperation#createJavaFile(IFolder, IPackageFragment) |
| * |
| * @param pack |
| * @param className |
| * @return String java file contents |
| */ |
| private String getJavaFileContent(IPackageFragment pack, String className) { |
| // Create the superclass name |
| String superclassName = model.getStringProperty(SUPERCLASS); |
| List interfaces = (List) model.getProperty(INTERFACES); |
| String packageStatement = getPackageStatement(pack); |
| // Create the import statements |
| setupImportStatements(pack, superclassName, interfaces); |
| // Create the class declaration |
| String classDeclaration = getClassDeclaration(superclassName, className, interfaces); |
| // Create the fields |
| String fields = getFields(); |
| // Create the methods |
| String methods = getMethodStubs(superclassName, className); |
| |
| StringBuffer contents = new StringBuffer(); |
| // Add the package statement to the buffer |
| contents.append(packageStatement); |
| // Add all the import statements to the buffer |
| for (int i = 0; i < importStatements.size(); i++) { |
| contents.append(IMPORT + importStatements.get(i) + SEMICOLON); |
| contents.append(lineSeparator); |
| } |
| contents.append(lineSeparator); |
| // Add the class declaration to the buffer |
| contents.append(classDeclaration); |
| // Add the fields to the buffer |
| contents.append(fields); |
| // Add the method bodies to the buffer |
| contents.append(methods); |
| contents.append(CLOSE_BRA); |
| // Return the contents of the buffer |
| return contents.toString(); |
| } |
| |
| /** |
| * This is intended for internal use only. This method will return a package string for |
| * the class. It will not accept a null parameter. It will not return null. |
| * @see NewJavaClassOperation#getJavaFileContent(IPackageFragment, String) |
| * |
| * @param pack |
| * @return String package statement |
| */ |
| private String getPackageStatement(IPackageFragment pack) { |
| StringBuffer sb = new StringBuffer(); |
| // If it is not default package, add package statement |
| if (!pack.isDefaultPackage()) { |
| sb.append(PACKAGE + pack.getElementName() + SEMICOLON); |
| sb.append(lineSeparator); |
| sb.append(lineSeparator); |
| } |
| // Return contents of buffer |
| return sb.toString(); |
| } |
| |
| /** |
| * This method is intended for internal use. It checks to see if the qualified class name |
| * belongs to the specified package. This method will not accept nulls. It will not return null. |
| * @see NewJavaClassOperation#setupImportStatements(IPackageFragment, String, List) |
| * |
| * @param packageFragment |
| * @param className |
| * @return boolean is class in this package? |
| */ |
| private boolean isSamePackage(IPackageFragment packageFragment, String className) { |
| if (className != null && className.length() > 0) { |
| String sPackageName = packageFragment.getElementName(); |
| String classPackageName = Signature.getQualifier(className); |
| // Does the qualified class's package name match the passed in package's name? |
| if (classPackageName.equals(sPackageName)) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * This method is intended for internal use only. This method will set up the required import |
| * statements and cache to the importStatements list. |
| * This method does not accept null parameters. |
| * @see NewJavaClassOperation#importStatements |
| * @see NewJavaClassOperation#getJavaFileContent(IPackageFragment, String) |
| * |
| * @param pack |
| * @param superclassName |
| * @param interfaces |
| */ |
| private void setupImportStatements(IPackageFragment pack, String superclassName, List interfaces) { |
| // If there is a superclass and it is not in the same package, add an import for it |
| if (superclassName != null && superclassName.length() > 0) { |
| if (!superclassName.equals(JAVA_LANG_OBJECT) && !isSamePackage(pack, superclassName)) { |
| importStatements.add(superclassName); |
| } |
| } |
| // Add an import the list of implemented interfaces |
| if (interfaces != null && interfaces.size() > 0) { |
| int size = interfaces.size(); |
| for (int i = 0; i < size; i++) { |
| String interfaceName = (String) interfaces.get(i); |
| if(!interfaceName.equals(JAVA_LANG_OBJECT) && !isSamePackage(pack, interfaceName)){ |
| importStatements.add(interfaceName); |
| } |
| } |
| } |
| } |
| |
| /** |
| * This class is intended for internal use only. This will build up the class declartion |
| * statement based off the properties set in the java class data model. |
| * This method does not accept null parameters. It will not return null. |
| * @see NewJavaClassOperation#getJavaFileContent(IPackageFragment, String) |
| * |
| * @param superclassName |
| * @param className |
| * @param interfaces |
| * @return String class declaration string |
| */ |
| private String getClassDeclaration(String superclassName, String className, List interfaces) { |
| StringBuffer sb = new StringBuffer(); |
| // Append appropriate modifiers |
| if (model.getBooleanProperty(MODIFIER_PUBLIC)) |
| sb.append(PUBLIC); |
| if (model.getBooleanProperty(MODIFIER_ABSTRACT)) |
| sb.append(ABSTRACT); |
| if (model.getBooleanProperty(MODIFIER_FINAL)) |
| sb.append(FINAL); |
| // Add the class token |
| sb.append(CLASS); |
| // Add the class name |
| sb.append(className + SPACE); |
| // If there is a superclass, add the extends and super class name |
| if (superclassName != null && superclassName.length() > 0 && !superclassName.equals(JAVA_LANG_OBJECT)) { |
| int index = superclassName.lastIndexOf(DOT); |
| if (index != -1) |
| superclassName = superclassName.substring(index + 1); |
| sb.append(EXTENDS + superclassName + SPACE); |
| } |
| // If there are interfaces, add the implements and then interate over the interface list |
| if (interfaces != null && interfaces.size() > 0) { |
| sb.append(IMPLEMENTS); |
| int size = interfaces.size(); |
| for (int i = 0; i < size; i++) { |
| String interfaceName = (String) interfaces.get(i); |
| int index = interfaceName.lastIndexOf(DOT); |
| if (index != -1) |
| interfaceName = interfaceName.substring(index + 1); |
| sb.append(interfaceName); |
| if (i < size - 1) |
| sb.append(COMMA); |
| sb.append(SPACE); |
| } |
| } |
| sb.append(OPEN_BRA); |
| sb.append(lineSeparator); |
| // Return the finished class declaration string |
| return sb.toString(); |
| } |
| |
| /** |
| * Subclasses may extend this method to add their own fields. The default implementation |
| * is not to have any fields. This method will not return null. |
| * @see NewJavaClassOperation#getJavaFileContent(IPackageFragment, String) |
| * |
| * @return String fields string |
| */ |
| protected String getFields() { |
| return EMPTY_STRING; |
| } |
| |
| /** |
| * This method is intended for internal use only. This will build up a string with the |
| * contents of all the method stubs for the unimplemented methods defined in the interfaces. |
| * It will also add inherited constructors from the superclass as appropriate. |
| * This method does not accept null parameters. It will not return null. |
| * @see NewJavaClassOperation#getJavaFileContent(IPackageFragment, String) |
| * |
| * @param superclassName |
| * @param className |
| * @return String method stubs string |
| */ |
| private String getMethodStubs(String superclassName, String className) { |
| StringBuffer sb = new StringBuffer(); |
| IJavaProject javaProj = JemProjectUtilities.getJavaProject(getTargetProject()); |
| if (model.getBooleanProperty(INewJavaClassDataModelProperties.MAIN_METHOD)) { |
| // Add main method |
| sb.append(MAIN_METHOD); |
| sb.append(lineSeparator); |
| sb.append(TODO_COMMENT); |
| sb.append(lineSeparator); |
| sb.append(TAB + CLOSE_BRA); |
| sb.append(lineSeparator); |
| sb.append(lineSeparator); |
| } |
| |
| IType superClassType = null; |
| if (model.getBooleanProperty(CONSTRUCTOR) || model.getBooleanProperty(ABSTRACT_METHODS)) { |
| // Find super class type |
| try { |
| superClassType = javaProj.findType(superclassName); |
| } catch (JavaModelException e) { |
| Logger.getLogger().log(e); |
| } |
| } |
| if (model.getBooleanProperty(CONSTRUCTOR)) { |
| // Implement constructors from superclass |
| try { |
| if (superClassType != null) { |
| IMethod[] methods = superClassType.getMethods(); |
| for (int j = 0; j < methods.length; j++) { |
| if (methods[j].isConstructor() && !Flags.isPrivate(methods[j].getFlags()) && !hasGenericParams(methods[j])) { |
| String methodStub = getMethodStub(methods[j], superclassName, className); |
| sb.append(methodStub); |
| } |
| } |
| } |
| } catch (JavaModelException e) { |
| Logger.getLogger().log(e); |
| } |
| } |
| // Add unimplemented methods defined in the interfaces list |
| if (model.getBooleanProperty(ABSTRACT_METHODS) && superClassType != null) { |
| String methodStub = getUnimplementedMethodsFromSuperclass(superClassType, className); |
| if (methodStub != null && methodStub.trim().length() > 0) |
| sb.append(methodStub); |
| methodStub = getUnimplementedMethodsFromInterfaces(superClassType, className, javaProj); |
| if (methodStub != null && methodStub.trim().length() > 0) |
| sb.append(methodStub); |
| } |
| // Add any user defined method stubs |
| if (superClassType != null) { |
| String userDefined = getUserDefinedMethodStubs(superClassType); |
| if (userDefined != null && userDefined.trim().length() > 0) |
| sb.append(userDefined); |
| } |
| // Return the methods string |
| return sb.toString(); |
| } |
| |
| private boolean hasGenericParams(IMethod method) { |
| try { |
| IType parentType = method.getDeclaringType(); |
| String[] paramTypes = method.getParameterTypes(); |
| |
| int nP = paramTypes.length; |
| for (int i = 0; i < nP; i++) { |
| String type = paramTypes[i]; |
| if (!isPrimitiveType(type)) { |
| type = JavaModelUtil.getResolvedTypeName(type, parentType); |
| if(type.indexOf(Signature.C_GENERIC_START, 0) != -1){ |
| return true; |
| } |
| } |
| } |
| } catch (JavaModelException e) { |
| Logger.getLogger().log(e); |
| } |
| return false; |
| } |
| |
| /** |
| * This method is intended for internal use only. This will retrieve method stubs for |
| * unimplemented methods in the superclass that will need to be created in the new class. |
| * This method does not accept null parameters. It will not return null. |
| * @see NewJavaClassOperation#getMethodStubs(String, String) |
| * |
| * @param superClassType |
| * @param className |
| * @return String unimplemented methods defined in superclass |
| */ |
| private String getUnimplementedMethodsFromSuperclass(IType superClassType, String className) { |
| StringBuffer sb = new StringBuffer(); |
| try { |
| // Implement abstract methods from superclass |
| IMethod[] methods = superClassType.getMethods(); |
| for (int j = 0; j < methods.length; j++) { |
| IMethod method = methods[j]; |
| int flags = method.getFlags(); |
| // Add if the method is abstract, not private or static, and the option is selected in data model |
| if ((Flags.isAbstract(flags) && !Flags.isStatic(flags) && !Flags.isPrivate(flags)) || implementImplementedMethod(methods[j])) { |
| String methodStub = getMethodStub(methods[j], superClassType.getFullyQualifiedName(), className); |
| sb.append(methodStub); |
| } |
| } |
| } catch (JavaModelException e) { |
| Logger.getLogger().log(e); |
| } |
| // Return method stubs string |
| return sb.toString(); |
| } |
| |
| /** |
| * This method is intended for internal use only. This will retrieve method stubs for |
| * unimplemented methods defined in the interfaces that will need to be created in the new class. |
| * This method does not accept null parameters. It will not return null. |
| * @see NewJavaClassOperation#getMethodStubs(String, String) |
| * |
| * @param superClassType |
| * @param className |
| * @param javaProj |
| * @return String unimplemented methods defined in interfaces |
| */ |
| private String getUnimplementedMethodsFromInterfaces(IType superClassType, String className, IJavaProject javaProj) { |
| StringBuffer sb = new StringBuffer(); |
| try { |
| // Implement defined methods from interfaces |
| List interfaces = (List) model.getProperty(INTERFACES); |
| if (interfaces != null) { |
| for (int i = 0; i < interfaces.size(); i++) { |
| String qualifiedClassName = (String) interfaces.get(i); |
| IType interfaceType = javaProj.findType(qualifiedClassName); |
| IMethod[] methodArray = interfaceType.getMethods(); |
| // Make sure the method isn't already defined in the heirarchy |
| for (int j = 0; j < methodArray.length; j++) { |
| if (isMethodImplementedInHierarchy(methodArray[j], superClassType)) |
| continue; |
| String methodStub = getMethodStub(methodArray[j], qualifiedClassName, className); |
| sb.append(methodStub); |
| } |
| } |
| } |
| } catch (JavaModelException e) { |
| Logger.getLogger().log(e); |
| } |
| // Return method stubs string |
| return sb.toString(); |
| } |
| |
| /** |
| * This method is intended for internal use only. Checks to see if the passed type name |
| * is of a primitive type. This method does not accept null. It will not return null. |
| * @see Signature#getElementType(java.lang.String) |
| * |
| * @param typeName |
| * @return boolean is type Primitive? |
| */ |
| private boolean isPrimitiveType(String typeName) { |
| char first = Signature.getElementType(typeName).charAt(0); |
| return (first != Signature.C_RESOLVED && first != Signature.C_UNRESOLVED); |
| } |
| |
| /** |
| * This method is intended for internal use only. This will add import statements for the specified |
| * type if it is determined to be necessary. This does accept null parameters. It will not return null. |
| * @see NewJavaClassOperation#getMethodStub(IMethod, String, String) |
| * |
| * @param refTypeSig |
| * @param declaringType |
| * @return String type signature |
| * @throws JavaModelException |
| */ |
| private String resolveAndAdd(String refTypeSig, IType declaringType) throws JavaModelException { |
| if(refTypeSig.indexOf(Signature.C_GENERIC_START, 0) != -1){ |
| getImportStatements(refTypeSig, declaringType); |
| } else { |
| String resolvedTypeName = JavaModelUtil.getResolvedTypeName(refTypeSig, declaringType); |
| // Could type not be resolved and is import statement missing? |
| if (resolvedTypeName != null && !importStatements.contains(resolvedTypeName) && !resolvedTypeName.startsWith("java.lang")) { //$NON-NLS-1$ |
| importStatements.add(resolvedTypeName); |
| } |
| } |
| return Signature.toString(refTypeSig); |
| } |
| |
| private void getImportStatements(String signature, IType declaringType) throws JavaModelException{ |
| String erasure = Signature.getTypeErasure(signature); |
| String resolvedTypeName = JavaModelUtil.getResolvedTypeName(erasure, declaringType); |
| if (resolvedTypeName != null && !importStatements.contains(resolvedTypeName) && !resolvedTypeName.startsWith("java.lang")) { //$NON-NLS-1$ |
| importStatements.add(resolvedTypeName); |
| } |
| String [] params = Signature.getTypeArguments(signature); |
| for(int i=0;i<params.length; i++){ |
| getImportStatements(params[i], declaringType); |
| } |
| } |
| |
| /** |
| * This method is intended for internal use only. This will use the predefined tokens to generate the |
| * actual method stubs. This method does not accept null parameters. It will not return null. |
| * |
| * @param method |
| * @param superClassName |
| * @param className |
| * @return String method stub |
| */ |
| private String getMethodStub(IMethod method, String superClassName, String className) { |
| StringBuffer sb = new StringBuffer(); |
| try { |
| IType parentType = method.getDeclaringType(); |
| String name = method.getElementName(); |
| String[] paramTypes = method.getParameterTypes(); |
| String[] paramNames = method.getParameterNames(); |
| String[] exceptionTypes = method.getExceptionTypes(); |
| |
| // Parameters String |
| String paramString = EMPTY_STRING; |
| int nP = paramTypes.length; |
| for (int i = 0; i < nP; i++) { |
| String type = paramTypes[i]; |
| // update import statements |
| if (!isPrimitiveType(type)) { |
| type = resolveAndAdd(type, parentType); |
| } else { |
| type = Signature.toString(type); |
| } |
| |
| int index = type.lastIndexOf(DOT); |
| if (index != -1) |
| type = type.substring(index + 1); |
| paramString += type + SPACE + paramNames[i]; |
| if (i < nP - 1) |
| paramString += COMMA + SPACE; |
| } |
| // Java doc |
| sb.append("\t/* (non-Java-doc)"); //$NON-NLS-1$ |
| sb.append(lineSeparator); |
| sb.append("\t * @see "); //$NON-NLS-1$ |
| sb.append(superClassName + POUND + name + OPEN_PAR); |
| sb.append(paramString); |
| sb.append(CLOSE_PAR); |
| sb.append(lineSeparator); |
| sb.append("\t */"); //$NON-NLS-1$ |
| sb.append(lineSeparator); |
| // access |
| sb.append(TAB); |
| if (Flags.isPublic(method.getFlags())) |
| sb.append(PUBLIC); |
| else if (Flags.isProtected(method.getFlags())) |
| sb.append(PROTECTED); |
| else if (Flags.isPrivate(method.getFlags())) |
| sb.append(PRIVATE); |
| String returnType = null; |
| if (method.isConstructor()) { |
| sb.append(className); |
| } else { |
| // return type |
| returnType = method.getReturnType(); |
| if (!isPrimitiveType(returnType)) { |
| returnType = resolveAndAdd(returnType, parentType); |
| } else { |
| returnType = Signature.toString(returnType); |
| } |
| int idx = returnType.lastIndexOf(DOT); |
| if (idx == -1) |
| sb.append(returnType); |
| else |
| sb.append(returnType.substring(idx + 1)); |
| sb.append(SPACE); |
| // name |
| sb.append(name); |
| } |
| // Parameters |
| sb.append(OPEN_PAR + paramString + CLOSE_PAR); |
| // exceptions |
| int nE = exceptionTypes.length; |
| if (nE > 0) { |
| sb.append(SPACE + THROWS); |
| for (int i = 0; i < nE; i++) { |
| String type = exceptionTypes[i]; |
| if (!isPrimitiveType(type)) { |
| type = resolveAndAdd(type, parentType); |
| } else { |
| type = Signature.toString(type); |
| } |
| int index = type.lastIndexOf(DOT); |
| if (index != -1) |
| type = type.substring(index + 1); |
| sb.append(type); |
| if (i < nE - 1) |
| sb.append(COMMA + SPACE); |
| } |
| } |
| sb.append(SPACE + OPEN_BRA); |
| sb.append(lineSeparator); |
| if (method.isConstructor()) { |
| sb.append(TAB + TAB + SUPER + OPEN_PAR); |
| for (int i = 0; i < nP; i++) { |
| sb.append(paramNames[i]); |
| if (i < nP - 1) |
| sb.append(COMMA + SPACE); |
| } |
| sb.append(CLOSE_PAR + SEMICOLON); |
| sb.append(lineSeparator); |
| } else { |
| String methodBody = getMethodBody(method, returnType); |
| sb.append(methodBody); |
| } |
| sb.append(TAB + CLOSE_BRA); |
| sb.append(lineSeparator); |
| sb.append(lineSeparator); |
| } catch (JavaModelException e) { |
| Logger.getLogger().log(e); |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * This method is intended for internal use only. It checks to see whether or not the |
| * method is already implemented in the class heirarchy. |
| * It does not accept null parameters. It will not return null. |
| * @see NewJavaClassOperation#getUnimplementedMethodsFromInterfaces(IType, String, IJavaProject) |
| * |
| * @param method |
| * @param superClass |
| * @return boolean is method already in heirarchy? |
| */ |
| private boolean isMethodImplementedInHierarchy(IMethod method, IType superClass) { |
| boolean ret = false; |
| IMethod foundMethod = findMethodImplementationInHierarchy(method, superClass); |
| // if the method exists and the property is set on the data model, then return true |
| if (foundMethod != null && foundMethod.exists() && !implementImplementedMethod(method)) |
| ret = true; |
| return ret; |
| } |
| |
| /** |
| * This method is intended for internal use only. This will recursively check the supertype heirarchy for |
| * the passed in method. This will not accept null parameters. It will return null if the method does |
| * not already exist in the heirarchy. |
| * @see NewJavaClassOperation#isMethodImplementedInHierarchy(IMethod, IType) |
| * |
| * @param method |
| * @param superClass |
| * @return IMethod the method from the heirarchy |
| */ |
| private IMethod findMethodImplementationInHierarchy(IMethod method, IType superClass) { |
| IMethod implementedMethod = null; |
| try { |
| if (superClass != null && superClass.exists()) { |
| ITypeHierarchy tH = superClass.newSupertypeHierarchy(new NullProgressMonitor()); |
| implementedMethod = findMethodImplementationInHierarchy(tH, superClass, method.getElementName(), method.getParameterTypes(), method.isConstructor()); |
| } |
| } catch (JavaModelException e) { |
| //Ignore |
| } |
| return implementedMethod; |
| } |
| |
| /** |
| * This method is intended for internal use only. This will recursively check the supertype heirarchy for |
| * the passed in method. This will not accept null parameters. It will return null if the method does |
| * not already exist in the heirarchy. |
| * @see NewJavaClassOperation#findMethodImplementationInHierarchy(IMethod, IType) |
| * @see JavaModelUtil#findMethodImplementationInHierarchy(ITypeHierarchy, IType, String, String[], boolean) |
| * |
| * @param tH |
| * @param thisType |
| * @param methodName |
| * @param parameterTypes |
| * @param isConstructor |
| * @return IMethod |
| * @throws JavaModelException |
| */ |
| private IMethod findMethodImplementationInHierarchy(ITypeHierarchy tH, IType thisType, String methodName, String parameterTypes[], boolean isConstructor) throws JavaModelException { |
| IMethod found = JavaModelUtil.findMethod(methodName, parameterTypes, isConstructor, thisType); |
| // If method exists make sure it is not abstract |
| if (found != null && !Flags.isAbstract(found.getFlags())) { |
| return found; |
| } |
| // Check recursively |
| return JavaModelUtil.findMethodInHierarchy(tH, thisType, methodName, parameterTypes, isConstructor); |
| } |
| |
| /** |
| * Subclasses may extend this method to provide their own specific method body definitions. |
| * The default implementation is to add a todo, and to return the appropriate type. |
| * This method does not accept null parameters. It will not return null. |
| * @see NewJavaClassOperation#getMethodStub(IMethod, String, String) |
| * |
| * @param method |
| * @param returnType |
| * @return String method body |
| */ |
| protected String getMethodBody(IMethod method, String returnType) { |
| // Add a todo comment |
| String body = TODO_COMMENT; |
| body += lineSeparator; |
| // Add the appropriate default return type |
| if (returnType == null || returnType.equals(VOID)) |
| return body; |
| if (returnType.equals(INT)) |
| body += RETURN_0; |
| else if (returnType.equals(BOOLEAN)) |
| body += RETURN_FALSE; |
| else |
| body += RETURN_NULL; |
| body += lineSeparator; |
| // Return the method body |
| return body; |
| } |
| |
| /** |
| * Subclasses may extend this method to provide their own user defined method stubs. The |
| * default implementation to just return an empty string. This method will not accept |
| * null parameter. It will not return null. |
| * @see NewJavaClassOperation#getMethodStubs(String, String) |
| * |
| * @param superClassType |
| * @return String user defined methods |
| */ |
| protected String getUserDefinedMethodStubs(IType superClassType) { |
| return EMPTY_STRING; |
| } |
| |
| /** |
| * Subclasses may extend this method to provide their own specialized return on which nonimplemented |
| * methods to implement. This does not accept a null parameter. This will not return null. |
| * The default implementation is to always return false. |
| * |
| * @param method |
| * @return boolean should implement method? |
| */ |
| protected boolean implementImplementedMethod(IMethod method) { |
| return false; |
| } |
| |
| @Override |
| public IStatus execute(IProgressMonitor monitor, IAdaptable info) |
| throws ExecutionException { |
| // TODO Auto-generated method stub |
| return doExecute(monitor, info); |
| } |
| |
| public IProject getTargetProject() { |
| String projectName = model.getStringProperty(IArtifactEditOperationDataModelProperties.PROJECT_NAME); |
| return ProjectUtilities.getProject(projectName); |
| } |
| } |