/* * Copyright 2012 James Moger * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.moxie.ant; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.tools.zip.ZipOutputStream; import org.moxie.MoxieException; import org.moxie.console.Console; public class JarUtils { public static void mergeMetaInfServices(Console console, File destFile) { // collate service entries Map<String, String> services = new TreeMap<String, String>(); Map<String, StringBuilder> merged = new TreeMap<String, StringBuilder>(); ZipInputStream is = null; try { console.debug(1, "collating META-INF/services"); is = new ZipInputStream(new BufferedInputStream(new FileInputStream(destFile))); ZipEntry entry = null; while ((entry = is.getNextEntry()) != null) { String name= entry.getName(); if (!entry.isDirectory() && name.toLowerCase().startsWith("meta-inf/services")) { console.debug(2, name); byte [] buffer = new byte[(int) entry.getSize()]; int len = is.read(buffer); String content = new String(buffer, 0, len, "UTF-8"); if (!services.containsKey(name)) { // first hit on this service definition services.put(name, content); } else { // duplicate service definition if (!merged.containsKey(name)) { // inject first-hit definition StringBuilder sb = new StringBuilder(); sb.append(services.get(name)); sb.append('\n'); merged.put(name, sb); } // append duplicate to in-memory cache merged.get(name).append(content).append('\n'); } } is.closeEntry(); } } catch (Exception e) { console.error("Failed to merge service definitions!"); throw new MoxieException(e); } finally { // close input file if (is != null) { try { is.close(); } catch (IOException e1) { } } } // write merged service definitions if (merged.size() > 0) { console.log(1, "merging {0} META-INF/service definitions", merged.size()); File mergeFile = new File(destFile.getParentFile(), destFile.getName() + ".merge"); if (mergeFile.exists()) { mergeFile.delete(); } boolean success = false; List<String> skip = new ArrayList<String>(); is = null; ZipOutputStream os = null; try { is = new ZipInputStream(new BufferedInputStream(new FileInputStream(destFile))); os = new ZipOutputStream(mergeFile); ZipEntry entry = null; while ((entry = is.getNextEntry()) != null) { String name = entry.getName(); if (skip.contains(name)) { // already wrote merged service definition continue; } os.putNextEntry(new org.apache.tools.zip.ZipEntry(name)); if (merged.containsKey(name)) { // write merged service definition String def = merged.get(name).toString(); // strip blank lines def = def.replace("\r\n", "\n").replace("\n\n", "\n"); os.write(def.getBytes("UTF-8")); skip.add(name); } else { // pass-through int len = 0; byte [] buffer = new byte[4096]; while ((len = is.read(buffer, 0, buffer.length)) != -1) { os.write(buffer, 0, len); } } } success = true; } catch (Exception e) { console.error(e); } finally { // close input file if (is != null) { try { is.close(); } catch (Exception e) { } } // close merged output file if (os != null) { try { os.flush(); os.close(); } catch (Exception e) { } } // successfully wrote new jar with merged META-INF/services if (success) { destFile.delete(); mergeFile.renameTo(destFile); } } } } }