/******************************************************************************* * Copyright (c) 2006-2012 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * 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: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ package org.emftext.language.java.jamoppc; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; import org.emftext.commons.layout.LayoutPackage; import org.emftext.language.java.JavaClasspath; import org.emftext.language.java.JavaPackage; import org.emftext.language.java.resource.JavaSourceOrClassFileResourceFactoryImpl; import org.emftext.language.java.resource.java.IJavaOptions; public class JaMoPPC { protected static final ResourceSet rs = new ResourceSetImpl(); public static void main(String[] args) throws IOException { if ((args.length >= 1) && args[0].equals("--disable-layout")) { rs.getLoadOptions().put(IJavaOptions.DISABLE_LAYOUT_INFORMATION_RECORDING, Boolean.TRUE); args = Arrays.copyOfRange(args, 1, args.length); } if (args.length < 2) { printUsageAndExit(); } setUp(); File srcFolder = new File(args[0]); if (!srcFolder.exists()) { System.out.println("not found: " + args[0]); return; } JavaClasspath cp = JavaClasspath.get(rs); // register jar files for (int i = 2; i < args.length; i++) { File jarPath = new File(args[i]); if (!jarPath.exists()) { System.out.println("not found: " + args[i]); return; } System.out.println("Registering JAR " + jarPath.getCanonicalPath()); cp.registerClassifierJar(URI.createFileURI(jarPath .getCanonicalPath())); } // load all java files into resource set loadAllFilesInResourceSet(srcFolder, ".java"); if (!resolveAllProxies(0)) { System.err.println("Resolution of some Proxies failed..."); Iterator<Notifier> it = rs.getAllContents(); while (it.hasNext()) { Notifier next = it.next(); if (next instanceof EObject) { EObject o = (EObject) next; if (o.eIsProxy()) { try { it.remove(); } catch (UnsupportedOperationException e) { e.printStackTrace(); } } } } // return; } URI srcUri = URI.createFileURI(srcFolder.getCanonicalPath()); String outFileOrDir = args[1]; if (outFileOrDir.endsWith(".xmi")) { saveToSingleXMIFile(srcUri, new File(outFileOrDir)); } else { saveToFolder(srcUri, new File(outFileOrDir)); } } private static void saveToSingleXMIFile(URI srcUri, File file) throws IOException { File parentDir = file.getParentFile(); if (parentDir == null) { parentDir = new File(System.getProperty("user.dir")); } else if (!parentDir.exists()) { parentDir.mkdirs(); } URI outUri = URI.createFileURI(file.getCanonicalPath()); Resource xmiResource = rs.createResource(outUri); for (Resource javaResource : new ArrayList<Resource>(rs.getResources())) { xmiResource.getContents().addAll(javaResource.getContents()); } // save the metamodels (schemas) for dynamic loading serializeMetamodel(parentDir); saveXmiResource(xmiResource); } private static void saveToFolder(URI srcUri, File outFolder) throws IOException { List<Resource> result = new ArrayList<Resource>(); URI outUri = URI.createFileURI(outFolder.getCanonicalPath()); for (Resource javaResource : new ArrayList<Resource>(rs.getResources())) { URI srcURI = javaResource.getURI(); srcURI = rs.getURIConverter().normalize(srcURI); URI outFileURI = outUri.appendSegments( srcURI.deresolve(srcUri.appendSegment("")).segments()) .appendFileExtension("xmi"); Resource xmiResource = rs.createResource(outFileURI); xmiResource.getContents().addAll(javaResource.getContents()); result.add(xmiResource); } // save the metamodels (schemas) for dynamic loading serializeMetamodel(outFolder); for (Resource xmiResource : result) { saveXmiResource(xmiResource); } } private static void saveXmiResource(Resource xmiResource) throws IOException { Map<Object, Object> options = new HashMap<Object, Object>(); options.put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); xmiResource.save(options); } private static void printUsageAndExit() { System.out.println("JaMoPPC Usage:"); System.out.println("=============="); System.out.println(); System.out .println("To parse all files in a source folder and produce one model file per\n" + "parsed compilation unit in the target folder, use:"); System.out.println(); System.out .println(" jamoppc [--disable-layout] <source folder path> <target folder path> <jar file paths>*"); System.out.println(); System.out .println("To parse all files in a source folder and produce one XMI file\n" + "with the complete syntax graph, use:"); System.out.println(); System.out .println(" jamoppc [--disable-layout] <source folder path> <target XMI file> <jar file paths>*"); System.out.println(); System.out .println("In the latter case, the second parameter has to end in \".xmi\"."); System.out.println(); System.out.println("The --disable-layout option disables the generation of layout information."); System.out.println("If given, it must be the first argument given to JaMoPPC."); System.exit(1); } protected static void setUp() { rs.getLoadOptions().put(IJavaOptions.DISABLE_LOCATION_MAP, Boolean.TRUE); EPackage.Registry.INSTANCE.put("http://www.emftext.org/java", JavaPackage.eINSTANCE); Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put( "java", new JavaSourceOrClassFileResourceFactoryImpl()); Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put( Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()); } protected static void serializeMetamodel(File outFolder) throws IOException { URI outUri = URI.createFileURI(outFolder.getCanonicalPath()); URI javaEcoreURI = outUri.appendSegment("java.ecore"); Resource javaEcoreResource = rs.createResource(javaEcoreURI); javaEcoreResource.getContents().addAll( JavaPackage.eINSTANCE.getESubpackages()); javaEcoreResource.save(null); URI layoutEcoreURI = outUri.appendSegment("layout.ecore"); Resource layoutEcoreResource = rs.createResource(layoutEcoreURI); layoutEcoreResource.getContents().add( LayoutPackage.eINSTANCE); layoutEcoreResource.save(null); } protected static void loadAllFilesInResourceSet(File startFolder, String extension) throws IOException { for (File member : startFolder.listFiles()) { if (member.isFile()) { if (member.getName().endsWith(extension)) { System.out.println("Parsing " + member); parseResource(member); } else { System.out.println("Skipping " + member); } } if (member.isDirectory()) { if (!member.getName().startsWith(".")) { System.out.println("Recursing into " + member); loadAllFilesInResourceSet(member, extension); } else { System.out.println("Skipping " + member); } } } } protected static boolean resolveAllProxies(int resourcesProcessedBefore) { boolean failure = false; List<EObject> eobjects = new LinkedList<EObject>(); for (Iterator<Notifier> i = rs.getAllContents(); i.hasNext();) { Notifier next = i.next(); if (next instanceof EObject) { eobjects.add((EObject) next); } } int resourcesProcessed = rs.getResources().size(); if (resourcesProcessed == resourcesProcessedBefore) { return true; } System.out.println("Resolving cross-references of " + eobjects.size() + " EObjects."); int resolved = 0; int notResolved = 0; int eobjectCnt = 0; for (EObject next : eobjects) { eobjectCnt++; if (eobjectCnt % 1000 == 0) { System.out.println(eobjectCnt + "/" + eobjects.size() + " done: Resolved " + resolved + " crossrefs, " + notResolved + " crossrefs could not be resolved."); } InternalEObject nextElement = (InternalEObject) next; for (EObject crElement : nextElement.eCrossReferences()) { crElement = EcoreUtil.resolve(crElement, rs); if (crElement.eIsProxy()) { failure = true; notResolved++; System.out .println("Can not find referenced element in classpath: " + ((InternalEObject) crElement).eProxyURI()); } else { resolved++; } } } System.out.println(eobjectCnt + "/" + eobjects.size() + " done: Resolved " + resolved + " crossrefs, " + notResolved + " crossrefs could not be resolved."); //call this method again, because the resolving might have triggered loading //of additional resources that may also contain references that need to be resolved. return !failure && resolveAllProxies(resourcesProcessed); } protected static void parseResource(File file) throws IOException { loadResource(file.getCanonicalPath()); } protected static void parseResource(ZipFile file, ZipEntry entry) throws IOException { loadResource(URI.createURI("archive:file:///" + new File(".").getAbsoluteFile().toURI().getRawPath() + file.getName().replaceAll("\\\\", "/") + "!/" + entry.getName())); } protected static void loadResource(String filePath) throws IOException { loadResource(URI.createFileURI(filePath)); } protected static void loadResource(URI uri) throws IOException { rs.getResource(uri, true); } }