1 /*
   2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package jdk.tools.jlink.internal.plugins;
  26 
  27 import java.io.ByteArrayOutputStream;
  28 import java.io.FileInputStream;
  29 import java.io.IOException;
  30 import java.io.UncheckedIOException;
  31 import java.lang.module.ModuleDescriptor;
  32 import java.util.EnumSet;
  33 import java.util.HashMap;
  34 import java.util.Map;
  35 import java.util.Optional;
  36 import java.util.Properties;
  37 import java.util.Set;
  38 import java.util.function.Function;
  39 import jdk.tools.jlink.internal.Utils;
  40 import jdk.tools.jlink.plugin.ResourcePool;
  41 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
  42 import jdk.tools.jlink.plugin.ResourcePoolEntry;
  43 import jdk.tools.jlink.plugin.ResourcePoolModule;
  44 import jdk.tools.jlink.plugin.Plugin.Category;
  45 import jdk.tools.jlink.plugin.Plugin.State;
  46 import jdk.tools.jlink.plugin.Plugin;
  47 
  48 /**
  49  * This plugin adds/deletes information for 'release' file.
  50  */
  51 public final class ReleaseInfoPlugin implements Plugin {
  52     // option name
  53     public static final String NAME = "release-info";
  54     public static final String KEYS = "keys";
  55     private final Map<String, String> release = new HashMap<>();
  56 
  57     @Override
  58     public Category getType() {
  59         return Category.METAINFO_ADDER;
  60     }
  61 
  62     @Override
  63     public String getName() {
  64         return NAME;
  65     }
  66 
  67     @Override
  68     public String getDescription() {
  69         return PluginsResourceBundle.getDescription(NAME);
  70     }
  71 
  72     @Override
  73     public Set<State> getState() {
  74         return EnumSet.of(State.FUNCTIONAL);
  75     }
  76 
  77     @Override
  78     public boolean hasArguments() {
  79         return true;
  80     }
  81 
  82     @Override
  83     public String getArgumentsDescription() {
  84         return PluginsResourceBundle.getArgument(NAME);
  85     }
  86 
  87     @Override
  88     public void configure(Map<String, String> config) {
  89         String operation = config.get(NAME);
  90         switch (operation) {
  91             case "add": {
  92                 // leave it to open-ended! source, java_version, java_full_version
  93                 // can be passed via this option like:
  94                 //
  95                 //     --release-info add:build_type=fastdebug,source=openjdk,java_version=9
  96                 // and put whatever value that was passed in command line.
  97 
  98                 config.keySet().stream().
  99                     filter(s -> !NAME.equals(s)).
 100                     forEach(s -> release.put(s, config.get(s)));
 101             }
 102             break;
 103 
 104             case "del": {
 105                 // --release-info del:keys=openjdk,java_version
 106                 Utils.parseList(config.get(KEYS)).stream().forEach((k) -> {
 107                     release.remove(k);
 108                 });
 109             }
 110             break;
 111 
 112             default: {
 113                 // --release-info <file>
 114                 Properties props = new Properties();
 115                 try (FileInputStream fis = new FileInputStream(operation)) {
 116                     props.load(fis);
 117                 } catch (IOException exp) {
 118                     throw new RuntimeException(exp);
 119                 }
 120                 props.forEach((k, v) -> release.put(k.toString(), v.toString()));
 121             }
 122             break;
 123         }
 124     }
 125 
 126     @Override
 127     public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
 128         in.transformAndCopy(Function.identity(), out);
 129 
 130         // create a TOP level ResourcePoolEntry for "release" file.
 131         out.add(ResourcePoolEntry.create("/java.base/release",
 132             ResourcePoolEntry.Type.TOP, releaseFileContent()));
 133         return out.build();
 134     }
 135 
 136     private byte[] releaseFileContent() {
 137         Properties props = new Properties();
 138         props.putAll(release);
 139         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 140         try {
 141             props.store(baos, "");
 142             return baos.toByteArray();
 143         } catch (IOException ex) {
 144             throw new UncheckedIOException(ex);
 145         }
 146     }
 147 }