1b5840353SAdam Hornáček /* 2b5840353SAdam Hornáček * CDDL HEADER START 3b5840353SAdam Hornáček * 4b5840353SAdam Hornáček * The contents of this file are subject to the terms of the 5b5840353SAdam Hornáček * Common Development and Distribution License (the "License"). 6b5840353SAdam Hornáček * You may not use this file except in compliance with the License. 7b5840353SAdam Hornáček * 8b5840353SAdam Hornáček * See LICENSE.txt included in this distribution for the specific 9b5840353SAdam Hornáček * language governing permissions and limitations under the License. 10b5840353SAdam Hornáček * 11b5840353SAdam Hornáček * When distributing Covered Code, include this CDDL HEADER in each 12b5840353SAdam Hornáček * file and include the License file at LICENSE.txt. 13b5840353SAdam Hornáček * If applicable, add the following below this CDDL HEADER, with the 14b5840353SAdam Hornáček * fields enclosed by brackets "[]" replaced with your own identifying 15b5840353SAdam Hornáček * information: Portions Copyright [yyyy] [name of copyright owner] 16b5840353SAdam Hornáček * 17b5840353SAdam Hornáček * CDDL HEADER END 18b5840353SAdam Hornáček */ 19b5840353SAdam Hornáček 20b5840353SAdam Hornáček /* 21*d6df19e1SAdam Hornacek * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. 22b5840353SAdam Hornáček */ 239805b761SAdam Hornáček package org.opengrok.indexer.configuration; 24b5840353SAdam Hornáček 25b5840353SAdam Hornáček import java.beans.IntrospectionException; 26b5840353SAdam Hornáček import java.beans.PropertyDescriptor; 27b5840353SAdam Hornáček import java.io.File; 28b5840353SAdam Hornáček import java.io.IOException; 29b5840353SAdam Hornáček import java.io.OutputStream; 30bf9cb9d4SKryštof Tulinger import java.io.PrintStream; 31b5840353SAdam Hornáček import java.lang.reflect.Field; 32b5840353SAdam Hornáček import java.lang.reflect.Method; 33b5840353SAdam Hornáček import java.lang.reflect.Modifier; 34b5840353SAdam Hornáček import java.text.ParseException; 359805b761SAdam Hornáček import org.opengrok.indexer.util.Getopt; 36b5840353SAdam Hornáček 37b5840353SAdam Hornáček /** 38b5840353SAdam Hornáček * Merge 2 config files together. More precisely, take the 1st as a base and 39b5840353SAdam Hornáček * set all properties from the 2nd in it. 40b5840353SAdam Hornáček * 41b5840353SAdam Hornáček * @author Vladimir Kotal 42b5840353SAdam Hornáček */ 43b5840353SAdam Hornáček public class ConfigMerge { 44b5840353SAdam Hornáček 450e4c5554SAdam Hornacek private static final String NAME = "ConfigMerge"; 46b5840353SAdam Hornáček ConfigMerge()47ff44f24aSAdam Hornáček private ConfigMerge() { 48ff44f24aSAdam Hornáček } 49ff44f24aSAdam Hornáček 50b5840353SAdam Hornáček /** 51b5840353SAdam Hornáček * Merge base and new configuration. 52b5840353SAdam Hornáček * @param cfgBase base configuration 53b5840353SAdam Hornáček * @param cfgNew new configuration, will receive properties from the base configuration 54b5840353SAdam Hornáček * @throws Exception exception 55b5840353SAdam Hornáček */ merge(Configuration cfgBase, Configuration cfgNew)56b5840353SAdam Hornáček public static void merge(Configuration cfgBase, Configuration cfgNew) throws Exception { 57b5840353SAdam Hornáček Configuration cfgDefault = new Configuration(); 58b5840353SAdam Hornáček 59b5840353SAdam Hornáček // Basic strategy: take all non-static/transient fields that have a setter 60b5840353SAdam Hornáček // from cfgBase that are not of default value and set them to cfgNew. 61b5840353SAdam Hornáček for (Field field : cfgBase.getClass().getDeclaredFields()) { 62b5840353SAdam Hornáček String fieldName = field.getName(); 63b5840353SAdam Hornáček int modifiers = field.getModifiers(); 64b5840353SAdam Hornáček if (Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers) || 65b5840353SAdam Hornáček Modifier.isFinal(modifiers)) { 66b5840353SAdam Hornáček continue; 67b5840353SAdam Hornáček } 68*d6df19e1SAdam Hornacek PropertyDescriptor desc; 69b5840353SAdam Hornáček try { 70b5840353SAdam Hornáček desc = new PropertyDescriptor(fieldName, Configuration.class); 71b5840353SAdam Hornáček } catch (IntrospectionException ex) { 72b5840353SAdam Hornáček throw new Exception("cannot get property descriptor for '" + fieldName + "'"); 73b5840353SAdam Hornáček } 74b5840353SAdam Hornáček 75b5840353SAdam Hornáček Method setter = desc.getWriteMethod(); 76b5840353SAdam Hornáček if (setter == null) { 77b5840353SAdam Hornáček throw new Exception("no setter for '" + fieldName + "'"); 78b5840353SAdam Hornáček } 79b5840353SAdam Hornáček 80b5840353SAdam Hornáček Method getter = desc.getReadMethod(); 81b5840353SAdam Hornáček if (getter == null) { 82b5840353SAdam Hornáček throw new Exception("no getter for '" + fieldName + "'"); 83b5840353SAdam Hornáček } 84b5840353SAdam Hornáček 85b5840353SAdam Hornáček try { 86b5840353SAdam Hornáček Object obj = getter.invoke(cfgBase); 87b5840353SAdam Hornáček if ((obj == null && getter.invoke(cfgDefault) == null) || 88b5840353SAdam Hornáček obj.equals(getter.invoke(cfgDefault))) { 89b5840353SAdam Hornáček continue; 90b5840353SAdam Hornáček } 91b5840353SAdam Hornáček } catch (Exception ex) { 92b5840353SAdam Hornáček throw new Exception("failed to invoke getter for " + fieldName + ": " + ex); 93b5840353SAdam Hornáček } 94b5840353SAdam Hornáček 95b5840353SAdam Hornáček try { 96b5840353SAdam Hornáček setter.invoke(cfgNew, getter.invoke(cfgBase)); 97b5840353SAdam Hornáček } catch (Exception ex) { 98b5840353SAdam Hornáček throw new Exception("failed to invoke setter for '" + fieldName + "'"); 99b5840353SAdam Hornáček } 100b5840353SAdam Hornáček } 101b5840353SAdam Hornáček } 102b5840353SAdam Hornáček main(String[] argv)103b5840353SAdam Hornáček public static void main(String[] argv) { 104b5840353SAdam Hornáček 105b5840353SAdam Hornáček Getopt getopt = new Getopt(argv, "h?"); 106b5840353SAdam Hornáček 107b5840353SAdam Hornáček try { 108b5840353SAdam Hornáček getopt.parse(); 109b5840353SAdam Hornáček } catch (ParseException ex) { 1100e4c5554SAdam Hornacek System.err.println(NAME + ": " + ex.getMessage()); 111*d6df19e1SAdam Hornacek bUsage(System.err); 112b5840353SAdam Hornáček System.exit(1); 113b5840353SAdam Hornáček } 114b5840353SAdam Hornáček 115b5840353SAdam Hornáček int cmd; 116b5840353SAdam Hornáček getopt.reset(); 117b5840353SAdam Hornáček while ((cmd = getopt.getOpt()) != -1) { 118b5840353SAdam Hornáček switch (cmd) { 119b5840353SAdam Hornáček case '?': 120b5840353SAdam Hornáček case 'h': 121*d6df19e1SAdam Hornacek aUsage(System.out); 122b5840353SAdam Hornáček System.exit(0); 123b5840353SAdam Hornáček break; 124b5840353SAdam Hornáček default: 125b5840353SAdam Hornáček System.err.println("Internal Error - Not implemented option: " + (char) cmd); 126*d6df19e1SAdam Hornacek bUsage(System.err); 127b5840353SAdam Hornáček System.exit(1); 128b5840353SAdam Hornáček break; 129b5840353SAdam Hornáček } 130b5840353SAdam Hornáček } 131b5840353SAdam Hornáček 132b5840353SAdam Hornáček int optind = getopt.getOptind(); 133b5840353SAdam Hornáček if (optind < 0 || argv.length - optind != 2) { 134*d6df19e1SAdam Hornacek aUsage(System.err); 135b5840353SAdam Hornáček System.exit(1); 136b5840353SAdam Hornáček } 137b5840353SAdam Hornáček 138b5840353SAdam Hornáček Configuration cfgBase = null; 139b5840353SAdam Hornáček try { 140b5840353SAdam Hornáček cfgBase = Configuration.read(new File(argv[optind])); 141b5840353SAdam Hornáček } catch (IOException ex) { 142b5840353SAdam Hornáček System.err.println("cannot read base file " + argv[optind] + ":" + ex); 143b5840353SAdam Hornáček System.exit(1); 144b5840353SAdam Hornáček } 145b5840353SAdam Hornáček 146b5840353SAdam Hornáček Configuration cfgNew = null; 147b5840353SAdam Hornáček try { 148b5840353SAdam Hornáček cfgNew = Configuration.read(new File(argv[optind + 1])); 149b5840353SAdam Hornáček } catch (IOException ex) { 150b5840353SAdam Hornáček System.err.println("cannot read file " + argv[optind + 1] + ":" + ex); 151b5840353SAdam Hornáček System.exit(1); 152b5840353SAdam Hornáček } 153b5840353SAdam Hornáček 154b5840353SAdam Hornáček try { 155b5840353SAdam Hornáček merge(cfgBase, cfgNew); 156b5840353SAdam Hornáček } catch (Exception ex) { 157b5840353SAdam Hornáček System.err.print(ex); 158b5840353SAdam Hornáček System.exit(1); 159b5840353SAdam Hornáček } 160b5840353SAdam Hornáček 161b5840353SAdam Hornáček // Write the resulting XML representation to standard output. 162b5840353SAdam Hornáček OutputStream os = System.out; 163b5840353SAdam Hornáček cfgNew.encodeObject(os); 164b5840353SAdam Hornáček } 165b5840353SAdam Hornáček aUsage(PrintStream out)166*d6df19e1SAdam Hornacek private static void aUsage(PrintStream out) { 167bf9cb9d4SKryštof Tulinger out.println("Usage:"); 1680e4c5554SAdam Hornacek out.println(NAME + " [-h] <config_file_base> <config_file_new>"); 169bf9cb9d4SKryštof Tulinger out.println(); 170bf9cb9d4SKryštof Tulinger out.println("OPTIONS:"); 171bf9cb9d4SKryštof Tulinger out.println("Help"); 172bf9cb9d4SKryštof Tulinger out.println("-? print this help message"); 173bf9cb9d4SKryštof Tulinger out.println("-h print this help message"); 174bf9cb9d4SKryštof Tulinger out.println(); 175b5840353SAdam Hornáček } 176b5840353SAdam Hornáček bUsage(PrintStream out)177*d6df19e1SAdam Hornacek private static void bUsage(PrintStream out) { 1780e4c5554SAdam Hornacek out.println("Maybe try to run " + NAME + " -h"); 179b5840353SAdam Hornáček } 180b5840353SAdam Hornáček } 181