/*******************************************************************************
* Copyright (c) 2012-2015 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ext.java.worker;
import org.eclipse.che.ide.collections.Array;
import org.eclipse.che.ide.collections.js.JsoArray;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTNode;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTVisitor;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AnnotationTypeDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.che.ide.ext.java.jdt.core.dom.CompilationUnit;
import org.eclipse.che.ide.ext.java.jdt.core.dom.EnumDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.FieldDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ImportDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.MethodDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.PackageDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Type;
import org.eclipse.che.ide.ext.java.jdt.core.dom.TypeDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.che.ide.ext.java.messages.BlockTypes;
import org.eclipse.che.ide.ext.java.messages.impl.OutlineUpdateMessage;
import org.eclipse.che.ide.ext.java.messages.impl.WorkerCodeBlock;
import java.util.Iterator;
/**
* Worker Outline updater
*
* @author Evgen Vidolob
*/
public class WorkerOutlineModelUpdater {
private WorkerCodeBlock root;
private JavaParserWorker worker;
public WorkerOutlineModelUpdater(JavaParserWorker worker) {
this.worker = worker;
}
public void onCompilationUnitChanged(CompilationUnit cUnit, String path) {
if (this.root == null) {
root = WorkerCodeBlock.make();
// root.setType(CodeBlock.ROOT_TYPE);
root.setOffset(0);
root.setChildren(JsoArray.<WorkerCodeBlock>create());
}
OutlineAstVisitor v = new OutlineAstVisitor(root, cUnit);
cUnit.accept(v);
OutlineUpdateMessage message = OutlineUpdateMessage.make();
message.setFilePath(path).setBlocks(v.childrens);
worker.sendMessage(message.serialize());
}
class OutlineAstVisitor extends ASTVisitor {
private final ASTNode astParent;
WorkerCodeBlock parent;
Array<WorkerCodeBlock> childrens = JsoArray.create();
private WorkerCodeBlock imports;
/** @param parent */
public OutlineAstVisitor(WorkerCodeBlock parent, ASTNode astParent) {
super();
this.parent = parent;
this.astParent = astParent;
}
/** {@inheritDoc} */
@Override
public boolean visit(PackageDeclaration node) {
WorkerCodeBlock i = createCodeBlock(BlockTypes.PACKAGE.getType(), node.getStartPosition(), node.getLength());
i.setName(node.getName().getFullyQualifiedName());
childrens.add(i);
return false;
}
/** {@inheritDoc} */
@Override
public boolean visit(ImportDeclaration node) {
if (imports == null) {
imports = WorkerCodeBlock.make();
imports.setChildren(JsoArray.<WorkerCodeBlock>create());
imports.setType(BlockTypes.IMPORTS.getType());
imports.setName("import declarations");
imports.setOffset(node.getStartPosition());
imports.setLength(0);
childrens.add(imports);
}
WorkerCodeBlock c = createCodeBlock(BlockTypes.IMPORT.getType(), node.getStartPosition(), node.getLength());
c.setName(node.getName().getFullyQualifiedName());
imports.getChildren().add(c);
return false;
}
/** {@inheritDoc} */
@Override
public boolean visit(TypeDeclaration node) {
if (node == astParent)
return true;
WorkerCodeBlock type = addJavaType(node, node.isInterface() ? BlockTypes.INTERFACE : BlockTypes.CLASS);
addChildrens(node, type);
return false;
}
/** {@inheritDoc} */
@Override
public boolean visit(AnnotationTypeDeclaration node) {
if (node == astParent)
return true;
WorkerCodeBlock type = addJavaType(node, BlockTypes.ANNOTATION);
addChildrens(node, type);
return false;
}
private void addChildrens(ASTNode node, WorkerCodeBlock type) {
OutlineAstVisitor typeVisitor = new OutlineAstVisitor(type, node);
node.accept(typeVisitor);
type.setChildren(typeVisitor.childrens);
}
/** {@inheritDoc} */
@Override
public boolean visit(EnumDeclaration node) {
if (node == astParent)
return true;
WorkerCodeBlock type = addJavaType(node, BlockTypes.ENUM);
addChildrens(node, type);
return false;
}
private WorkerCodeBlock addJavaType(AbstractTypeDeclaration node, BlockTypes type) {
WorkerCodeBlock t = createCodeBlock(type.getType(), node.getStartPosition(), node.getLength());
t.setModifiers(node.getModifiers());
t.setName(node.getName().getFullyQualifiedName());
childrens.add(t);
return t;
}
/** {@inheritDoc} */
@Override
public boolean visit(FieldDeclaration node) {
if (node == astParent)
return true;
for (VariableDeclarationFragment fragment : node.fragments()) {
WorkerCodeBlock f = createCodeBlock(BlockTypes.FIELD.getType(), fragment.getStartPosition(), fragment.getLength());
f.setName(fragment.getName().getFullyQualifiedName());
f.setModifiers(node.getModifiers());
f.setJavaType(node.getType().toString());
childrens.add(f);
}
return false;
}
/** {@inheritDoc} */
@Override
public boolean visit(MethodDeclaration node) {
if (node == astParent)
return true;
WorkerCodeBlock m = createCodeBlock(BlockTypes.METHOD.getType(), node.getStartPosition(), node.getLength());
m.setModifiers(node.getModifiers());
m.setName(node.getName().getFullyQualifiedName() + getMethodParams(node));
Type returnType = node.getReturnType2();
m.setJavaType(returnType != null ? returnType.toString() : null);
childrens.add(m);
addChildrens(node, m);
return false;
}
/** {@inheritDoc} */
@Override
public boolean visit(AnonymousClassDeclaration node) {
if (node == astParent)
return true;
String name = "";
ASTNode parent = node.getParent();
if (parent instanceof ClassInstanceCreation) {
Type type = ((ClassInstanceCreation)parent).getType();
name = ASTNodes.getTypeName(type);
}
WorkerCodeBlock type = createCodeBlock(BlockTypes.CLASS.getType(), node.getStartPosition(), node.getLength());
type.setName(name);
childrens.add(type);
addChildrens(node, type);
return false;
}
private WorkerCodeBlock createCodeBlock(String type, int offset, int length) {
return WorkerCodeBlock.make().setType(type).setOffset(offset).setLength(length).setChildren(JsoArray.<WorkerCodeBlock>create());
}
/**
* Returns the string presentation of method's parameters.
*
* @param method
* @return {@link String} method's parameters comma separated
*/
@SuppressWarnings("unchecked")
protected String getMethodParams(MethodDeclaration method) {
if (method.parameters().isEmpty()) {
return "()";
} else {
Iterator<SingleVariableDeclaration> paramsIterator = method.parameters().iterator();
StringBuffer params = new StringBuffer("(");
while (paramsIterator.hasNext()) {
SingleVariableDeclaration variable = paramsIterator.next();
params.append(variable.getType().toString());
if (paramsIterator.hasNext()) {
params.append(", ");
}
}
params.append(")");
return params.toString();
}
}
}
}