xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/ConfigMerge.java (revision d6df19e1b22784c78f567cf74c42f18e3901b900)
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