/******************************************************************************* * Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors * 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://robocode.sourceforge.net/license/epl-v10.html * * Contributors: * Pavel Savara * - Initial implementation *******************************************************************************/ package net.sf.robocode.repository.packager; import net.sf.robocode.core.Container; import net.sf.robocode.host.IHostManager; import net.sf.robocode.io.FileUtil; import net.sf.robocode.io.Logger; import net.sf.robocode.repository.items.RobotItem; import net.sf.robocode.repository.items.TeamItem; import net.sf.robocode.version.IVersionManager; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.net.URL; import java.net.URLDecoder; /** * @author Pavel Savara (original) */ public class JarCreator { public static String createPackage(File target, boolean includeSources, List<RobotItem> robots, List<TeamItem> teams, URL web, String desc, String author, String version) { final IHostManager host = Container.getComponent(IHostManager.class); final String rVersion = Container.getComponent(IVersionManager.class).getVersion(); JarOutputStream jarout = null; FileOutputStream fos = null; Set<String> entries = new HashSet<String>(); try { fos = new FileOutputStream(target); jarout = new JarOutputStream(fos, createManifest(robots)); jarout.setComment(rVersion + " - Robocode version"); for (TeamItem team : teams) { final String teamEntry = team.getRelativePath() + '/' + team.getShortClassName() + ".team"; if (!entries.contains(teamEntry)) { JarEntry jt = new JarEntry(teamEntry); jarout.putNextEntry(jt); entries.add(teamEntry); // called here, as an exception might occur before this line try { team.storeProperties(jarout, includeSources, version, desc, author, web); } finally { jarout.closeEntry(); } } } for (RobotItem robot : robots) { final String propsEntry = robot.getRelativePath() + '/' + robot.getShortClassName() + ".properties"; if (!entries.contains(propsEntry)) { JarEntry jt = new JarEntry(propsEntry); jarout.putNextEntry(jt); entries.add(propsEntry); // called here, as an exception might occur before this line try { robot.storeProperties(jarout, includeSources, version, desc, author, web); } finally { jarout.closeEntry(); } packageSourceAndClasses(includeSources, host, jarout, robot, entries); } } } catch (IOException e) { Logger.logError(e); } finally { FileUtil.cleanupStream(jarout); FileUtil.cleanupStream(fos); } StringBuilder sb = new StringBuilder(); for (String entry : entries) { sb.append(entry); sb.append('\n'); } appendCodeSize(target, sb); return sb.toString(); } private static void appendCodeSize(File target, StringBuilder sb) { int size = -1; try { // Call the codesize utility using reflection Object item = Class.forName("codesize.Codesize").getMethod("processZipFile", new Class[] { File.class}).invoke( null, target); size = (Integer) item.getClass().getMethod("getCodeSize", (Class[]) null).invoke(item, (Object[]) null); } catch (Exception ignore) {} if (size >= 0) { String weightClass = null; if (size >= 1500) { weightClass = "MegaBot (codesize >= 1500 bytes)"; } else if (size > 750) { weightClass = "MiniBot (codesize < 1500 bytes)"; } else if (size > 250) { weightClass = "MicroBot (codesize < 750 bytes)"; } else { weightClass = "NanoBot (codesize < 250 bytes)"; } sb.append("\n\n---- Codesize ----\n"); sb.append("Codesize: ").append(size).append(" bytes\n"); sb.append("Robot weight class: ").append(weightClass).append('\n'); } } private static Manifest createManifest(List<RobotItem> robots) { Manifest manifest; manifest = new Manifest(); manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); StringBuilder robotsString = new StringBuilder(); for (int i = 0; i < robots.size(); i++) { robotsString.append(robots.get(i).getFullClassName()); if (i < robots.size() - 1) { robotsString.append(','); } } manifest.getMainAttributes().put(new Attributes.Name("robots"), robotsString.toString()); return manifest; } private static void packageSourceAndClasses(boolean includeSources, IHostManager host, JarOutputStream jarout, RobotItem robot, Set<String> entries) throws IOException { for (String className : host.getReferencedClasses(robot)) { if (!className.startsWith("java") && !className.startsWith("robocode")) { String name = className.replace('.', '/'); packageSourceAndClass(includeSources, jarout, robot, name, entries); } } } private static void packageSourceAndClass(boolean includeSource, JarOutputStream jarout, RobotItem robot, String name, Set<String> entries) throws IOException { final String javaFileName = name + ".java"; final String classFileName = name + ".class"; if (includeSource && !entries.contains(javaFileName) && !name.contains("$")) { for (URL sourcePathURL : robot.getSourcePathURLs()) { String sourcePath = sourcePathURL.getPath(); sourcePath = URLDecoder.decode(sourcePath, "UTF-8"); File javaFile = new File(sourcePath, javaFileName); if (javaFile.exists()) { JarEntry je = new JarEntry(javaFileName); jarout.putNextEntry(je); entries.add(javaFileName); // called here, as an exception might occur before this line try { copy(javaFile, jarout); } finally { jarout.closeEntry(); } } } } String classPath = robot.getClassPathURL().getPath(); classPath = URLDecoder.decode(classPath, "UTF-8"); File classFile = new File(classPath, classFileName); if (classFile.exists() && !entries.contains(classFileName)) { JarEntry je = new JarEntry(classFileName); jarout.putNextEntry(je); entries.add(classFileName); // called here, as an exception might occur before this line try { copy(classFile, jarout); } finally { jarout.closeEntry(); } } } private static void copy(File inFile, JarOutputStream out) throws IOException { FileInputStream in = null; try { in = new FileInputStream(inFile); final byte[] buf = new byte[4096]; while (in.available() > 0) { int count = in.read(buf, 0, 4096); out.write(buf, 0, count); } } finally { FileUtil.cleanupStream(in); } } }