Skip to content

Commit 9c986da

Browse files
committed
allow multiple string placeholders to be altered from CLI call
1 parent 37950e8 commit 9c986da

10 files changed

Lines changed: 379 additions & 171 deletions

File tree

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ To use a parameters' file, call AutoCompChem and give it the pathname to the par
105105
```
106106
autocompchem -p <path_to_parameters_file>
107107
```
108+
The content of a parameter file may also contain any number of placeholder strings that can be replaced upon calling AutoCompChem:
109+
```
110+
autocompchem -p <path_to_parameters_file> --replace <old_String>:<new_string> <other_placeholder>:<new_value>
111+
```
112+
where `<old_String>` and `<other_placeholder>` are two placeholder strings that will be replaces respectivly with `<new_string>` and `<new_value>`.
108113

109114
##### Example
110115
The parameters file [examples/single_job.params](examples/single_job.params) defines a simple task meant to change the identity of any Cl atom into Br in a given SDF file:
@@ -151,12 +156,23 @@ To use a job details file, call AutoCompChem and give it the pathname to the job
151156
```
152157
autocompchem -j <path_to_job_details_file>
153158
```
154-
155159
The job details file [examples/single_job.json](examples/single_job.json) defines the same job performed in the previous example, i.e., a job meant to change the identity of any Cl atom into Br in a given SDF file.
156160
Many other examples are available under the [test folder](test). However, note that the JSON format can be used to define many kinds on objects, including jobs that are not meant to be performed by AutoCompChem, e.g., any molecular modeling job. Therefore, not all ´.json´ files in the test folder define ACCJobs.
157161

158162
JSON job details files can be conveniently generated from parameter's file (and vice versa) by the `convertJobDefinition` task.
159163

164+
Notably, the parameters of the outermost job defined in the JSON file can be alterd by providing the correspodning CLI argument. Therefore, to re-run a job with a different input file we can use the wollowing:
165+
166+
```
167+
autocompchem -j <path_to_job_details_file> --infile <path_to_new_input_file>
168+
```
169+
This possibility applies *only to the parameters of the outermost job in the JSON file*, settings of any nested job cannot be overwritten by the corresponding CLI arguments. However, a string replacement mechanism allows to directly replace strings in any part of the JSON or parameter's file from CLI upon reading such files:
170+
```
171+
autocompchem -j <path_to_job_details_file> --replace <old_String>:<new_string> <other_placeholder>:<new_value>
172+
```
173+
where `<old_String>` and `<other_placeholder>` are two placeholder strings that will be replaces respectivly with `<new_string>` and `<new_value>`.
174+
175+
160176
### Multiple Jobs
161177
AutoCompChem can also perform multiple tasks, hence *jobs*, whether in a sequence (i.e., a workflow), or in parallel (i.e., a batch). Either way, the list of jobs to perform, whether steps of a workflow or independent jobs to be performed in parallel, are defined within a job that acts as a container. Such container may itself be contained in a parent job resulting in a recursive structure.
162178
The distinction between serial and parallel execution is controlled by the jobs' container: if the container defines the `PARALLELIZE: <threads>` key-value pair, then the contained jobs will be executed in parallel using a number of asynchronous threads equal to the value specified by `<threads>`.

src/main/java/autocompchem/datacollections/ParameterConstants.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,6 @@ public class ParameterConstants
138138
*/
139139
public static final String SITUATION = "SITUATION";
140140

141-
/**
142-
* Placeholder for a string defined via command line argument. This
143-
* placeholder string is replaced with the string given in CLI upon
144-
* importing parameters from a file.
145-
*/
146-
public static final String STRINGFROMCLI = "STRINGFROMCLI";
147-
148141
/**
149142
* Keyword of parameter defining tolerance towards info channels that are
150143
* defined by not readable.

src/main/java/autocompchem/run/JobFactory.java

Lines changed: 93 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,21 @@
22

33
import java.io.File;
44
import java.io.IOException;
5+
import java.io.StringReader;
56
import java.lang.reflect.Constructor;
67
import java.lang.reflect.InvocationTargetException;
8+
import java.nio.charset.StandardCharsets;
9+
import java.nio.file.Files;
10+
import java.util.AbstractMap.SimpleImmutableEntry;
11+
import java.util.Collections;
712
import java.util.HashMap;
813
import java.util.List;
914
import java.util.Map;
15+
import java.util.regex.Matcher;
16+
import java.util.regex.Pattern;
17+
18+
import com.google.gson.JsonIOException;
19+
import com.google.gson.JsonSyntaxException;
1020

1121
import org.apache.logging.log4j.core.config.Configurator;
1222

@@ -15,6 +25,7 @@
1525
import autocompchem.files.ACCFileType;
1626
import autocompchem.utils.NumberUtils;
1727
import autocompchem.files.FileAnalyzer;
28+
import autocompchem.io.ACCJson;
1829
import autocompchem.io.IOtools;
1930
import autocompchem.log.LogUtils;
2031
import autocompchem.text.TextBlockIndexed;
@@ -96,70 +107,84 @@ public synchronized void registerType(Object object)
96107

97108
public static Job buildFromFile(File file) throws IOException
98109
{
99-
return buildFromFile(file, null);
110+
Map<String, String> cliReplacements = new HashMap<>();
111+
return buildFromFile(file, cliReplacements);
100112
}
101-
113+
102114
//------------------------------------------------------------------------------
103-
104-
/**
105-
* Build a {@link Job} from from an existing file.
106-
* @param file the file from which to read the definition of the job.
107-
* @param imposedStr a string that has to be used to replace
108-
* {@value ParameterConstants#STRINGFROMCLI} in the definition
109-
* of the job. This is a way to customize a general-purpose job definition
110-
* making it specific for the given string.
111-
* @return the resulting job.
112-
* @throws IOException if the file is not suitable for creating a Job.
113-
*/
114-
115-
public static Job buildFromFile(File file, String imposedStr) throws IOException
115+
116+
/**
117+
* Build a {@link Job} from an existing file, applying optional string
118+
* replacements in file order before the job is parsed.
119+
*
120+
* @param file the file from which to read the definition of the job
121+
* @param cliReplacements the key-value mapping for replacing the
122+
* string placeholders in the JSON file.
123+
* @return the resulting job
124+
* @throws IOException if the file is not suitable for creating a Job
125+
*/
126+
public static Job buildFromFile(File file,
127+
Map<String, String> cliReplacements) throws IOException
116128
{
117-
Job job = null;
118-
119-
ACCFileType type = FileAnalyzer.detectFileType(file);
120-
switch (type)
121-
{
122-
case JSON:
123-
job = buildFromJSONFile(file, imposedStr);
124-
break;
125-
126-
case PAR:
127-
case TXT:
128-
job = buildFromParametersFile(file, imposedStr);
129-
break;
130-
129+
Job job = null;
130+
131+
ACCFileType type = FileAnalyzer.detectFileType(file);
132+
switch (type)
133+
{
134+
case JSON:
135+
job = buildFromJSONFile(file, cliReplacements);
136+
break;
137+
138+
case PAR:
139+
case TXT:
140+
job = buildFromParametersFile(file, cliReplacements);
141+
break;
142+
131143
default:
132144
throw new IllegalArgumentException("Format of file '" + file + "' does "
133145
+ "not allow to create a Job. Please make sure the file is "
134146
+ "either a JSON file or TXT parameters file adhering to "
135147
+ "ACC format.");
136-
}
137-
return job;
148+
}
149+
return job;
138150
}
139-
151+
140152
//------------------------------------------------------------------------------
141153

142154
/**
143155
* Build a {@link Job} from from an existing definition stored in a JSON
144-
* file. It also
145-
* allows you to given string that will replace the placeholder (i.e.,
146-
* {@value ParameterConstants.STRINGFROMCLI}).
156+
* file. It also allows to given string that will replace placeholders in
157+
* the JSON file.
147158
* @param file the file from which to read the definition of the job.
148-
* @param imposedStr a string that has to be used to replace
149-
* {@value ParameterConstants#STRINGFROMCLI} in the definition
150-
* of the job. This is a way to customize a general-purpose job definition
151-
* making it specific for the given string.
159+
* @param cliReplacements the key-value mapping for replacing the
160+
* string placeholders in the JSON file.
152161
* @return the resulting job.
153162
* @throws IOException is the file is not readable somehow.
154163
*/
155-
156-
public static Job buildFromJSONFile(File file, String imposedStr) throws IOException
164+
public static Job buildFromJSONFile(File file, Map<String, String> cliReplacements) throws IOException
157165
{
158166
Object obj = null;
159-
if (imposedStr!=null)
167+
if (cliReplacements != null && !cliReplacements.isEmpty())
160168
{
161-
obj = IOtools.readJsonFile(file, Job.class,
162-
ParameterConstants.STRINGFROMCLI, imposedStr);
169+
String json = Files.readString(file.toPath(), StandardCharsets.UTF_8);
170+
for (String key : cliReplacements.keySet())
171+
{
172+
json = json.replace(key, cliReplacements.get(key));
173+
}
174+
try
175+
{
176+
obj = ACCJson.getReader().fromJson(new StringReader(json), Job.class);
177+
}
178+
catch (JsonSyntaxException jse)
179+
{
180+
throw new IOException("JSON file '" + file
181+
+ "' has illegal syntax: " + jse.getMessage(), jse);
182+
}
183+
catch (JsonIOException jio)
184+
{
185+
throw new IOException("Error reading JSON from '" + file + "': "
186+
+ jio.getMessage(), jio);
187+
}
163188
} else {
164189
obj = IOtools.readJsonFile(file, Job.class);
165190
}
@@ -179,19 +204,15 @@ public static Job buildFromJSONFile(File file, String imposedStr) throws IOExcep
179204
/**
180205
* Build a {@link Job} from from an existing definition stored in a
181206
* text file adhering to the format of ACC's parameter's file. It also
182-
* allows you to given string that will replace the placeholder (i.e.,
183-
* {@value ParameterConstants.STRINGFROMCLI}).
207+
* allows to given string that will replace placeholders in the text file.
184208
* @param file the file from which to read the definition of the job.
185-
* @param imposedStr a string that has to be used to replace
186-
* {@value ParameterConstants#STRINGFROMCLI} in the definition
187-
* of the job. This is a way to customize a general-purpose job definition
188-
* making it specific for the given string.
189-
* @return the resulting job
190-
* @throws IOException if the file is not readable
209+
* @param cliReplacements the key-value mapping for replacing the
210+
* string placeholders in the text file.
211+
* @return the resulting job.
212+
* @throws IOException if the file is not suitable for creating a Job.
191213
*/
192-
193-
public static Job buildFromParametersFile(File file, String imposedStr)
194-
throws IOException
214+
public static Job buildFromParametersFile(File file,
215+
Map<String, String> cliReplacements) throws IOException
195216
{
196217
List<TextBlockIndexed> blocks = FileAnalyzer.extractTextBlocks(
197218
file,
@@ -200,11 +221,11 @@ public static Job buildFromParametersFile(File file, String imposedStr)
200221
false, //don't take only first
201222
false); //don't include delimiters
202223

203-
if (imposedStr != null && !imposedStr.isBlank())
224+
if (cliReplacements != null && !cliReplacements.isEmpty())
204225
{
205226
for (TextBlockIndexed tb : blocks)
206227
{
207-
tb.replaceAll(ParameterConstants.STRINGFROMCLI,imposedStr);
228+
applyCliReplacements(tb, cliReplacements);
208229
}
209230
}
210231

@@ -216,13 +237,26 @@ public static Job buildFromParametersFile(File file, String imposedStr)
216237
lines.add(ParameterConstants.RUNNABLEAPPIDKEY
217238
+ ParameterConstants.SEPARATOR + SoftwareId.ACC);
218239
TextBlockIndexed tb = new TextBlockIndexed(lines, 0, 0, 0);
219-
if (imposedStr != null && !imposedStr.isBlank())
220-
tb.replaceAll(ParameterConstants.STRINGFROMCLI,imposedStr);
240+
if (cliReplacements != null && !cliReplacements.isEmpty())
241+
applyCliReplacements(tb, cliReplacements);
221242
blocks.add(tb);
222243
}
223244

224245
return createJob(blocks);
225246
}
247+
248+
//------------------------------------------------------------------------------
249+
250+
private static void applyCliReplacements(TextBlockIndexed tb,
251+
Map<String, String> cliReplacements)
252+
{
253+
for (String key : cliReplacements.keySet())
254+
{
255+
String regex = Pattern.quote(key);
256+
String replacement = Matcher.quoteReplacement(cliReplacements.get(key));
257+
tb.replaceAll(regex, replacement);
258+
}
259+
}
226260

227261
//-----------------------------------------------------------------------------
228262

0 commit comments

Comments
 (0)