Java tutorial
/******************************************************************************* * Copyright (c) 2005 IBM Corporation and others. * 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: * 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 java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.eclipse.ajdt.core.AJLog; import org.eclipse.ajdt.core.BuildConfig; import org.eclipse.ajdt.core.javaelements.AJCompilationUnit; import org.eclipse.ajdt.core.javaelements.AJCompilationUnitManager; import org.eclipse.ajdt.core.model.AJProjectModelFactory; import org.eclipse.core.internal.resources.Workspace; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; 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.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.ICompilationUnit; 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.JavaCore; 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-ajc.xml"; //$NON-NLS-1$ /** * Generate one aop-ajc.xml file for each source directory in the given project. * The aop-ajc.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) && root.getJavaProject().equals(project)) { 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-ajc.xml file: if (ltwConfigFile == null) { if (aspects.size() != 0) { // If there are aspects in the list // Create the META-INF folder and the aop-ajc.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); if (metainf == null || !metainf.exists()) { 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-ajc.xml file addAspectsToLTWConfigFile(false, aspects, aopFile); copyToOutputFolder(aopFile, project, root.getRawClasspathEntry()); } // Otherwise update the existing file } else { addAspectsToLTWConfigFile(true, aspects, ltwConfigFile); copyToOutputFolder(ltwConfigFile, project, root.getRawClasspathEntry()); } } } } catch (Exception e) { } } private static void copyToOutputFolder(IFile file, IJavaProject javaProject, IClasspathEntry srcEntry) throws CoreException { IPath outputPath = srcEntry.getOutputLocation(); if (outputPath == null) { outputPath = javaProject.getOutputLocation(); } outputPath = outputPath.removeFirstSegments(1).makeRelative(); IContainer outputFolder = getContainerForGivenPath(outputPath, javaProject.getProject()); IContainer srcContainer = getContainerForGivenPath(srcEntry.getPath().removeFirstSegments(1), javaProject.getProject()); if (!outputFolder.equals(srcContainer)) { IResource outputFile = outputFolder.getFile(new Path(AOP_XML_LOCATION)); if (outputFile.exists()) { AJLog.log("Deleting existing file " + outputFile);//$NON-NLS-1$ outputFile.delete(IResource.FORCE, null); } AJLog.log("Copying added file " + file);//$NON-NLS-1$ IFolder metainf = (IFolder) ((Workspace) ResourcesPlugin.getWorkspace()).newResource( new Path(outputFolder.getFullPath() + "/META-INF"), //$NON-NLS-1$ IResource.FOLDER); if (!metainf.exists()) { metainf.create(true, true, null); } file.copy(outputFile.getFullPath(), IResource.FORCE, null); outputFile.setDerived(true); outputFile.refreshLocal(IResource.DEPTH_ZERO, null); } } private static IContainer getContainerForGivenPath(IPath path, IProject project) { if (path.toOSString().equals("")) { //$NON-NLS-1$ return project; } return project.getFolder(path); } /** * 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-ajc.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-ajc.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();) { IType aspect = (IType) 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(IType 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) { return ""; } if (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<IType> getAspects(final IPackageFragmentRoot root) throws CoreException { final List<IType> aspects = new ArrayList(); final Set<IFile> includedFiles = BuildConfig.getIncludedSourceFiles(root.getJavaProject().getProject()); root.getResource().accept(new IResourceVisitor() { public boolean visit(IResource resource) { if (includedFiles.contains(resource)) { AJCompilationUnit ajcu = AJCompilationUnitManager.INSTANCE .getAJCompilationUnit((IFile) resource); if (ajcu != null) { try { IType[] types = ajcu.getAllAspects(); for (int i = 0; i < types.length; i++) { aspects.add(types[i]); } } catch (JavaModelException e) { } } else { ICompilationUnit cu = JavaCore.createCompilationUnitFrom((IFile) resource); if (cu != null) { Set<IType> types = AJProjectModelFactory.getInstance().getModelForJavaElement(cu) .aspectsForFile(cu); for (IType element : types) { aspects.add(element); } } } } 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-ajc.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); } } }