Java tutorial
/* * Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved. * * This program and the accompanying materials are made available * under the terms of the Eclipse Public License, Version 1.0, * which accompanies this distribution and is available at * * http://www.eclipse.org/legal/epl-v10.html * */ package net.rim.ejde.internal.packaging; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.EmptyStackException; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.Vector; import java.util.jar.JarEntry; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.rim.ejde.internal.builders.ALXBuilder; import net.rim.ejde.internal.builders.ResourceBuilder; import net.rim.ejde.internal.core.ContextManager; import net.rim.ejde.internal.core.IConstants; import net.rim.ejde.internal.core.IRIMMarker; import net.rim.ejde.internal.launching.DeploymentHelper; import net.rim.ejde.internal.model.BlackBerryProject; import net.rim.ejde.internal.model.BlackBerryProjectCoreNature; import net.rim.ejde.internal.model.BlackBerryProperties; import net.rim.ejde.internal.model.BlackBerryPropertiesFactory; import net.rim.ejde.internal.model.BlackBerrySDKInstall; import net.rim.ejde.internal.model.BlackBerryVMInstallType; import net.rim.ejde.internal.packaging.JadFile.CodEntry; import net.rim.ejde.internal.ui.consoles.PackagingConsole; import net.rim.ejde.internal.util.ImportUtils; import net.rim.ejde.internal.util.InternalPackagingUtils; import net.rim.ejde.internal.util.Messages; import net.rim.ejde.internal.util.PackageUtils; import net.rim.ejde.internal.util.PackagingUtils; import net.rim.ejde.internal.util.ProblemFactory; import net.rim.ejde.internal.util.ProjectUtils; import net.rim.ejde.internal.util.StatusFactory; import net.rim.ejde.internal.util.VMUtils; import net.rim.ejde.internal.validation.DiagnosticFactory; import net.rim.ide.OSUtils; import net.rim.ide.Project; import net.rim.ide.core.Util; import net.rim.sdk.resourceutil.ResourceParseException; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.eclipse.core.internal.resources.ResourceException; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.ToolFactory; import org.eclipse.jdt.core.util.IClassFileReader; import org.eclipse.jdt.core.util.IMethodInfo; import org.eclipse.jdt.core.util.IModifierConstants; import org.eclipse.jdt.internal.launching.JREContainer; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.LibraryLocation; import org.eclipse.osgi.util.NLS; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.ui.console.IConsole; import org.eclipse.ui.console.MessageConsoleStream; /** * This class provides methods to package a BlackBerry project. * * Usually a project has two deployment folders: * <p> * /deliverables/Standard * <p> * and * <p> * /deliverables/Web * <p> * The project is packaged into the <code>/deliverables/Standard</code> folder and all generated rapc artifacts are copied to the * <code>/deliverables/Web</code> folder. However, if the cod file is a zipped parent cod file, we un-zip it and copy all the * sibling cod files in the the <code>/deliverables/Web</code> folder. */ public class PackagingManager { static final Logger _log = Logger.getLogger(PackagingManager.class); static final int MAX_COMMAND_ELEMENTS = 30; public static final String COMPRESS_RESOURCE_OPTION = "-cr"; public static final String CONVERT_PNG_RAPC_OPTION = "-convertpng"; public static final String VERBOSE_RAPC_OPTION = "-verbose"; public static final int MIDLET_JAR = 0x0001; public static final int EVISCERATED_JAR = 0x0002; private Vector<String> _compileOptions; private BlackBerryProject _bbProject; private List<String> _rapcCommandsHead; private List<String> _rapcCommands; private Vector<String> _sourceRoots; private Vector<String> _protectionOptions; private Vector<ImportedJar> _imports; private Vector<String> _otherFiles; private Vector<String> _outputFolders; private MessageConsoleStream _consoleOutputStream; private boolean writeToFile; private PackagingManager(BlackBerryProject bbProject) { _bbProject = bbProject; _compileOptions = new Vector<String>(); _sourceRoots = new Vector<String>(); _imports = new Vector<ImportedJar>(); _otherFiles = new Vector<String>(); _protectionOptions = new Vector<String>(); _outputFolders = new Vector<String>(); _rapcCommandsHead = new ArrayList<String>(); _rapcCommands = new ArrayList<String>(); // Grab and activate a console to redirect build output to. PackagingConsole packagingConsole = PackagingConsole.getInstance(); ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[] { packagingConsole }); _consoleOutputStream = packagingConsole.newMessageStream(); } /** * This is a help method to package a BlackBerry project. * * @param project * A BlackBerry project * * @throws CoreException */ static public void packageProject(BlackBerryProject project) throws CoreException { PackagingManager packagingManage = new PackagingManager(project); packagingManage.internalPackageProject(); } /** * This is a help method to package a BlackBerry project. * * @param project * A BlackBerry project * * @throws CoreException */ static public void generateALXForProject(BlackBerryProject project) throws CoreException { PackagingManager packagingManage = new PackagingManager(project); // if the deliverable folder does not exist, create it IProject eclipseProject = project.getProject(); IPath outputFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(project)); try { ImportUtils.createFolders(eclipseProject, outputFolderPath, IResource.DERIVED); } catch (CoreException e) { throw new ResourceException(DiagnosticFactory.CREATE_FOLDER_ERR_ID, project.getMetaFileHandler().getProjectRelativePath(), NLS.bind(Messages.PackagingManager_PACKAGING_CANNOT_CREATE_FOLDER_MSG, outputFolderPath), e); } packagingManage.internalGenerateALX(); } private void internalGenerateALX() throws CoreException { generateALX(); IResource outputFolder = _bbProject.getProject() .findMember(new Path(PackagingUtils.getRelativeAlxFileOutputFolder(_bbProject))); outputFolder.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor()); } private void internalPackageProject() throws CoreException { final BlackBerrySDKInstall bbVM = PackagingUtils.getBBSDKInstall(_bbProject.getJavaProject()); if (bbVM == null) { String msg = NLS.bind(Messages.PackagingManager_PACKAGING_NO_BB_JRE_MSG, _bbProject.getProject().getName()); reportProblem(_bbProject.getProject(), -1, 0, 0, msg, Problem.ERROR); _log.error(msg); return; } // clean the deployment folders try { PackagingUtils.cleanProjectOutputFolder(_bbProject); } catch (CoreException e) { _log.error(e); } IProject eclipseProject = _bbProject.getProject(); // if the deliverable folder does not exist, create it IPath outputFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(_bbProject)); try { ImportUtils.createFolders(eclipseProject, outputFolderPath, IResource.DERIVED); } catch (CoreException e) { throw new ResourceException(DiagnosticFactory.CREATE_FOLDER_ERR_ID, _bbProject.getMetaFileHandler().getProjectRelativePath(), NLS.bind(Messages.PackagingManager_PACKAGING_CANNOT_CREATE_FOLDER_MSG, outputFolderPath), e); } // calculate rapc commands calculateRAPCCommand(); // check if the project should be packaged if (!shouldPackage()) { return; } // run rapc command runRapcCommand(); // post packaging steps postPackagingProcess(_bbProject); } private void postPackagingProcess(BlackBerryProject BBProject) throws CoreException { IPath outputFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(_bbProject)); IResource outputFolder = BBProject.getProject().findMember(outputFolderPath); // copy the cod files of dependency projects to the deployment folders copyDependencyDeploymentFiles(); // Refresh to show new resources outputFolder.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); // Generate ALX File if (BBProject.getProperties()._packaging.getGenerateALXFile().booleanValue()) { generateALX(); } } /** * Copies the deployment files of the dependent projects to the corresponding deployment folders. * * @throws CoreException */ private void copyDependencyDeploymentFiles() throws CoreException { IPath standardSrcFolderPath, standardDstFolderPath; String outputFileName; IPath absoluteStandardSrcFolderPath, absoluteStandardDstFolderPath; List<CodEntry> codEntries = new ArrayList<CodEntry>(); String mainVersion = PackagingUtils.getVMOutputFolderName(_bbProject); for (BlackBerryProject dependentProj : ProjectUtils.getAllReferencedProjects(_bbProject)) { JadFile jadFile = null; try { jadFile = new JadFile(getJadFilePath(dependentProj).toFile()); jadFile.parseJadFile(); String dependencyVersion = PackagingUtils.getVMOutputFolderName(dependentProj); if (!mainVersion.equals(dependencyVersion)) { // if the BB JRE of the main project is different than the dependency projects, need to calculate the cod // relative paths for (CodEntry entry : jadFile.getCodeEntries()) { entry.setUrl(".." + File.separator + dependencyVersion + File.separator + entry.getUrl()); } } codEntries.addAll(jadFile.getCodeEntries()); } catch (IOException e) { _log.error(e); } // get the standard deployment folder of the dependent project standardDstFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(dependentProj)); // get the standard corresponding deployment folder of the main project absoluteStandardDstFolderPath = _bbProject.getProject().getLocation().append(standardDstFolderPath); // make sure the destination folder is created try { ImportUtils.createFolders(_bbProject.getProject(), standardDstFolderPath, IResource.DERIVED); } catch (CoreException e) { throw new ResourceException(DiagnosticFactory.CREATE_FOLDER_ERR_ID, _bbProject.getMetaFileHandler().getProjectRelativePath(), NLS.bind(Messages.PackagingManager_PACKAGING_CANNOT_CREATE_FOLDER_MSG, standardDstFolderPath), e); } // copy deployment files in standard folder standardSrcFolderPath = new Path(PackagingUtils.getRelativeStandardOutputFolder(dependentProj)); absoluteStandardSrcFolderPath = dependentProj.getProject().getLocation().append(standardSrcFolderPath); outputFileName = dependentProj.getProperties()._packaging.getOutputFileName(); File[] outputFiles = absoluteStandardSrcFolderPath.toFile() .listFiles(new DeploymentFileNameFilter(outputFileName)); _log.trace( "Dependent project " + dependentProj.getElementName() + " copy folder: " + standardSrcFolderPath + " --> " + _bbProject.getElementName() + " / " + standardDstFolderPath); for (File file : outputFiles) { if (file.exists()) { DeploymentHelper.executeCopy(file, absoluteStandardDstFolderPath.append(file.getName()).toFile()); } } // refresh the standard folder IFolder folder = _bbProject.getProject().getFolder(standardDstFolderPath); folder.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor()); } if (codEntries.size() != 0) { writeCodEntry(codEntries); } } private void writeCodEntry(List<CodEntry> codEntries) { File file = getJadFilePath(_bbProject).toFile(); BufferedWriter writer = null; List<String> list = new ArrayList<String>(); try { JadFile jadFile = new JadFile(file); jadFile.parseJadFile(); // add dependency cod entries jadFile.addCodEntries(codEntries); list = jadFile.getOtherProperties(); for (CodEntry entry : jadFile.getCodeEntries()) { list.add(entry.getCodURLPropertyLine()); list.add(entry.getCodSizePropertyLine()); list.add(entry.getCodCreationgTimePropertyLine()); list.add(entry.getCodShaPropertyLine()); } IPath destFilePath = getJadFilePath(_bbProject); destFilePath = destFilePath.removeLastSegments(1); destFilePath = destFilePath.append(_bbProject.getProperties().getPackaging().getOutputFileName() + IConstants.FULL_JAD_FILE_SUFFIX + IConstants.JAD_FILE_EXTENSION_WITH_DOT); writer = new BufferedWriter(new FileWriter(destFilePath.toFile())); for (int i = 0; i < list.size(); i++) { writer.write(list.get(i) + "\r\n"); } } catch (Exception e) { _log.error(e); } finally { try { if (writer != null) { writer.close(); } } catch (IOException e) { _log.error(e); } } } public static final void copyInputStream(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) >= 0) out.write(buffer, 0, len); in.close(); out.close(); } class DeploymentFileNameFilter implements FilenameFilter { String _outputFileName; boolean _excludeCodFile; public DeploymentFileNameFilter(String outputFileName) { _outputFileName = outputFileName; } public DeploymentFileNameFilter(String outputFileName, boolean excludeCod) { _outputFileName = outputFileName; _excludeCodFile = excludeCod; } @Override public boolean accept(File dir, String name) { if (name.startsWith(_outputFileName)) { if (_excludeCodFile) { if (!name.endsWith(IConstants.COD_FILE_EXTENSION_WITH_DOT)) { return true; } } else { return true; } } return false; } } private void generateALX() throws CoreException { BlackBerryProperties properties = _bbProject.getProperties(); String targetDir = PackagingUtils.getRelativeAlxFileOutputFolder(_bbProject); String targetFolderLocation; if (targetDir == null || targetDir.equals(IConstants.EMPTY_STRING)) { targetFolderLocation = _bbProject.getProject().getLocation().toOSString(); } else { targetFolderLocation = _bbProject.getProject().getFolder(new Path(targetDir)).getLocation() .toOSString(); } String filename = properties._packaging.getOutputFileName(); String alxName = targetFolderLocation + File.separator + filename; try { ALXBuilder.Alx alx = ALXBuilder.generateAlx(null, _bbProject); ALXBuilder.write(alxName, alx); } catch (ResourceParseException rpe) { throw new CoreException(new Status(IStatus.ERROR, ContextManager.PLUGIN_ID, rpe.getMessage())); } catch (FileNotFoundException fnfe) { throw new CoreException(new Status(IStatus.ERROR, ContextManager.PLUGIN_ID, fnfe.getMessage())); } // refresh the alx file IFile alxFile = _bbProject.getProject().getFolder(new Path(targetDir)) .getFile(filename + IConstants.ALX_FILE_EXTENSION_WITH_DOT); alxFile.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); } private void runRapcCommand() throws CoreException { try { File workDir = _bbProject.getProject().getLocation().toFile(); if (writeToFile) { File outputFile = null; String outputFileName = _bbProject.getProject().getName() + ".files"; outputFile = new File(workDir, outputFileName); _rapcCommandsHead.add("@" + outputFileName); flushToFile(outputFile); } else { _rapcCommandsHead.addAll(_rapcCommands); } String command = getStringCommand(_rapcCommandsHead); _log.trace("Execute rapc command: " + command + "; Working Directory: " + workDir.getPath()); ProcessBuilder rapcBuilder = new ProcessBuilder(_rapcCommandsHead); String javaHome = System.getenv("JAVA_HOME"); if (javaHome != null) { Map<String, String> env = rapcBuilder.environment(); String pathName = "Path"; for (String s : env.keySet()) { if (s.equalsIgnoreCase("Path")) pathName = s; } String path = env.get(pathName); path = path == null ? javaHome : (path + File.pathSeparator + javaHome); path = path + File.pathSeparator + javaHome + File.separator + "bin"; env.put(pathName, path); _log.trace("PATH=" + path); } rapcBuilder.directory(workDir); rapcBuilder.redirectErrorStream(true); long startTime = System.currentTimeMillis(); _consoleOutputStream.println( NLS.bind(Messages.PackagingManager_PACKAGING_PROJECT_MSG, _bbProject.getProject().getName())); _consoleOutputStream.println(command); Process process = rapcBuilder.start(); InputStream inStream = process.getInputStream(); InputStreamHandler inputHandler = new InputStreamHandler(_bbProject.getProject(), _consoleOutputStream, inStream); inputHandler.start(); int result = process.waitFor(); inputHandler.join(); float spendTime = ((float) (System.currentTimeMillis() - startTime)) / 1000; if (result == 0) { _consoleOutputStream.println(NLS.bind(Messages.PackagingManager_PACKAGING_SUCCEED_MSG, new String[] { _bbProject.getProject().getName(), String.valueOf(spendTime) })); } else { _consoleOutputStream.println(NLS.bind(Messages.PackagingManager_PACKAGING_FAILED_MSG, new String[] { _bbProject.getProject().getName(), String.valueOf(spendTime) })); } } catch (IOException e) { throw new CoreException(StatusFactory.createErrorStatus(e.getMessage())); } catch (InterruptedException e) { throw new CoreException(StatusFactory.createErrorStatus(e.getMessage())); } } private void flushToFile(File file) throws IOException { FileOutputStream fout = null; PrintStream indirect = null; try { ByteArrayOutputStream bout = new ByteArrayOutputStream(); indirect = new PrintStream(bout, false, "UTF-8"); for (int i = 0; i < _rapcCommands.size(); i++) { indirect.println(_rapcCommands.get(i)); } indirect.close(); byte[] newBytes = bout.toByteArray(); // either old file doesn't exist or it isn't the same // write out the new data fout = new FileOutputStream(file); fout.write(newBytes); fout.close(); } finally { if (indirect != null) { indirect.close(); } if (fout != null) { fout.close(); } } } private String getStringCommand(List<String> commands) { StringBuffer command = new StringBuffer(); for (int i = 0; i < commands.size(); i++) { if (i != 0) { command.append(IConstants.ONE_BLANK_STRING); } System.out.println(commands.get(i)); command.append(commands.get(i)); } return command.toString(); } private void calculateRAPCCommand() throws CoreException { // calculate rapc commands SourcerootVisitor visitor = new SourcerootVisitor(); _bbProject.getProject().accept(visitor); // get customized jad and rapc files String custjad = PackagingUtils.getCustomJadFile(_bbProject); if (custjad != null) { _otherFiles.add(custjad); } String custrapc = PackagingUtils.getCustomRapcFile(_bbProject); if (custrapc != null) { _otherFiles.add(custrapc); } // get imported jars (project level and workspace level) _imports = getCompileImports(_bbProject); // check if there is any exported midlet jar // TODO: Try invoking rapc.jar in Windows instead of rapc.exe if (OSUtils.isWindows()) { // add path of rapc.exe _rapcCommandsHead.add(getRAPCPath()); } else { _rapcCommandsHead.add("java"); _rapcCommandsHead.add("-jar"); // add path of rapc.jar _rapcCommandsHead.add(getRAPCPath()); } // get compile options _compileOptions = getCompileOptions(); // add compile options if (_compileOptions.size() > 0) { _rapcCommandsHead.addAll(_compileOptions); } // get source roots _sourceRoots = visitor.getSourceRoots(_bbProject.getProject()); // add source roots // TODO: Added for preverifier and do more investigation and // see whether we can eliminate this option or not. if (!OSUtils.isWindows()) { String binDir = getRAPCPath().replace("rapc.jar", ""); String exepath = "-exepath=" + binDir; _rapcCommandsHead.add(exepath); } StringBuffer rapcComandBuffer = new StringBuffer(); if (_sourceRoots.size() > 0) { rapcComandBuffer.append("-sourceroot="); rapcComandBuffer.append(composeString(_sourceRoots, File.pathSeparator)); _rapcCommandsHead.add(rapcComandBuffer.toString()); } // get protection options _protectionOptions = getProtectionOptions(false); // add imports rapcComandBuffer = new StringBuffer(); writeToFile = (_imports.size() + _protectionOptions.size()) > MAX_COMMAND_ELEMENTS; if (_imports.size() > 0) { if (writeToFile) { for (int i = 0; i < _imports.size(); i++) { _rapcCommands.add("-import=" + _imports.get(i).toString()); } } else { rapcComandBuffer.append("-import="); rapcComandBuffer.append(composeImportsString(_imports, File.pathSeparator, false)); _rapcCommands.add(rapcComandBuffer.toString()); } } // add protection options if (_protectionOptions.size() > 0) { _rapcCommands.addAll(_protectionOptions); } // add exported jar files for (int i = 0; i < _imports.size(); i++) { if (_imports.get(i).isExported()) { _rapcCommands.add(_imports.get(i).getPath()); } } prepareDescriptor(); // add other files _rapcCommands.addAll(_otherFiles); // get output folders getOutputFolder(); // add output folders if (_outputFolders.size() > 0) { _rapcCommands.addAll(_outputFolders); } } private void prepareDescriptor() throws CoreException { boolean found = false; IPath outputFilePath = PackagingUtils.getAbsoluteStandardOutputFilePath(_bbProject).removeLastSegments(1); int i; for (i = 0; i < _otherFiles.size(); i++) { String sl = _otherFiles.get(i).toLowerCase(); if (sl.endsWith(IConstants.RAPC_FILE_EXTENSION_WITH_DOT) || sl.endsWith(IConstants.JAD_FILE_EXTENSION_WITH_DOT)) { File f = new File(_otherFiles.get(i)); String distFileName = _bbProject.getProperties().getPackaging().getOutputFileName(); if (sl.endsWith(IConstants.RAPC_FILE_EXTENSION_WITH_DOT)) { distFileName += IConstants.RAPC_FILE_EXTENSION_WITH_DOT; found = true; } else { distFileName += IConstants.JAD_FILE_EXTENSION_WITH_DOT; } File f2 = outputFilePath.append(distFileName).toFile(); DeploymentHelper.executeCopy(f, f2); _otherFiles.set(i, f2.getAbsolutePath()); } } if (!found) { // generate rapc file RAPCFile rapcFile = new RAPCFile(_bbProject); rapcFile.loadContent(); rapcFile.flushToFile(); _otherFiles.addElement(RAPCFile.getRelativeRapcFilePath(_bbProject).toOSString()); } } private IPath getJadFilePath(BlackBerryProject bbProject) { IPath outputFilePath = PackagingUtils.getAbsoluteStandardOutputFilePath(bbProject).removeLastSegments(1); String jadFileName = bbProject.getProperties().getPackaging().getOutputFileName(); jadFileName += IConstants.JAD_FILE_EXTENSION_WITH_DOT; return outputFilePath.append(jadFileName); } /** * Checks if the project should be packaged. * * @return */ private boolean shouldPackage() { int MidletJarNumber = 0; for (ImportedJar jar : _imports) { if (jar.isExported()) { if (jar.isMidletJar()) { MidletJarNumber++; if (MidletJarNumber != 1) { reportProblem(_bbProject.getProject(), 0, 0, 0, Messages.PackagingManager_MIDLET_JAR_ERROR_MSG1, Problem.ERROR); return false; } Vector<String> jadFiles = getJadFiles(_otherFiles); if (jadFiles.size() == 0) { reportProblem(_bbProject.getProject(), 0, 0, 0, Messages.PackagingManager_MIDLET_JAR_ERROR_MSG2, Problem.WARNING); } else if (jadFiles.size() > 1) { reportProblem(_bbProject.getProject(), 0, 0, 0, Messages.PackagingManager_MIDLET_JAR_ERROR_MSG3, Problem.ERROR); return false; } } else if ((jar.getType() & EVISCERATED_JAR) > 0) { reportProblem(_bbProject.getProject(), 0, 0, 0, NLS.bind(Messages.PackagingManager_MIDLET_JAR_ERROR_MSG4, jar._path), Problem.ERROR); return false; } } } return true; } private Vector<String> getJadFiles(Vector<String> files) { Vector<String> jadFiles = new Vector<String>(); for (String file : files) { if (file.endsWith(IConstants.JAD_FILE_EXTENSION_WITH_DOT)) { jadFiles.add(file); } } return jadFiles; } private void getOutputFolder() { Set<IPath> outputFolderSet = ImportUtils.getOutputPathSet(_bbProject); IPath javaOutRelPath; for (IPath path : outputFolderSet) { // get rid of the first project segment javaOutRelPath = path.removeFirstSegments(1).makeRelative(); IFolder folder = _bbProject.getProject().getFolder(javaOutRelPath); if (folder == null || !folder.exists()) { continue; } if (folder.isLinked()) { _outputFolders.add(folder.getLocation().toOSString()); } else { _outputFolders.add(_bbProject.getProject().getLocation().append(javaOutRelPath).toOSString()); } } } private String composeImportsString(Vector<ImportedJar> vector, String separator, boolean exported) { StringBuffer buffer = new StringBuffer(); if (vector == null) { return buffer.toString(); } boolean first = true; for (int i = 0; i < vector.size(); i++) { if (vector.get(i).isExported() != exported) { continue; } if (first) { buffer.append(vector.get(i).toString()); first = false; } else { buffer.append(separator); buffer.append(vector.get(i).toString()); } } return buffer.toString(); } private String composeString(Vector<String> vector, String separator) { StringBuffer buffer = new StringBuffer(); if (vector == null) { return buffer.toString(); } for (int i = 0; i < vector.size(); i++) { if (i == 0) { buffer.append(vector.get(i).toString()); } else { buffer.append(separator); buffer.append(vector.get(i).toString()); } } return buffer.toString(); } static private boolean existingJar(Vector<ImportedJar> vec, ImportedJar jar) { if (jar == null) { return false; } for (int i = 0; i < vec.size(); i++) { if (vec.get(i).getPath().equalsIgnoreCase(jar.getPath())) { return true; } } return false; } /** * Gets paths of all imported jars (project level and workspace level) and jars of dependency projects. * * @return * @throws CoreException */ static public Vector<ImportedJar> getCompileImports(IJavaProject jProject) throws CoreException { Vector<ImportedJar> vector = new Vector<ImportedJar>(); IClasspathEntry[] entries = jProject.getRawClasspath(); if (entries != null && entries.length > 0) { getCompileImportsRecusively(entries, jProject, vector, true); } return vector; } static private void getCompileImportsRecusively(IClasspathEntry[] entries, IJavaProject jProject, Vector<ImportedJar> imports, boolean isMainProject) throws CoreException { if (imports == null) { imports = new Vector<ImportedJar>(); } // Workspace imports; if there aren't any specified, default to // using the runtime libraries. IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); // String jarPathString; try { BlackBerryProperties properties = null; boolean needAddBBJar = false; IPath jarPath = null; ImportedJar importedJar = null; for (IClasspathEntry entry : entries) { switch (entry.getEntryKind()) { case IClasspathEntry.CPE_CONTAINER: { // libraries IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), jProject.getJavaProject()); if (container == null) { continue; } IVMInstall containerVM; if (!(container instanceof JREContainer)) { // We need to verify the type of the container because the path of Maven container only has one // segment and JavaRuntime.getVMInstall(IPath) return the default VM install if the entry path has one // segment. containerVM = null; } else { containerVM = JavaRuntime.getVMInstall(entry.getPath()); } try { if (containerVM != null) { if (containerVM.getVMInstallType().getId().equals(BlackBerryVMInstallType.VM_ID)) { if (isMainProject) { // Add jars to a list IClasspathEntry[] classpathEntries = container.getClasspathEntries(); if (classpathEntries != null && classpathEntries.length > 0) { getCompileImportsRecusively(classpathEntries, jProject, imports, false); } } } else { if (!jProject.getProject().hasNature(BlackBerryProjectCoreNature.NATURE_ID)) { needAddBBJar = true; continue; } } } else { // Add jars to a list IClasspathEntry[] classpathEntries = container.getClasspathEntries(); if (classpathEntries != null && classpathEntries.length > 0) { getCompileImportsRecusively(classpathEntries, jProject, imports, false); } } } catch (CoreException e) { _log.error(e.getMessage()); continue; } break; } case IClasspathEntry.CPE_LIBRARY: { // imported jars jarPath = PackageUtils.getAbsoluteEntryPath(entry); // the jar path can be null if the jar file does not exist if (jarPath == null) { throw new CoreException(StatusFactory.createErrorStatus( NLS.bind(Messages.PackagingManager_Entry_Not_Found_MSG, entry.getPath()))); } if (jarPath.lastSegment().equals(IConstants.RIM_API_JAR) && needAddBBJar) { needAddBBJar = false; } importedJar = null; if (PackagingUtils.getPackagExportedJar()) { if (entry.isExported()) { if (isMainProject) { // if the exported jar is not in the main project but a dependent project, the classes it // contains are packaged into the dependent project jar. We don't add it to classpath. importedJar = new ImportedJar(jarPath.toOSString(), true, getJarFileType(jarPath.toFile())); } } else { importedJar = new ImportedJar(jarPath.toOSString(), false, getJarFileType(jarPath.toFile())); } } else { importedJar = new ImportedJar(jarPath.toOSString(), false, getJarFileType(jarPath.toFile())); } if (importedJar != null && !existingJar(imports, importedJar)) { imports.add(importedJar); } break; } case IClasspathEntry.CPE_PROJECT: { // dependency projects IProject project = workspaceRoot.getProject(entry.getPath().toString()); IJavaProject javaProject = JavaCore.create(project); try { if (project.hasNature(BlackBerryProjectCoreNature.NATURE_ID)) { properties = ContextManager.PLUGIN.getBBProperties(javaProject.getProject().getName(), false); if (properties == null) { _log.error("BlackBerry properties is null"); break; } } else { properties = BlackBerryPropertiesFactory.createBlackBerryProperties(javaProject); } } catch (CoreException e) { _log.error(e.getMessage()); continue; } if (PackagingManager.getProjectTypeID(properties._application.getType()) == Project.LIBRARY) { IPath absoluteJarPath = PackagingUtils .getAbsoluteStandardOutputFilePath(new BlackBerryProject(javaProject, properties)); File jarFile = new File( absoluteJarPath.toOSString() + IConstants.DOT_MARK + IConstants.JAR_EXTENSION); importedJar = new ImportedJar(jarFile.getAbsolutePath(), false, getJarFileType(jarFile)); if (!existingJar(imports, importedJar)) { imports.add(importedJar); } IClasspathEntry[] subEntries = javaProject.getRawClasspath(); if (subEntries != null && subEntries.length > 0) { getCompileImportsRecusively(subEntries, javaProject, imports, false); } } break; } case IClasspathEntry.CPE_VARIABLE: { // variables String e = entry.getPath().toString(); int index = e.indexOf('/'); if (index == -1) { index = e.indexOf('\\'); } String variable = e; IPath cpvar = JavaCore.getClasspathVariable(variable); if (cpvar == null) { String msg = NLS.bind(Messages.PackagingManager_Variable_Not_Defined_MSG, variable); throw new CoreException(StatusFactory.createErrorStatus(msg)); } if (cpvar.lastSegment().equals(IConstants.RIM_API_JAR) && needAddBBJar) { needAddBBJar = false; } // TODO RAPC does not support a class folder. We may support it later on if (cpvar.lastSegment().endsWith("." + IConstants.JAR_EXTENSION)) { importedJar = new ImportedJar(cpvar.toOSString(), false, getJarFileType(cpvar.toFile())); if (!existingJar(imports, importedJar)) { imports.add(importedJar); } } break; } } } if (needAddBBJar && isMainProject) { // insert the default BB jre lib if needed IVMInstall bbVM = VMUtils.getDefaultBBVM(); if (bbVM != null) { LibraryLocation[] libLocations = bbVM.getLibraryLocations(); if (libLocations != null) { for (LibraryLocation location : libLocations) { importedJar = new ImportedJar(location.getSystemLibraryPath().toOSString(), false, getJarFileType(location.getSystemLibraryPath().toFile())); if (!existingJar(imports, importedJar)) { imports.add(importedJar); } } } } } } catch (JavaModelException e) { _log.error(e.getMessage()); } } public static String quoteFile(String fileName) { return IConstants.DOUBLE_QUOTE + fileName + IConstants.DOUBLE_QUOTE; } public static int getProjectTypeID(String type) { if (type.trim().equalsIgnoreCase(BlackBerryProject.CLDC_APPLICATION)) { return Project.CLDC_APPLICATION; } if (type.trim().equalsIgnoreCase(BlackBerryProject.MIDLET)) { return Project.MIDLET; } if (type.trim().equalsIgnoreCase(BlackBerryProject.LIBRARY)) { return Project.LIBRARY; } return -1; } private String getRAPCPath() { String rapcPath = IConstants.EMPTY_STRING; try { IVMInstall vm = null; if (_bbProject.getProject().hasNature(BlackBerryProjectCoreNature.NATURE_ID)) { vm = JavaRuntime.getVMInstall(_bbProject); } else { // for java proejct, we use the default BB jre vm = VMUtils.getDefaultBBVM(); } if (vm != null) { File vmLocation = vm.getInstallLocation(); IPath vmPath = new Path(vmLocation.getPath()); vmPath = vmPath.append("bin"); if (OSUtils.isWindows()) { vmPath = vmPath.append("rapc.exe"); } else { // Make sure preverify is in executable state File f = null; if ((f = new File(vmPath + File.separator + IConstants.PREVERIFY_FILE_NAME)).exists()) { if (!f.canExecute()) { f.setExecutable(true); } } // invoke rapc.jar instead of rapc.exe vmPath = vmPath.append("rapc.jar"); } rapcPath = vmPath.toOSString(); } else { throw ProblemFactory.create_VM_MISSING_exception(_bbProject.getElementName()); } } catch (CoreException e) { _log.error("getRapcPath: " + e.getMessage()); } return rapcPath; } private Vector<String> getCompileOptions() { Vector<String> options = new Vector<String>(); BlackBerryProperties properties = _bbProject.getProperties(); // TODO java home // get options from the compile section if (properties._compile.getCompressResources().booleanValue()) { options.add(COMPRESS_RESOURCE_OPTION); } if (properties._compile.getConvertImages().booleanValue()) { options.add(CONVERT_PNG_RAPC_OPTION); } if (!properties._compile.getCreateWarningForNoExportedRoutine().booleanValue() || !properties._application.getType().equals(BlackBerryProject.CLDC_APPLICATION)) { options.add(Project.NO_MAIN_RAPC_OPTION); } if (!properties._compile.getOutputCompilerMessages().booleanValue()) { options.add(Project.QUIET_RAPC_OPTION); } if (!StringUtils.isBlank(properties._compile.getAliasList()) && properties._application.getType().equals(BlackBerryProject.LIBRARY)) { options.add(Project.ALIAS_RAPC_OPTION + properties._compile.getAliasList()); } // add other options InternalPackagingUtils.addOtherOptions(options, properties); // add codename int projectType = getProjectTypeID(properties._application.getType()); String outputFileName = PackagingUtils.getRelativeStandardOutputFilePath(_bbProject).toOSString(); if (projectType == Project.LIBRARY) { options.addElement("library=" + outputFileName); } else { options.addElement("codename=" + outputFileName); } if (projectType == Project.MIDLET) { options.addElement("-midlet"); } return options; } /** * Checks if a jar file is a MidletJar created by rapc. * * @param f * @return */ static public int getJarFileType(File f) { int type = 0x0; if (!f.exists()) { return type; } java.util.jar.JarFile jar = null; try { jar = new java.util.jar.JarFile(f, false); java.util.jar.Manifest manifest = jar.getManifest(); if (manifest != null) { java.util.jar.Attributes attributes = manifest.getMainAttributes(); String profile = attributes.getValue("MicroEdition-Profile"); if (profile != null) { if ("MIDP-1.0".equals(profile) || "MIDP-2.0".equals(profile)) { type = type | MIDLET_JAR; } } } Enumeration<JarEntry> entries = jar.entries(); JarEntry entry; String entryName; InputStream is = null; IClassFileReader classFileReader = null; // check the attribute of the class files in the jar file for (; entries.hasMoreElements();) { entry = entries.nextElement(); entryName = entry.getName(); if (entryName.endsWith(IConstants.CLASS_FILE_EXTENSION_WITH_DOT)) { is = jar.getInputStream(entry); classFileReader = ToolFactory.createDefaultClassFileReader(is, IClassFileReader.ALL); if (isEvisceratedClass(classFileReader)) { type = type | EVISCERATED_JAR; break; } } } } catch (IOException e) { _log.error(e.getMessage()); } finally { try { if (jar != null) { jar.close(); } } catch (IOException e) { _log.error(e.getMessage()); } } return type; } /** * Verify if the given <code>classFileReader</code> has code attributes. * * @param classFileReader * @return */ static private boolean isEvisceratedClass(IClassFileReader classFileReader) { // ignore interface classes if (!classFileReader.isClass()) { return false; } IMethodInfo[] methodInfos = classFileReader.getMethodInfos(); if (methodInfos == null) { return false; } for (int i = 0; i < methodInfos.length; i++) { // Ignore <init>, <clinit> and abstract methods if ("<init>".equalsIgnoreCase(String.valueOf(methodInfos[i].getName())) || methodInfos[i].isClinit() || (methodInfos[i].getAccessFlags() & IModifierConstants.ACC_ABSTRACT) != 0) { continue; } if (methodInfos[i].getCodeAttribute() == null) { return true; } } return false; } public static void reportProblem(IResource resource, int line, int start, int end, String msg, int level) { reportProblem(resource, IRIMMarker.PACKAGING_PROBLEM, line, start, end, msg, level); } public static void reportProblem(IResource resource, String type, int line, int start, int end, String msg, int level) { try { IMarker m = resource.createMarker(type); m.setAttribute(IMarker.LINE_NUMBER, line); m.setAttribute(IMarker.MESSAGE, msg); m.setAttribute(IMarker.CHAR_START, start); m.setAttribute(IMarker.CHAR_END, end); switch (level) { case Problem.ERROR: m.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); m.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); break; case Problem.WARNING: m.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_NORMAL); m.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING); break; case Problem.INFO: default: m.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_LOW); m.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO); break; } } catch (CoreException e) { _log.error(e.getMessage(), e); } } private Vector<String> getProtectionOptions(boolean forMakefile) { Vector<String> v = new Vector<String>(); Hashtable<String, String> classProtection, packageProtection; classProtection = _bbProject.getProperties()._hiddenProperties.getClassProtection(); packageProtection = _bbProject.getProperties()._hiddenProperties.getPackageProtection(); Object keys[] = packageProtection.keySet().toArray(); for (int i = 0; i < keys.length; ++i) { v.addElement("package:" + Util.doubleDollar(keys[i].toString()) + "=" + stripPath(packageProtection.get(keys[i]))); } keys = classProtection.keySet().toArray(); for (int i = 0; i < keys.length; ++i) { if (forMakefile) { v.addElement("class:" + Util.doubleDollar(keys[i].toString()) + "=" + stripPath(classProtection.get(keys[i]))); } else { // When we are not creating a makefile don't add double $$ to rapc cmd line v.addElement("class:" + keys[i].toString() + "=" + stripPath(classProtection.get(keys[i]))); } } return v; } private String stripPath(Object f) { return new File(f.toString()).getName(); } private class SourcerootVisitor implements IResourceVisitor { Set<String> _resourceRootSet; public SourcerootVisitor() { _resourceRootSet = new HashSet<String>(); } public boolean visit(IResource resource) throws CoreException { if (!(resource instanceof IFile)) { return shouldBeSourceRoot(resource); } String extension = resource.getFileExtension(); if (extension != null) { if (extension.equalsIgnoreCase(IConstants.JAVA_EXTENSION)) { String sourceRoot = calculateSourceRoot(resource.getLocation().toFile()); if (sourceRoot != null) { _resourceRootSet.add(sourceRoot); } } } return false; } private String calculateSourceRoot(File javaFile) { String packagename = PackageUtils.getJavaFilePackageID(javaFile); packagename = packagename.replace(IConstants.DOT_CHAR, IConstants.BACK_SLASH_CHAR); IPath absolutePath = new Path(javaFile.getPath()); IPath packageAndFileNamPath = null; if (packagename.trim().equals(IConstants.EMPTY_STRING)) { packageAndFileNamPath = new Path(javaFile.getName()); } else { packageAndFileNamPath = new Path(packagename); packageAndFileNamPath = packageAndFileNamPath.append(new Path(javaFile.getName())); } int differentSegNumber = absolutePath.segmentCount() - packageAndFileNamPath.segmentCount(); if (differentSegNumber >= 0) { IPath actualPackageAndFileNamPath = absolutePath.removeFirstSegments(differentSegNumber); if (actualPackageAndFileNamPath .matchingFirstSegments(packageAndFileNamPath) == packageAndFileNamPath.segmentCount()) { return absolutePath.removeLastSegments(packageAndFileNamPath.segmentCount()).toOSString(); } } _log.debug("Java file [" + javaFile.getPath() + "] is not in the right package."); //$NON-NLS-1$ //$NON-NLS-2$ return null; } public Vector<String> getSourceRoots(IProject proj) { Vector<String> roots = new Vector<String>(); roots.addAll(_resourceRootSet); try { if (proj.hasNature(JavaCore.NATURE_ID)) { IJavaProject jproj = JavaCore.create(proj); IClasspathEntry[] clpentrs = jproj.getResolvedClasspath(true); IWorkspaceRoot workspaceRoot = proj.getWorkspace().getRoot(); for (IClasspathEntry clpentry : clpentrs) { if ((clpentry.getEntryKind() == IClasspathEntry.CPE_SOURCE) && !ImportUtils.getImportPref(ResourceBuilder.LOCALE_INTERFACES_FOLDER_NAME) .equals(clpentry.getPath().lastSegment())) { // Try to resolve the source container IResource resource = workspaceRoot.findMember(clpentry.getPath()); boolean found = false; if (resource instanceof IContainer) { for (String resRoot : _resourceRootSet) { if (resource.getLocation().equals(new Path(resRoot))) { found = true; break; } } if (!found) { roots.add(resource.getLocation().toOSString()); } } } } } } catch (CoreException e) { _log.error(e); } return roots; } private boolean shouldBeSourceRoot(IResource resource) { if (resource instanceof IProject) { return true; } if (PackageUtils.isUnderSrcFolder(resource)) { return true; } return false; } } /** * This class is a handler for executing reading an InputStream of a process in a StringBuffer * * */ static public class InputStreamHandler extends Thread { private InputStream _stream; private MessageConsoleStream _consoleStream; private IProject _project; /** * Regular expression to match an error line pattern. These lines are usually in the form file:line:msg */ private static final Pattern javaErrorStartPattern = Pattern.compile(".*\\.java:\\d+:\\s\\S.*"); private static final Pattern rapcErrorStartPattern = Pattern.compile("[Ee]rror.*"); private static final Pattern rapcErrorStartPattern2 = Pattern.compile(".*[Ee]rror!.*"); /** * Regular expression to match a symbol error. This typically looks like symbol : <missing symbol> */ private static final Pattern errorSymbolPattern = Pattern.compile("^symbol\\s*:\\s\\S.*"); private static final Pattern errorLocationPattern = Pattern.compile("^location\\s*:\\s\\S.*$"); private static final Pattern errorSourcePattern = Pattern.compile("^\\s+\\S.*$"); private static final Pattern errorSourceLocationPattern = Pattern.compile("^\\s*\\^\\s*$"); /** * Regular expression to match a warning line pattern. These lines are usually in the form file:line: Warning!: msg */ private static final Pattern javaWarningStartPattern = Pattern.compile(".*\\.java:\\d+:\\s[Ww]arning.*"); private static final Pattern errorLineNumberPattern = Pattern.compile(":\\d+:"); private static final Pattern rapcWarningStartPattern = Pattern.compile("[Ww]arning.*"); private static final Pattern rapcWarningStartPattern2 = Pattern.compile(".*[Ww]arning!.*"); /** * @param captureBuffer * @param stream */ public InputStreamHandler(IProject project, MessageConsoleStream consoleOutputStream, InputStream inputStream) { _stream = inputStream; _consoleStream = consoleOutputStream; _project = project; } /* * (non-Javadoc) * * @see java.lang.Thread#run() */ @Override public void run() { try { /* * List of queued problems to submit. This is a stack, because it is useful to get the problem just added to add * additional info to it. */ Stack<Problem> problems = new Stack<Problem>(); InputStreamReader isr = new InputStreamReader(_stream); BufferedReader br = new BufferedReader(isr); while (true) { String line = br.readLine(); if (line == null) { break; } try { parse(line, problems); } catch (RuntimeException e) { _log.error(e.getMessage(), e); } _consoleStream.println(line); } _stream.close(); reportProblems(problems); } catch (IOException ioe) { _log.error(ioe); } } private void reportProblems(Stack<Problem> problems) { for (Problem problem : problems) { reportProblem(problem); } problems.clear(); } private void reportProblem(Problem problem) { _log.trace("reporting problem " + problem.file + " at " + problem.line + " about " + problem.msg); IResource resource = null; if (problem.file != null) { IPath problemFileLocation = new Path(problem.file); resource = ProjectUtils.getResource(_project, problemFileLocation.toFile()); } else { resource = _project; } if (resource != null) { PackagingManager.reportProblem(resource, problem.line, problem.start, problem.end, problem.msg, problem.level); } } /** * Takes a string and delegates it based on the pattern of it. * * @param s */ protected void parse(String s, Stack<Problem> problems) { if (javaWarningStartPattern.matcher(s).matches()) { parseJavaWarningStart(s, problems); } else if (rapcWarningStartPattern.matcher(s).matches() || rapcWarningStartPattern2.matcher(s).matches()) { parseRAPCWarningStart(s, problems); } else if (javaErrorStartPattern.matcher(s).matches()) { parseJavaErrorString(s, problems); } else if (rapcErrorStartPattern.matcher(s).matches() || rapcErrorStartPattern2.matcher(s).matches()) { parseRAPCErrorStart(s, problems); } } /** * Parses an error generated by RAPC. */ private void parseRAPCErrorStart(String s, Stack<Problem> problems) { // For example: // Error!: Error: java compiler failed: // C:\Java\jdk1.6.0_01\bin\javac.exe -source 1.3 // -target 1.1 -g -O -d C:\DOCUME~1\zqiu\LOCALS~1\Temp\r ... Matcher m = rapcErrorStartPattern.matcher(s); if (!m.find()) { m = rapcErrorStartPattern2.matcher(s); if (!m.find()) { _log.error("Failed to parse RAPC error message: " + s); return; } } Problem problem = new Problem(); problem.msg = s; problem.level = Problem.ERROR; problems.add(problem); } /** * Parses an error start. An error start has the file name, line number, and message. Subsequent lines will hold more * information about the specific error. */ private void parseRAPCWarningStart(String s, Stack<Problem> problems) { // For example: // Warning!: Reference to class: net.rim.device.api.io.File requires // signing // with key: RIM Runtime API Matcher m = rapcWarningStartPattern.matcher(s); if (!m.find()) { m = rapcWarningStartPattern2.matcher(s); if (!m.find()) { _log.error("Failed to parse RAPC warning message: " + s); return; } } Problem problem = new Problem(); problem.msg = s; problem.level = Problem.WARNING; problems.add(problem); } /** * Parses an error start. An error start has the file name, line number, and message. Subsequent lines will hold more * information about the specific error. */ private void parseJavaWarningStart(String s, Stack<Problem> problems) { // For example: // C:\samples\com\rim\samples\device\tictactoe\TTTService.java:10: // package net.rim.blackberry.api.blackberrymessenger does not exist int firstColon, secondColon; Matcher m = errorLineNumberPattern.matcher(s); if (m.find()) { firstColon = m.start(); secondColon = m.end() - 1; } else { _log.warn("Faling back to old way of doing things..."); secondColon = s.lastIndexOf(':'); firstColon = s.lastIndexOf(':', secondColon - 1); } Problem problem = new Problem(); problem.file = s.substring(0, firstColon).trim(); problem.line = Integer.parseInt(s.substring(firstColon + 1, secondColon)); problem.msg = s.substring(secondColon + 1).trim(); problem.level = Problem.WARNING; problems.add(problem); } /* Keep track of state for parse() automaton */ private int parseState; /** * Takes a string and delegates it based on the pattern of it. * * @param s */ private void parseJavaErrorString(String s, Stack<Problem> problems) { _log.trace("Parsing " + s); if (javaErrorStartPattern.matcher(s).matches()) { // Some warnings appear on stderr for some reason... // For example: // C:\samples\com\rim\samples\device\syncdemo\SyncDemo.java:288: // warning: [deprecation] getScreenWidth() in // net.rim.device.api.ui.Graphics has been deprecated if (javaWarningStartPattern.matcher(s).matches()) { parseJavaWarningStart(s, problems); } else { parseErrorStart(s, problems); } parseState = 0; } else if ((parseState == 0) && errorSymbolPattern.matcher(s).matches()) { parseErrorSymbol(s, problems); parseState = 1; } else if ((parseState == 1) && errorLocationPattern.matcher(s).matches()) { // Optional "location:*" line. Only occurs for stuff in inner // classes or methods. } else if ((parseState == 1) && errorSourcePattern.matcher(s).matches()) { parseErrorSource(s, problems); parseState = 2; } else if ((parseState == 2) && errorSourceLocationPattern.matcher(s).matches()) { parseErrorLocation(s, problems); parseState = 3; } } /** * Parses an error start. An error start has the file name, line number, and message. Subsequent lines will hold more * information about the specific error. */ private void parseErrorStart(String s, Stack<Problem> problems) { // For example: // C:\samples\com\rim\samples\device\tictactoe\TTTService.java:10: // package net.rim.blackberry.api.blackberrymessenger does not exist int firstColon, secondColon; Matcher m = errorLineNumberPattern.matcher(s); if (m.find()) { firstColon = m.start(); secondColon = m.end() - 1; } else { _log.warn("Faling back to old way of doing things..."); secondColon = s.lastIndexOf(':'); firstColon = s.lastIndexOf(':', secondColon - 1); } Problem problem = new Problem(); problem.file = s.substring(0, firstColon).trim(); problem.line = Integer.parseInt(s.substring(firstColon + 1, secondColon)); problem.msg = s.substring(secondColon + 1).trim(); problem.level = Problem.ERROR; problems.add(problem); } /** * This parses the line associated with a "cannot find symbol" error. Following such an error, rapc will output the undef * symbol. * * @param s */ private void parseErrorSymbol(String s, Stack<Problem> problems) { // For example: // C:\samples\com\rim\samples\device\tictactoe\TTTRequestListener.java // :28: cannot find symbol // symbol : class Session try { int colon = s.indexOf(":"); Problem problem = problems.peek(); if ((problem.msg != null) && problem.msg.equals("cannot find symbol")) { problem.msg += " " + s.substring(colon).trim(); } } catch (EmptyStackException e) { _log.error(e.getMessage(), e); } } private void parseErrorLocation(String s, Stack<Problem> problems) { try { Problem problem = problems.peek(); if (problem != null) { problem.start = s.indexOf('^'); String source = problem.source; int sourceLength = source.length(); for (int i = problem.start; i < sourceLength; i++) { char c = source.charAt(i); // All valid characters that can go into java // identifiers. if (((c > 96) && (c < 123)) || ((c > 64) && (c < 91)) || ((c > 47) && (c < 58)) || (c == 36) || (c == 95)) { // Do Nothing } else { problem.end = i + 1; break; } } } } catch (EmptyStackException e) { _log.error(e.getMessage(), e); } } private void parseErrorSource(String s, Stack<Problem> problems) { try { Problem problem = problems.peek(); if (problem != null) { problem.source = s; } } catch (EmptyStackException e) { _log.error(e.getMessage(), e); } } } /** * Problem declaration */ static public class Problem { public static final int ERROR = 1; public static final int WARNING = 2; public static final int INFO = 4; String file; int line; String msg; int level; String source; int start = -1; int end = -1; @Override public String toString() { return "Problem[file=" + file + ";line=" + line + ";msg=" + msg + ";level=" + level + ";]"; } } /** * ImportedJar class is used to differentiate if a jar is exported or not. * * */ public static class ImportedJar { String _path; boolean _exported; int _type; public ImportedJar(String path, boolean exported, int jarType) { _path = path; _exported = exported; _type = jarType; } public boolean isExported() { return _exported; } public void setExported(boolean exported) { _exported = exported; } public String getPath() { return _path; } public void setPath(String path) { _path = path; } public int getType() { return _type; } public void setType(int type) { _type = type; } public String toString() { return _path; } public boolean isMidletJar() { return (_type & MIDLET_JAR) > 0; } } }