/*******************************************************************************
* Copyright (c) 2011 Gerd Wuetherich (gerd@gerd-wuetherich.de).
* 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:
* Gerd Wuetherich (gerd@gerd-wuetherich.de) - initial API and implementation
******************************************************************************/
package org.bundlemaker.core.parser.bytecode;
import org.bundlemaker.core.common.ResourceType;
import org.bundlemaker.core.jtype.ITypeResource;
import org.bundlemaker.core.jtype.JavaTypeUtils;
import org.bundlemaker.core.jtype.JavaUtils;
import org.bundlemaker.core.parser.IProblem;
import org.bundlemaker.core.parser.bytecode.asm.ArtefactAnalyserClassVisitor;
import org.bundlemaker.core.parser.bytecode.asm.AsmReferenceRecorder;
import org.bundlemaker.core.project.IProjectContentEntry;
import org.bundlemaker.core.spi.parser.AbstractParser;
import org.bundlemaker.core.spi.parser.IParsableResource;
import org.objectweb.asm.ClassReader;
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public class ByteCodeParser extends AbstractParser {
/**
* {@inheritDoc}
*/
@Override
public ParserType getParserType() {
return ParserType.BINARY;
}
/**
* {@inheritDoc}
*/
@Override
public boolean canParse(IParsableResource resource) {
//
if (!resource.getPath().endsWith(".class")) {
return false;
}
//
return JavaUtils.isValidJavaPackage(resource.getPath());
}
@Override
protected void doParseResource(IProjectContentEntry content,
IParsableResource resource, boolean parseReferences, boolean isBatchParse) {
// if the resource already contains a type, it already has been parsed.
// In this case we can return immediately
if (resource.adaptAs(ITypeResource.class) != null && !resource.adaptAs(ITypeResource.class).getContainedTypes()
.isEmpty()) {
return;
}
// if the resource does not contain a anonymous or local type
// the enclosing resource is the resource (the default)
IParsableResource enclosingResource = resource;
// get fully qualified type name
String fullyQualifiedName = JavaTypeUtils
.convertToFullyQualifiedName(resource.getPath());
// if the type is an anonymous or local type,
// we have to get the enclosing type name
if (JavaTypeUtils.isLocalOrAnonymousTypeName(fullyQualifiedName)
&& parseReferences) {
// get the name of the enclosing type
String enclosingName = JavaTypeUtils
.getEnclosingNonLocalAndNonAnonymousTypeName(fullyQualifiedName);
// get the enclosing resource
enclosingResource = content.getResource(
JavaTypeUtils.convertFromFullyQualifiedName(enclosingName),
ResourceType.BINARY).adaptAs(IParsableResource.class);
// if we have to parse the enclosing type
if (enclosingResource.adaptAs(ITypeResource.class)
.getContainedTypes().isEmpty()) {
parseResource(content, enclosingResource, true, false);
if (enclosingResource.adaptAs(ITypeResource.class)
.getContainedTypes().isEmpty()) {
// TODO
// TODO remove null handling in AsmReferenceRecorder
// Assert.isTrue(!enclosingResource.getContainedTypes().isEmpty());
}
}
}
try {
// create a new references recorder
AsmReferenceRecorder referenceRecorder = new AsmReferenceRecorder(
resource, enclosingResource);
// parse the class file
byte[] bytes = resource.getContent();
ClassReader reader = new ClassReader(bytes);
reader.accept(new ArtefactAnalyserClassVisitor(referenceRecorder,
parseReferences), 0);
} catch (Exception e) {
e.printStackTrace();
IProblem byteCodeParserProblem = new IProblem.DefaultProblem(
resource, e.toString());
getProblems().add(byteCodeParserProblem);
}
}
}