summaryrefslogtreecommitdiff
path: root/src/plugins/android.codeutils/src/com/motorola/studio/android/model/java/JavaClass.java
diff options
context:
space:
mode:
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.java426
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;
+ }
+
+}