diff options
Diffstat (limited to 'src/plugins/android.codeutils/src/com/motorola/studio/android/model/java/JavaClass.java')
-rw-r--r-- | src/plugins/android.codeutils/src/com/motorola/studio/android/model/java/JavaClass.java | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/src/plugins/android.codeutils/src/com/motorola/studio/android/model/java/JavaClass.java b/src/plugins/android.codeutils/src/com/motorola/studio/android/model/java/JavaClass.java new file mode 100644 index 0000000..523a38e --- /dev/null +++ b/src/plugins/android.codeutils/src/com/motorola/studio/android/model/java/JavaClass.java @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.motorola.studio.android.model.java; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jdt.core.ToolFactory; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.BodyDeclaration; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodRef; +import org.eclipse.jdt.core.dom.MethodRefParameter; +import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; +import org.eclipse.jdt.core.dom.PackageDeclaration; +import org.eclipse.jdt.core.dom.PrimitiveType; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.TagElement; +import org.eclipse.jdt.core.dom.Type; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.formatter.CodeFormatter; +import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.osgi.util.NLS; +import org.eclipse.text.edits.MalformedTreeException; +import org.eclipse.text.edits.TextEdit; + +import com.motorola.studio.android.codeutils.i18n.CodeUtilsNLS; +import com.motorola.studio.android.common.exception.AndroidException; +import com.motorola.studio.android.common.log.StudioLogger; + +/** + * Abstract class that contains the basic structure to create java classes programatically + */ +public abstract class JavaClass +{ + protected static Annotation OVERRIDE_ANNOTATION; + + static + { + AST tempAST = AST.newAST(AST.JLS3); + + OVERRIDE_ANNOTATION = tempAST.newMarkerAnnotation(); + OVERRIDE_ANNOTATION.setTypeName(tempAST.newSimpleName("Override")); + + tempAST = null; + } + + protected CompilationUnit compUnit; + + protected AST ast; + + protected TypeDeclaration classDecl = null; + + protected IDocument document; + + protected String className; + + protected String[] packageName; + + protected String[] superClass; + + /** + * Class constructor. Creates the basic elements for the class: + * package name and class declaration based on a super class. + * + * @param className The simple class name + * @param packageName The full-qualified class package name + * @param superClass The full-qualified super class name + */ + @SuppressWarnings("unchecked") + protected JavaClass(String className, String packageName, String superClass) + { + // It is expected that the parameters have been validated + // by the UI + Assert.isNotNull(className); + Assert.isNotNull(packageName); + Assert.isNotNull(superClass); + + this.className = className; + this.packageName = getFQNAsArray(packageName); + this.superClass = getFQNAsArray(superClass); + + // The package name must have two identifiers at least, according to + // the Android specifications + Assert.isLegal(packageName.length() > 1); + // So, the superclass must have at least two identifiers plus the name + Assert.isLegal(superClass.length() > 2); + + ast = AST.newAST(AST.JLS3); + compUnit = ast.newCompilationUnit(); + + Type superClassType = null; + + // Sets the package name to the class + PackageDeclaration pd = ast.newPackageDeclaration(); + QualifiedName qPackageName = + ast.newQualifiedName(ast.newName(getQualifier(this.packageName)), + ast.newSimpleName(getName(this.packageName))); + pd.setName(qPackageName); + compUnit.setPackage(pd); + + // Imports the super class + ImportDeclaration id = ast.newImportDeclaration(); + id.setName(ast.newName(superClass)); + compUnit.imports().add(id); + superClassType = ast.newSimpleType(ast.newName(getName(this.superClass))); + + // Creates the class + classDecl = ast.newTypeDeclaration(); + classDecl.modifiers().add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD)); + if (superClassType != null) + { + classDecl.setSuperclassType(superClassType); + } + + classDecl.setName(ast.newSimpleName(className)); + compUnit.types().add(classDecl); + + document = new Document(compUnit.toString()); + } + + /** + * Gets the class content + * + * @return an IDocument object containing the class content + */ + public IDocument getClassContent() throws AndroidException + { + String content = compUnit.toString(); + document = new Document(content); + + // Formats the code using the Eclipse settings + CodeFormatter codeFormatter = + ToolFactory.createCodeFormatter(DefaultCodeFormatterConstants + .getEclipseDefaultSettings()); + + TextEdit textEdit = + codeFormatter.format(CodeFormatter.K_COMPILATION_UNIT + | CodeFormatter.F_INCLUDE_COMMENTS, content, 0, content.length(), 0, null); + + try + { + textEdit.apply(document); + } + catch (MalformedTreeException e) + { + String errMsg = + NLS.bind(CodeUtilsNLS.EXC_JavaClass_ErrorFormattingSourceCode, className); + + StudioLogger.error(JavaClass.class, errMsg, e); + throw new AndroidException(errMsg); + } + catch (BadLocationException e) + { + String errMsg = + NLS.bind(CodeUtilsNLS.EXC_JavaClass_ErrorFormattingSourceCode, className); + + StudioLogger.error(JavaClass.class, errMsg, e); + throw new AndroidException(errMsg); + } + + addComments(); + + return document; + } + + /** + * Adds comments to the code. As we cannot add comments when + * we are making the AST, comments need to be insert after the + * class creation + */ + protected abstract void addComments() throws AndroidException; + + /** + * Adds a parameter to a method + * + * @param method The method object + * @param parameterName The parameter name + * @param parameterType The parameter type (only the single name, not the qualified) + */ + @SuppressWarnings("unchecked") + protected void addMethodParameter(MethodDeclaration method, String parameterName, + Type parameterType) + { + SingleVariableDeclaration vd = ast.newSingleVariableDeclaration(); + vd.setName(ast.newSimpleName(parameterName)); + vd.setType(parameterType); + method.parameters().add(vd); + } + + /** + * Adds a comment to a BodyDeclaration object. + * For now, this method does nothing. + * + * @param element The element to add the comment + * @param comment The comment + */ + //@SuppressWarnings("unchecked") + protected void addComment(BodyDeclaration element, String comment) + { + // TODO These comments will be reviewed for the Phase B + /*Javadoc javadoc = element.getJavadoc(); + TextElement textElement = ast.newTextElement(); + TagElement tagElement = ast.newTagElement(); + + if (javadoc == null) + { + javadoc = ast.newJavadoc(); + element.setJavadoc(javadoc); + } + + textElement.setText(comment); + tagElement.fragments().add(textElement); + javadoc.tags().add(tagElement);*/ + } + + /** + * Adds documentation reference to a method (the see tag to the javadoc) + * + * @param element The method declaration object + * @param qualifiedClassName The full qualified class name to refer + * @param methodName The method to refer + * @param parameters The method parameters + */ + @SuppressWarnings("unchecked") + protected void addMethodReference(MethodDeclaration element, String qualifiedClassName, + String methodName, Type[] parameters) + { + String[] fqnArray = getFQNAsArray(qualifiedClassName); + + MethodRef methodRef = ast.newMethodRef(); + methodRef.setQualifier(ast.newQualifiedName(ast.newName(getQualifier(fqnArray)), + ast.newSimpleName(getName(fqnArray)))); + + methodRef.setName(ast.newSimpleName(methodName)); + + if ((parameters != null) && (parameters.length > 0)) + { + for (Type param : parameters) + { + MethodRefParameter methodParam = ast.newMethodRefParameter(); + methodParam.setType(param); + methodRef.parameters().add(methodParam); + } + } + + Javadoc javadoc = element.getJavadoc(); + TagElement tagElement = ast.newTagElement(); + tagElement.setTagName(TagElement.TAG_SEE); + + if (javadoc == null) + { + javadoc = ast.newJavadoc(); + element.setJavadoc(javadoc); + } + + tagElement.fragments().add(methodRef); + javadoc.tags().add(tagElement); + } + + /** + * Adds an empty block to a method declaration + * + * @param method The method declaration + * @param returnType The method return type. If the method does not have one, use null + */ + @SuppressWarnings("unchecked") + protected void addEmptyBlock(MethodDeclaration method) + { + Expression expression = null; + Block emptyBlock = ast.newBlock(); + ReturnStatement returnStatement = ast.newReturnStatement(); + Type returnType = method.getReturnType2(); + + if (returnType instanceof PrimitiveType) + { + PrimitiveType pType = (PrimitiveType) returnType; + if (pType.getPrimitiveTypeCode() == PrimitiveType.BOOLEAN) + { + expression = ast.newBooleanLiteral(false); + } + else if (pType.getPrimitiveTypeCode() != PrimitiveType.VOID) + { + expression = ast.newNumberLiteral("0"); + } + } + else + { + expression = ast.newNullLiteral(); + } + + if (expression != null) + { + returnStatement.setExpression(expression); + emptyBlock.statements().add(returnStatement); + } + + method.setBody(emptyBlock); + } + + /** + * Creates a new string Type object + * + * @return a new string Type object + */ + protected Type stringType() + { + return ast.newSimpleType(ast.newSimpleName(String.class.getSimpleName())); + } + + /** + * Creates a new string array Type object + * + * @return a new string array Type object + */ + protected Type stringArrayType() + { + return ast.newArrayType(ast.newSimpleType(ast.newName(String.class.getSimpleName()))); + } + + /** + * Creates a new int array Type object + * + * @return a new int array Type object + */ + protected Type intArrayType() + { + return ast.newArrayType(ast.newPrimitiveType(PrimitiveType.INT)); + } + + /** + * Returns a full qualified class name as a array + * + * @param fqn The full qualified class name + * @return the full qualified class name as a array + */ + protected static String[] getFQNAsArray(String fqn) + { + String[] parts; + + if (fqn.contains(".")) + { + parts = fqn.split("\\."); + } + else + { + parts = new String[] + { + fqn + }; + } + + return parts; + } + + /** + * Retrieves the qualifier for a full qualified name. + * Example: + * com.motorola.studio.android.MyClass + * + * The qualifier for the class is com.motorola.studio.android + * + * @param qualifiedName The full qualified name + * @return The qualifier + */ + protected static String[] getQualifier(String[] qualifiedName) + { + String[] qualifier; + + if (qualifiedName.length > 1) + { + qualifier = new String[qualifiedName.length - 1]; + + System.arraycopy(qualifiedName, 0, qualifier, 0, qualifiedName.length - 1); + } + else + { + qualifier = qualifiedName; + } + + return qualifier; + } + + /** + * Gets the name part from a full qualified name + * + * @param qualifiedName The full qualified name + * + * @return The name part from a full qualified name + */ + protected static String getName(String[] qualifiedName) + { + String name = null; + + if ((qualifiedName != null) && (qualifiedName.length > 0)) + { + name = qualifiedName[qualifiedName.length - 1]; + } + + return name; + } + +} |