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.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.util.Hashtable; import java.util.Map; import java.util.Vector; import net.rim.ejde.internal.model.BasicBlackBerryProperties.AlternateEntryPoint; import net.rim.ejde.internal.model.BasicBlackBerryProperties.Icon; import net.rim.ejde.internal.model.BlackBerryProject; import net.rim.ejde.internal.model.BlackBerryProperties; 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.ProjectUtils; import net.rim.ejde.internal.util.ProjectUtils.RRHFile; import net.rim.ejde.internal.util.StatusFactory; import net.rim.ide.core.IDEError; import net.rim.ide.core.Util; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.osgi.util.NLS; /** * An instance of this class represents the rapc file of a BlackBerry Project. * */ public class RAPCFile { static private final Logger _log = Logger.getLogger(RAPCFile.class); /** * The maximum startup tiers available to a RIM project */ public static final int MAX_STARTUP_TIER = 7; BlackBerryProject _bbProject; File _rapcFile; Vector<String> _rapcContents = new Vector<String>(); /** * Constructs a RAPCFileContent instance. * * @param bbProject */ public RAPCFile(BlackBerryProject bbProject) { this._bbProject = bbProject; } /** * Loads the content of the RAPC file. <b>This method must be called before calling {@link #flushToFile()}.</b> * * @throws CoreException * */ public void loadContent() throws CoreException { initialize(); } void initialize() throws CoreException { BlackBerryProperties properties = _bbProject.getProperties(); _rapcContents.addElement("MIDlet-Name: " + _bbProject.getProject().getName()); String version = properties._general.getVersion(); if (version == null || version.length() == 0) { version = "0.0"; } _rapcContents.addElement("MIDlet-Version: " + version); String vendor = properties._general.getVendor(); if (vendor == null || vendor.length() == 0) { vendor = "<unknown>"; } _rapcContents.addElement("MIDlet-Vendor: " + vendor); String description = properties._general.getDescription(); if (description != null && description.length() != 0) { _rapcContents.addElement("MIDlet-Description: " + description); } _rapcContents.addElement("MIDlet-Jar-URL: " + _bbProject.getProject().getName() + ".jar"); _rapcContents.addElement("MIDlet-Jar-Size: 0"); _rapcContents.addElement("MicroEdition-Profile: MIDP-2.0"); _rapcContents.addElement("MicroEdition-Configuration: CLDC-1.1"); // handle alternate entry points String type = properties._application.getType(); if (!type.equals(BlackBerryProject.LIBRARY)) { _rapcFile = getRapcFile(_bbProject); addMidletEntries(_rapcFile, properties, _rapcContents, 1); AlternateEntryPoint[] entryPoints = properties.getAlternateEntryPoints(); for (int i = 0; i < entryPoints.length; ++i) { addMidletEntries(_rapcFile, new BlackBerryProperties(entryPoints[i]), _rapcContents, i + 2); } } else { _rapcContents.addElement("RIM-Library-Flags: " + getFlags(properties, true)); } addRimOptionsEntries(properties); } /** * Convert all forward slashes in the given <code>string</code> to back slashes. * * @param string * @return */ private String convertToBackSlash(String string) { return string.replace('\\', '/'); } private void addMidletEntries(File projectFile, BlackBerryProperties properties, Vector<String> entries, int index) throws CoreException { StringBuffer sb = new StringBuffer(); sb.append("MIDlet-").append(index); sb.append(": "); sb.append(properties._general.getTitle()); sb.append(','); Icon[] icons = properties._resources.getIconFiles(); for (int i = 0; i < icons.length; i++) { if (!icons[i].isFocus()) { // need to remove the source folder segment IPath iconFilePath = getSourceFolderRelativePath(icons[i].getCanonicalFileName()); sb.append(convertToBackSlash(iconFilePath.toOSString())); } } sb.append(','); if (!StringUtils.isBlank(properties._application.getMainMIDletName().trim())) { sb.append(properties._application.getMainMIDletName()); } else { sb.append(properties._application.getMainArgs()); } entries.addElement(sb.toString()); boolean hasFocusIcon = false; // set focus icon for (int i = 0; i < icons.length; ++i) { if (icons[i].isFocus()) { sb.setLength(0); // we only allow one focus icon sb.append("RIM-MIDlet-Icon-").append(index).append('-').append(1); sb.append(": "); // need to remove the source folder segment IPath iconFilePath = getSourceFolderRelativePath(icons[i].getCanonicalFileName()); sb.append(convertToBackSlash(iconFilePath.toOSString())); sb.append(",focused"); entries.addElement(sb.toString()); hasFocusIcon = true; } } if (hasFocusIcon) { sb.setLength(0); sb.append("RIM-MIDlet-Icon-Count-").append(index); sb.append(": "); sb.append(1); entries.addElement(sb.toString()); } sb.setLength(0); sb.append("RIM-MIDlet-Flags-").append(index); sb.append(": "); sb.append(getFlags(properties, false)); entries.addElement(sb.toString()); int ribbonPosition = properties._application.getHomeScreenPosition(); if (ribbonPosition != 0) { sb.setLength(0); sb.append("RIM-MIDlet-Position-").append(index); sb.append(": "); sb.append(ribbonPosition); entries.addElement(sb.toString()); } // we need to check all resource related properties to make sure the resource is valid String titleResourceBundleClassName = properties._resources.getTitleResourceBundleClassName(); String titleResourceBundleKey = properties._resources.getTitleResourceBundleKey(); if (properties._resources.hasTitleResource() && !StringUtils.isEmpty(titleResourceBundleClassName) && !StringUtils.isEmpty(titleResourceBundleKey)) { sb.setLength(0); sb.append("RIM-MIDlet-NameResourceBundle-").append(index); sb.append(": "); sb.append(titleResourceBundleClassName); entries.addElement(sb.toString()); sb.setLength(0); sb.append("RIM-MIDlet-NameResourceId-").append(index); sb.append(": "); sb.append(getTitleResourceId(properties)); entries.addElement(sb.toString()); } // check kewword resources String keywordResourceBundleClassName = properties.getKeywordResources() .getKeywordTitleResourceBundleClassName(); String keywordResourceBundleKey = properties.getKeywordResources().getKeywordResourceBundleKey(); if (!StringUtils.isEmpty(keywordResourceBundleClassName) && !StringUtils.isEmpty(keywordResourceBundleKey)) { sb.setLength(0); sb.append("RIM-MIDlet-KeywordResourceBundle-").append(index); sb.append(": "); sb.append(keywordResourceBundleClassName); entries.addElement(sb.toString()); sb.setLength(0); sb.append("RIM-MIDlet-KeywordResourceId-").append(index); sb.append(": "); sb.append(keywordResourceBundleKey); entries.addElement(sb.toString()); } } /* * These are internal options. There is no UI presented for them in external eJDE. */ private void addRimOptionsEntries(BlackBerryProperties properties) { StringBuffer sb = new StringBuffer(); String prefix = "RIM-Options: "; //$NON-NLS-1$ if (properties._application.isAddOn()) { if (sb.length() == 0) { sb.append(prefix); } else { sb.append(","); //$NON-NLS-1$ } sb.append("add-on"); //$NON-NLS-1$ } _rapcContents.addElement(sb.toString()); } /** * Get the resource id for the given project. We look this up given the resource title key that has been chosen. We used to * store the id number but problems occur if people update their resources outside of the resource editor (which preserves the * id numbers). * * @throws CoreException */ private int getTitleResourceId(BlackBerryProperties properties) throws CoreException { String key = properties._resources.getTitleResourceBundleKey(); Map<String, RRHFile> resourceMap = ProjectUtils.getProjectResources(_bbProject); RRHFile rrhFile = resourceMap.get(properties._resources.getTitleResourceBundleClassName()); if (rrhFile == null) { String msg = "Could not find key information for " + properties._resources.getTitleResourceBundleClassName(); _log.error(msg); throw new CoreException(StatusFactory.createErrorStatus(msg)); } Hashtable<String, String> headerKey2Id = rrhFile.getKeyTalbe(); if (headerKey2Id == null) { String path; if (rrhFile.getFile() != null) { path = rrhFile.getFile().getLocation().toOSString(); } else { path = properties._resources.getTitleResourceBundleClassName(); } String msg = NLS.bind(Messages.RAPCFIlE_NO_KEY_MSG, path); _log.error(msg); throw new CoreException(StatusFactory.createErrorStatus(msg)); } String resourceId = headerKey2Id.get(key); if (resourceId == null) { String msg = NLS.bind(Messages.RAPCFIlE_RESOURCE_KEY_NOT_FOUND_MSG, key); _log.error(msg); throw new CoreException(StatusFactory.createErrorStatus(msg)); } try { return Integer.parseInt(resourceId); } catch (NumberFormatException nfe) { _log.error(nfe); throw new CoreException(StatusFactory.createErrorStatus(nfe.getMessage())); } } /** * Get the path relative to the source folder of the given <code>canonicalFileName</code>. * * @param canonicalFileName * @return */ private IPath getSourceFolderRelativePath(String canonicalFileName) { IPath iconFilePath = new Path(canonicalFileName); IFile iconFile = _bbProject.getProject().getFile(iconFilePath); IContainer folder = PackageUtils.getSrcFolder(iconFile); if (folder == null) { return iconFilePath; } return iconFilePath.removeFirstSegments(folder.getProjectRelativePath().segmentCount()); } private int getFlags(BlackBerryProperties properties, boolean forceSystemModule) { // The flags are encoded into a single byte: // bit 0 - run on startup // bit 1 - system module // bit 2 - auto restart // bit 3 - unused // bit 4 - unused // bit 5 - startup tier (0 is 111b, 7 is 000b) // bit 6 - startup tier // bit 7 - startup tier boolean isAutostartup = properties._application.isAutostartup(); boolean isSystemModule = properties._application.isSystemModule() || properties._application.getType().equals(BlackBerryProject.LIBRARY);// a lib has to be run as system module boolean isAutoRestart = properties._application.isAutoRestart(); int flags = (isAutostartup ? 1 : 0) + ((isSystemModule || forceSystemModule) ? 2 : 0) + (isAutoRestart ? 4 : 0) + ((MAX_STARTUP_TIER - properties._application.getStartupTier()) << 5); return flags; } final static public File getRapcFile(BlackBerryProject project) { IPath outputFilePath = project.getProject().getLocation(); outputFilePath = outputFilePath.append(getRelativeRapcFilePath(project)); return outputFilePath.toFile(); } /** * Get the relative path of the rapc file of the given <code>project</code>. * * @param project * @return */ final static public IPath getRelativeRapcFilePath(BlackBerryProject project) { IPath outputFilePath = PackagingUtils.getRelativeStandardOutputFilePath(project); outputFilePath = outputFilePath.removeLastSegments(1); outputFilePath = outputFilePath.append(project.getProperties()._packaging.getOutputFileName() + ".rapc"); return outputFilePath; } /** * Collects a resource file content (like .rapc) * * @param relativeTo * @return * @throws IDEError */ private byte[] collectResourceInformation() throws IDEError { ByteArrayOutputStream bout = new ByteArrayOutputStream(); PrintStream out; try { out = new PrintStream(bout, false, "UTF-8"); } catch (UnsupportedEncodingException uee) { out = new PrintStream(bout); } for (int i = 0; i < _rapcContents.size(); ++i) { out.println(_rapcContents.elementAt(i)); } out.close(); return bout.toByteArray(); } public void flushToFile() { // TODO Clean up old generated jad files unless it is specifically listed in // project // String type = _bbProject.getProperties()._application.getType(); // if( type.equals( "MIDLET" ) || type.equals( "MIDLET_ENTRY" ) ) { // File jadFile = new File( _bbProject.getProperties()._packaging.getOutputFolder() + ".jad" ); // if( jadFile.exists() ) { // boolean canDelete = true; // TODO how to handle the case if the jad file is part of the // project // for ( int j=0; j < _files.size(); ++j ) { // WorkspaceFile fn = // (WorkspaceFile/*Node*/)_files.elementAt(j); // if ( fn.getIsJad() ) { // if ( fn.getFile().equals( jadFile ) ) { // canDelete = false; // jad file is part of project, don't // delete! // } // } // } // if( canDelete ) { // jad file was auto-generated by rapc, delete // // it // jadFile.delete(); // } // } // } File outputFile = getRapcFile(_bbProject); byte[] newBytes; try { newBytes = collectResourceInformation(); if (!Util.isFileIdentical(outputFile, newBytes)) { // either old file doesn't exist or it isn't the same write out // the new data FileOutputStream fout = new FileOutputStream(outputFile); fout.write(newBytes); fout.close(); } } catch (IDEError e) { _log.error(e); } catch (FileNotFoundException e) { _log.error(e); } catch (IOException e) { _log.error(e); } } }