File: SkeletalExecutable.java

package info (click to toggle)
libjaba-client-java 2.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 2,052 kB
  • sloc: java: 17,308; makefile: 12
file content (325 lines) | stat: -rw-r--r-- 9,849 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/* Copyright (c) 2009 Peter Troshin
 *  
 *  JAva Bioinformatics Analysis Web Services (JABAWS) @version: 1.0     
 * 
 *  This library is free software; you can redistribute it and/or modify it under the terms of the
 *  Apache License version 2 as published by the Apache Software Foundation
 * 
 *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache 
 *  License for more details.
 * 
 *  A copy of the license is in apache_license.txt. It is also available here:
 * @see: http://www.apache.org/licenses/LICENSE-2.0.txt
 * 
 * Any republication or derived work distributed in source code form
 * must include this copyright and license notice.
 */

package compbio.engine.client;

import java.io.File;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.List;

import org.apache.log4j.Logger;

import compbio.engine.client.CommandBuilder.Parameter;
import compbio.engine.conf.PropertyHelperManager;
import compbio.metadata.Limit;
import compbio.metadata.LimitsManager;
import compbio.util.PropertyHelper;
import compbio.util.Util;

public abstract class SkeletalExecutable<T> implements Executable<T> {

	protected static final PropertyHelper ph = PropertyHelperManager.getPropertyHelper();

	private static Logger log = Logger.getLogger(SkeletalExecutable.class);

	// Cache for Limits information
	private LimitsManager<T> limits;

	public static final String INPUT = "input.txt";
	public static final String OUTPUT = "result.txt";
	public static final String ERROR = "error.txt";

	protected String inputFile = INPUT;
	protected String outputFile = OUTPUT;
	protected String errorFile = ERROR;

	private boolean isInputSet = false;
	private boolean isOutputSet = false;
	private boolean isErrorSet = false;

	/**
	 * This has to allow duplicate parameters as different options may have the
	 * same value e.g. Muscle -weight1 clustalw -weight2 clustalw
	 */
	protected CommandBuilder<T> cbuilder;

	public SkeletalExecutable() {
		cbuilder = new CommandBuilder<T>(" ");
	}

	public SkeletalExecutable(String parameterKeyValueDelimiter) {
		assert parameterKeyValueDelimiter != null;
		cbuilder = new CommandBuilder<T>(parameterKeyValueDelimiter);
	}

	public SkeletalExecutable<T> setInput(String inFile) {
		if (compbio.util.Util.isEmpty(inFile)) {
			throw new IllegalArgumentException("Input file must not be NULL");
		}
		this.inputFile = inFile;
		this.isInputSet = true;
		return this;
	}

	public SkeletalExecutable<T> setOutput(String outFile) {
		if (compbio.util.Util.isEmpty(outFile) || PathValidator.isAbsolutePath(outFile)) {
			throw new IllegalArgumentException("Output file must not be NULL and Absolute path could not be used! Please provide the filename only. Value provided: " + outFile);
		}
		this.outputFile = outFile;
		this.isOutputSet = true;
		return this;
	}

	public SkeletalExecutable<T> setError(String errFile) {
		if (compbio.util.Util.isEmpty(errFile) || PathValidator.isAbsolutePath(errFile)) {
			throw new IllegalArgumentException("Error file must not be NULL and Absolute path could not be used! Please provide the filename only. Value provided: " + errFile);
		}
		this.errorFile = errFile;
		this.isErrorSet = true;
		return this;
	}

	@Override
	public CommandBuilder<T> getParameters(ExecProvider provider) {
		/*
		 * Prevent modification of the parameters unintentionally. This is
		 * important to preserve executable parameters intact as engine could
		 * add things into the array as it see fit. For instance
		 * ExecutableWrapper (part of local engines) add command line as the
		 * first element of an array.
		 */
		paramValueUpdater();
		return cbuilder;
	}

	@Override
	public Executable<T> addParameters(List<String> parameters) {
		cbuilder.addParams(parameters);
		return this;
	}

	public Executable<T> setParameter(String parameter) {
		cbuilder.setParam(parameter);
		return this;
	}

	/**
	 * This is a generic method of changing values of the parameters with
	 * properties
	 * 
	 * This method iterates via commands for an executable finding matches from
	 * the Executable.properties file and replacing values in CommandBuilder
	 * with a combination of value from CommandBuilder to merge path from
	 * properties
	 */
	void paramValueUpdater() {
		for (Parameter command : cbuilder.getCommandList()) {
			if (command.value == null) {
				continue;
			}
			String propertyPath = EngineUtil.getExecProperty(command.name + ".path", getType());
			if (Util.isEmpty(propertyPath)) {
				continue;
			}
			if (new File(command.value).isAbsolute()) {
				// Matrix can be found so no actions necessary
				// This method has been called already and the matrix name
				// is modified to contain full path // no further actions is
				// necessary
				continue;
			}
			String absMatrixPath = EngineUtil.convertToAbsolute(propertyPath);
			command.value = absMatrixPath + File.separator + command.value;
			cbuilder.setParam(command);
		}
	}

	/**
	 * This method cannot really tell whether the files has actually been
	 * created or not. It must be overridden as required.
	 * 
	 * @see compbio.engine.client.Executable#getCreatedFiles()
	 */
	@Override
	public List<String> getCreatedFiles() {
		return Arrays.asList(getOutput(), getError());
	}

	@Override
	public String getInput() {
		return inputFile;
	}

	protected boolean isInputSet() {
		return isInputSet;
	}

	protected boolean isOutputSet() {
		return isOutputSet;
	}

	protected boolean isErrorSet() {
		return isErrorSet;
	}

	@Override
	public String getOutput() {
		return outputFile;
	}

	@Override
	public String getError() {
		return errorFile;
	}

	@Override
	public String toString() {
		String value = "Input: " + this.getInput() + "\n";
		value += "Output: " + this.getOutput() + "\n";
		value += "Error: " + this.getError() + "\n";
		value += "Class: " + this.getClass() + "\n";
		value += "Params: " + cbuilder + "\n";
		return value;
	}

	@Override
	public Executable<?> loadRunConfiguration(RunConfiguration rconfig) {
		if (!compbio.util.Util.isEmpty(rconfig.getOutput())) {
			setOutput(rconfig.getOutput());
		}
		if (!compbio.util.Util.isEmpty(rconfig.getError())) {
			setError(rconfig.getError());
		}
		if (!compbio.util.Util.isEmpty(rconfig.getInput())) {
			setInput(rconfig.getInput());
		}
		this.cbuilder = (CommandBuilder<T>) rconfig.getParameters();
		return this;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof SkeletalExecutable<?>)) {
			return false;
		}
		SkeletalExecutable<?> exec = (SkeletalExecutable<?>) obj;
		if (!Util.isEmpty(this.inputFile) && !Util.isEmpty(exec.inputFile)) {
			if (!this.inputFile.equals(exec.inputFile)) {
				return false;
			}
		}
		if (!Util.isEmpty(this.outputFile) && !Util.isEmpty(exec.outputFile)) {
			if (!this.outputFile.equals(exec.outputFile)) {
				return false;
			}
		}
		if (!Util.isEmpty(this.errorFile) && !Util.isEmpty(exec.errorFile)) {
			if (!this.errorFile.equals(exec.errorFile)) {
				return false;
			}
		}
		if (!this.cbuilder.equals(exec.cbuilder)) {
			return false;
		}
		return true;
	}

	@Override
	public int hashCode() {
		int code = inputFile.hashCode();
		code += outputFile.hashCode();
		code += errorFile.hashCode();
		code *= this.cbuilder.hashCode();
		return code;
	}

	@Override
	public String getClusterJobSettings() {
		String settings = ph.getProperty(getType().getSimpleName().toLowerCase() + ".cluster.settings");
		return settings == null ? "" : settings;
	}

	/**
	 * @return number of cpus to use on the cluster or 0 if the value is undefined
	 */
	public static int getClusterCpuNum(Class<? extends Executable<?>> type) {
		int cpus = 0;
		String cpuNum = ph.getProperty(type.getSimpleName().toLowerCase() + ".cluster.cpunum");
		if (compbio.util.Util.isEmpty(cpuNum)) {
			return 0;
		}
		try {
			cpus = Integer.parseInt(cpuNum);
		} catch (NumberFormatException e) {
			// safe to ignore
			log.debug("Number of cpus to use for cluster execution is defined but could not be parsed as integer! Given value is: " + cpuNum);
			return 0;
		}
		if (cpus < 1 || cpus > 100) {
			throw new InvalidParameterException("Number of cpu for cluster execution must be within 1 and 100! "
							+ "Look at the value of 'tcoffee.cluster.cpunum' property. Given value is " + cpus);
		}
		return cpus;
	}

	@Override
	public synchronized Limit<T> getLimit(String presetName) {
		// Assume this function is called for the first time and thus need
		// initialization
		if (limits == null) {
			limits = getLimits();
		}
		// Either the initialization failed or limits were not configured.
		if (limits == null) {
			return null;
		}

		Limit<T> limit = null;
		if (limits != null) {
			// this returns default limit if preset is undefined!
			limit = limits.getLimitByName(presetName);
		}
		// If limit is not defined for a particular preset, then return default
		// limit
		if (limit == null) {
			log.debug("Limit for the preset " + presetName
					+ " is not found. Using default");
			limit = limits.getDefaultLimit();
		}
		return limit;
	}

	@Override
	public LimitsManager<T> getLimits() {
		synchronized (SkeletalExecutable.class) {
			if (limits == null) {
				limits = EngineUtil.getLimits(this.getType());
			}
		}
		return limits;
	}

	/**
	 * @return subclasses must return their type
	 */
	public abstract Class<T> getType();
}