11/*
2- * Copyright (c) 2019, 2022 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2019, 2024 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2525import java .io .IOException ;
2626import java .nio .file .Files ;
2727import java .nio .file .Path ;
28+ import java .util .ArrayList ;
2829import java .util .Collections ;
29- import java .util .HashMap ;
30+ import java .util .List ;
3031import java .util .Map ;
3132import java .util .Objects ;
3233import java .util .Optional ;
3334import java .util .regex .Matcher ;
3435import java .util .regex .Pattern ;
36+ import java .util .stream .Stream ;
3537
3638
3739public final class CfgFile {
38- public String getValue (String section , String key ) {
39- Objects .requireNonNull (section );
40- Objects .requireNonNull (key );
40+ public String getValue (String sectionName , String key ) {
41+ var section = getSection (sectionName );
42+ TKit .assertTrue (section != null , String .format (
43+ "Check section [%s] is found in [%s] cfg file" , sectionName , id ));
4144
42- Map <String , String > entries = data .get (section );
43- TKit .assertTrue (entries != null , String .format (
44- "Check section [%s] is found in [%s] cfg file" , section , id ));
45-
46- String value = entries .get (key );
45+ String value = section .getValue (key );
4746 TKit .assertNotNull (value , String .format (
4847 "Check key [%s] is found in [%s] section of [%s] cfg file" , key ,
49- section , id ));
48+ sectionName , id ));
5049
5150 return value ;
5251 }
5352
54- private CfgFile (Map <String , Map <String , String >> data , String id ) {
53+ public String getValueUnchecked (String sectionName , String key ) {
54+ var section = getSection (sectionName );
55+ if (section != null ) {
56+ return section .getValue (key );
57+ } else {
58+ return null ;
59+ }
60+ }
61+
62+ public void addValue (String sectionName , String key , String value ) {
63+ var section = getSection (sectionName );
64+ if (section == null ) {
65+ section = new Section (sectionName , new ArrayList <>());
66+ data .add (section );
67+ }
68+ section .data .add (Map .entry (key , value ));
69+ }
70+
71+ public CfgFile () {
72+ this (new ArrayList <>(), "*" );
73+ }
74+
75+ public static CfgFile combine (CfgFile base , CfgFile mods ) {
76+ var cfgFile = new CfgFile (new ArrayList <>(), "*" );
77+ for (var src : List .of (base , mods )) {
78+ for (var section : src .data ) {
79+ for (var kvp : section .data ) {
80+ cfgFile .addValue (section .name , kvp .getKey (), kvp .getValue ());
81+ }
82+ }
83+ }
84+ return cfgFile ;
85+ }
86+
87+ private CfgFile (List <Section > data , String id ) {
5588 this .data = data ;
5689 this .id = id ;
5790 }
5891
59- public static CfgFile readFromFile (Path path ) throws IOException {
92+ public void save (Path path ) {
93+ var lines = data .stream ().flatMap (section -> {
94+ return Stream .concat (
95+ Stream .of (String .format ("[%s]" , section .name )),
96+ section .data .stream ().map (kvp -> {
97+ return String .format ("%s=%s" , kvp .getKey (), kvp .getValue ());
98+ }));
99+ });
100+ TKit .createTextFile (path , lines );
101+ }
102+
103+ private Section getSection (String name ) {
104+ Objects .requireNonNull (name );
105+ for (var section : data .reversed ()) {
106+ if (name .equals (section .name )) {
107+ return section ;
108+ }
109+ }
110+ return null ;
111+ }
112+
113+ public static CfgFile load (Path path ) throws IOException {
60114 TKit .trace (String .format ("Read [%s] jpackage cfg file" , path ));
61115
62116 final Pattern sectionBeginRegex = Pattern .compile ( "\\ s*\\ [([^]]*)\\ ]\\ s*" );
63117 final Pattern keyRegex = Pattern .compile ( "\\ s*([^=]*)=(.*)" );
64118
65- Map < String , Map < String , String >> result = new HashMap <>();
119+ List < Section > sections = new ArrayList <>();
66120
67121 String currentSectionName = null ;
68- Map <String , String > currentSection = new HashMap <>();
122+ List < Map . Entry <String , String >> currentSection = new ArrayList <>();
69123 for (String line : Files .readAllLines (path )) {
70124 Matcher matcher = sectionBeginRegex .matcher (line );
71125 if (matcher .find ()) {
72126 if (currentSectionName != null ) {
73- result .put (currentSectionName , Collections .unmodifiableMap (
74- new HashMap <>(currentSection )));
127+ sections .add (new Section (currentSectionName ,
128+ Collections .unmodifiableList (new ArrayList <>(
129+ currentSection ))));
75130 }
76131 currentSectionName = matcher .group (1 );
77132 currentSection .clear ();
@@ -80,19 +135,31 @@ public static CfgFile readFromFile(Path path) throws IOException {
80135
81136 matcher = keyRegex .matcher (line );
82137 if (matcher .find ()) {
83- currentSection .put (matcher .group (1 ), matcher .group (2 ));
84- continue ;
138+ currentSection .add (Map .entry (matcher .group (1 ), matcher .group (2 )));
85139 }
86140 }
87141
88142 if (!currentSection .isEmpty ()) {
89- result .put (Optional .ofNullable (currentSectionName ).orElse ("" ),
90- Collections .unmodifiableMap (currentSection ));
143+ sections .add (new Section (
144+ Optional .ofNullable (currentSectionName ).orElse ("" ),
145+ Collections .unmodifiableList (currentSection )));
91146 }
92147
93- return new CfgFile (Collections .unmodifiableMap (result ), path .toString ());
148+ return new CfgFile (sections , path .toString ());
149+ }
150+
151+ private static record Section (String name , List <Map .Entry <String , String >> data ) {
152+ String getValue (String key ) {
153+ Objects .requireNonNull (key );
154+ for (var kvp : data .reversed ()) {
155+ if (key .equals (kvp .getKey ())) {
156+ return kvp .getValue ();
157+ }
158+ }
159+ return null ;
160+ }
94161 }
95162
96- private final Map < String , Map < String , String > > data ;
163+ private final List < Section > data ;
97164 private final String id ;
98165}
0 commit comments