blob: f88b27b6dc3b0d011c5412f9186de8b6de361194 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Helen Hawkins and Sian January - initial version
*******************************************************************************/
package org.eclipse.ajdt.internal.launching;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.ajdt.core.AspectJPlugin;
import org.eclipse.ajdt.core.javaelements.AJCompilationUnit;
import org.eclipse.ajdt.core.javaelements.AJCompilationUnitManager;
import org.eclipse.ajdt.core.javaelements.AspectElement;
import org.eclipse.ajdt.ui.buildconfig.DefaultBuildConfigurator;
import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
public class LTWUtils {
public final static String AOP_XML_LOCATION = "META-INF/aop.xml"; //$NON-NLS-1$
/**
* Generate one aop.xml file for each source directory in the given project.
* The aop.xml files will list all concrete aspects included in the active
* build configuration.
* @param project
*/
public static void generateLTWConfigFile(IJavaProject project) {
try {
// Get all the source folders in the project
IPackageFragmentRoot[] roots = project.getAllPackageFragmentRoots();
for (int i = 0; i < roots.length; i++) {
IPackageFragmentRoot root = roots[i];
if (!(root instanceof JarPackageFragmentRoot)) {
List aspects = getAspects(root);
String path;
if (root.getElementName().trim().equals("")) { //$NON-NLS-1$
path = AOP_XML_LOCATION;
} else {
path = root.getElementName().trim().concat("/").concat(AOP_XML_LOCATION); //$NON-NLS-1$
}
IFile ltwConfigFile = (IFile) project.getProject().findMember(path);
// If the source folder does not already contain an aop.xml file:
if (ltwConfigFile == null) {
if (aspects.size() != 0) { // If there are aspects in the list
// Create the META-INF folder and the aop.xml file
IFolder metainf = (IFolder) ((Workspace)ResourcesPlugin.getWorkspace()).
newResource(project.getPath().append("/" + root.getElementName() + "/META-INF"), //$NON-NLS-1$ //$NON-NLS-2$
IResource.FOLDER);
IFile aopFile = (IFile) ((Workspace)ResourcesPlugin.getWorkspace()).
newResource(project.getPath().append(path),
IResource.FILE);
metainf.create(true,true,null);
aopFile.create(new ByteArrayInputStream(new byte[0]), true, null);
project.getProject().refreshLocal(4, null);
// Add the xml content to the aop.xml file
addAspectsToLTWConfigFile(false, aspects, aopFile);
}
// Otherwise update the existing file
} else {
addAspectsToLTWConfigFile(true, aspects, ltwConfigFile);
}
}
}
} catch (Exception e) {
}
}
/**
* Create a new xml document with an 'aspectj' element that contains
* one 'aspects' element.
* @throws ParserConfigurationException
*/
private static Document createNewXMLDocument() throws ParserConfigurationException {
// Create the document and add a root 'aspectj' element with one 'aspects' child element
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
DOMImplementation impl = builder.getDOMImplementation();
Document doc = impl.createDocument(null, "aspectj", null); //$NON-NLS-1$
Element root = doc.getDocumentElement();
Element aspectsElement = doc.createElement("aspects"); //$NON-NLS-1$
root.appendChild(aspectsElement);
return doc;
}
/**
* Updates the given aop.xml file with the current aspects to be included.
* The file should exist when this method is called.
* @param readFileFirst - if true then file already contains xml content
* @param aspects - the list of aspects (IAspectElement)
* @param configFile - the file
* @throws Exception
*/
private static void addAspectsToLTWConfigFile(boolean readFileFirst,
List aspects, IFile configFile)
throws Exception {
Document doc;
if (readFileFirst) { // If the aop.xml file already exists load the existing document
doc = readFile(configFile);
} else { // Otherwise create a new document
doc = createNewXMLDocument();
}
if (doc == null) {
return;
}
NodeList children = doc.getDocumentElement().getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child.getNodeName().equals("aspects")) { //$NON-NLS-1$
// Delete any existing aspects
if (child.hasChildNodes()) {
Node root = child.getFirstChild();
while (root != null){
child.removeChild(root);
root = child.getFirstChild();
}
}
// Add all the current aspects to the document
for (Iterator iter = aspects.iterator(); iter.hasNext();) {
AspectElement aspect = (AspectElement) iter.next();
Element grandChild = doc.createElement("aspect"); //$NON-NLS-1$
grandChild.setAttribute("name",getFullyQualifiedName(aspect)); //$NON-NLS-1$
child.appendChild(grandChild);
}
}
}
// Write out the document
File file = new File(getFileName(configFile));
XMLPrintHandler.writeFile(doc, file);
configFile.refreshLocal(1,null);
}
/**
* Creates an XML document from the given file
* @param configFile
* @return
* @throws Exception if there was an error reading the file or creating the Document
*/
private static Document readFile(IFile configFile) throws Exception {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
builder.setErrorHandler(new AOPXMLErrorHandler());
return builder.parse(configFile.getContents());
}
/**
* Get the OS specific full path for the given file
* @param configFile
* @return
*/
private static String getFileName(IFile configFile) {
return ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString()
+ configFile.getFullPath().toOSString();
}
/**
* Get the fully qualified name for the given aspect (e.g. package.Class
* or package.EnclosingClass.InnerClass)
* @param aspect
* @return
*/
private static String getFullyQualifiedName(AspectElement aspect) {
StringBuffer sb = new StringBuffer();
IJavaElement parent = aspect.getCompilationUnit().getParent();
if (parent instanceof IPackageFragment
&& !parent.getElementName().equals("")) { //$NON-NLS-1$
sb.append(parent.getElementName());
sb.append("."); //$NON-NLS-1$
}
sb.append(getFullTypeName(aspect));
return sb.toString();
}
/**
* Get the full type name for the given type, including any enclosing classes.
* @param element
* @return
*/
private static String getFullTypeName(IType element) {
if (element != null && element.getParent() instanceof IType) {
return getFullTypeName((IType)element.getParent()) + "." + element.getElementName(); //$NON-NLS-1$
} else {
return element.getElementName();
}
}
/**
* Get a list of all the aspects found in the given source
* directory, which are included in the current build.
* @param root
* @return List of AspectElements
* @throws CoreException
*/
public static List /* AspectElement */ getAspects(
final IPackageFragmentRoot root) throws CoreException {
final List aspects = new ArrayList();
root.getResource().accept(new IResourceVisitor() {
public boolean visit(IResource resource) {
if (resource instanceof IFile
&& AspectJPlugin.AJ_FILE_EXT.equals(resource
.getFileExtension())) {
AJCompilationUnit ajcu = AJCompilationUnitManager.INSTANCE
.getAJCompilationUnit((IFile) resource);
if (ajcu != null
&& DefaultBuildConfigurator.getBuildConfigurator()
.getProjectBuildConfigurator(
root.getJavaProject())
.getActiveBuildConfiguration().isIncluded(
ajcu.getResource())) {
try {
IType[] types = ajcu.getAllTypes();
for (int i = 0; i < types.length; i++) {
IType type = types[i];
if (type instanceof AspectElement) {
aspects.add(type);
}
}
} catch (JavaModelException e) {
}
}
}
return resource.getType() == IResource.FOLDER
|| resource.getType() == IResource.PROJECT;
}
});
return aspects;
}
/**
* Error handler class for AOP XML parsing exceptions
*/
private static class AOPXMLErrorHandler extends DefaultHandler {
/**
* Throws a more detailed exception when an error occurs parsing a file.
* @param exception - the Exception input
* @throws SAXException - more detained Exception
* @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
*/
public void error(SAXParseException exception) throws SAXException {
throw new AOPXMLException(
"A problem occurred parsing aop.xml file " //$NON-NLS-1$
+ exception.getSystemId().substring(
exception.getSystemId().indexOf("file:///") + 8) //$NON-NLS-1$
+ "[" //$NON-NLS-1$
+ exception.getLineNumber()
+ "," //$NON-NLS-1$
+ exception.getColumnNumber()
+ "]" //$NON-NLS-1$
+ System.getProperty("line.separator") //$NON-NLS-1$
+ exception.getMessage().substring(
exception.getMessage().indexOf(':') + 2));
}
/**
* Throws a more detailed exception when a warning occurs while
* parsing a file
* @param exception - inout
* @throws SAXException - more detailed output
* @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
*/
public void warning(SAXParseException exception) throws SAXException {
error(exception);
}
/**
* Throws a more detailed exception when a fatal error occurs while
* parsing a file
* @param exception - input
* @throws SAXException - more detailed output
* @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
*/
public void fatalError(SAXParseException exception) throws SAXException {
error(exception);
}
}
/**
* Exception used in error handler to hold details of an XML parsing error
*/
private static class AOPXMLException extends SAXException{
private static final long serialVersionUID = 4296332843488816647L;
/**
* Constructor
* @param input - input String
*/
AOPXMLException(String input){
super(input);
}
}
}