001/**
002 * Copyright 2010-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.secure;
017
018import java.io.BufferedOutputStream;
019import java.io.ByteArrayInputStream;
020import java.io.ByteArrayOutputStream;
021import java.io.File;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.OutputStream;
025import java.lang.reflect.InvocationTargetException;
026import java.util.ArrayList;
027import java.util.List;
028import java.util.Properties;
029
030import org.apache.commons.beanutils.BeanUtils;
031import org.apache.commons.io.FileUtils;
032import org.apache.commons.io.FilenameUtils;
033import org.apache.commons.io.IOUtils;
034import org.apache.commons.lang3.StringUtils;
035import org.kuali.common.util.Assert;
036import org.kuali.common.util.CollectionUtils;
037import org.kuali.common.util.Encodings;
038import org.kuali.common.util.LocationUtils;
039import org.kuali.common.util.PropertyUtils;
040import org.kuali.common.util.Str;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043
044import com.jcraft.jsch.Channel;
045import com.jcraft.jsch.ChannelExec;
046import com.jcraft.jsch.ChannelSftp;
047import com.jcraft.jsch.JSch;
048import com.jcraft.jsch.JSchException;
049import com.jcraft.jsch.Session;
050import com.jcraft.jsch.SftpATTRS;
051import com.jcraft.jsch.SftpException;
052
053/**
054 * @deprecated
055 */
056@Deprecated
057public class DefaultSecureChannel implements SecureChannel {
058
059        private static final Logger logger = LoggerFactory.getLogger(DefaultSecureChannel.class);
060        private static final String SFTP = "sftp";
061        private static final String EXEC = "exec";
062        private static final String FORWARDSLASH = "/";
063        private static final int DEFAULT_SLEEP_MILLIS = 10;
064        private static final String DEFAULT_ENCODING = Encodings.UTF8;
065
066        File knownHosts = SSHUtils.DEFAULT_KNOWN_HOSTS;
067        File config = SSHUtils.DEFAULT_CONFIG_FILE;
068        boolean useConfigFile = true;
069        boolean includeDefaultPrivateKeyLocations = true;
070        boolean strictHostKeyChecking = true;
071        int port = SSHUtils.DEFAULT_PORT;
072        int waitForClosedSleepMillis = DEFAULT_SLEEP_MILLIS;
073        String encoding = DEFAULT_ENCODING;
074        String username;
075        String hostname;
076        Integer connectTimeout;
077        List<File> privateKeys;
078        List<String> privateKeyStrings;
079        Properties options;
080
081        protected Session session;
082        protected ChannelSftp sftp;
083
084        @Override
085        public synchronized void open() throws IOException {
086                logOpen();
087                validate();
088                try {
089                        JSch jsch = getJSch();
090                        this.session = openSession(jsch);
091                        this.sftp = openSftpChannel(session, connectTimeout);
092                } catch (JSchException e) {
093                        throw new IOException("Unexpected error opening secure channel", e);
094                }
095        }
096
097        @Override
098        public synchronized void close() {
099                logger.info("Closing secure channel [{}]", ChannelUtils.getLocation(username, hostname));
100                closeQuietly(sftp);
101                closeQuietly(session);
102        }
103
104        @Override
105        public Result executeCommand(String command) {
106                return executeCommand(command, null);
107        }
108
109        @Override
110        public Result executeCommand(String command, String stdin) {
111                Assert.notBlank(command);
112                ChannelExec exec = null;
113                InputStream stdoutStream = null;
114                ByteArrayOutputStream stderrStream = null;
115                InputStream stdinStream = null;
116                try {
117                        // Preserve start time
118                        long start = System.currentTimeMillis();
119                        // Open an exec channel
120                        exec = (ChannelExec) session.openChannel(EXEC);
121                        // Convert the command string to bytes
122                        byte[] commandBytes = Str.getBytes(command, encoding);
123                        // Store the command on the exec channel
124                        exec.setCommand(commandBytes);
125                        // Prepare the stdin stream
126                        stdinStream = getInputStream(stdin, encoding);
127                        // Prepare the stderr stream
128                        stderrStream = new ByteArrayOutputStream();
129                        // Get the stdout stream from the ChannelExec object
130                        stdoutStream = exec.getInputStream();
131                        // Update the ChannelExec object with the stdin stream
132                        exec.setInputStream(stdinStream);
133                        // Update the ChannelExec object with the stderr stream
134                        exec.setErrStream(stderrStream);
135                        // Execute the command.
136                        // This consumes anything from stdin and stores output in stdout/stderr
137                        connect(exec, null);
138                        // Convert stdout and stderr to String's
139                        String stdout = Str.getString(IOUtils.toByteArray(stdoutStream), encoding);
140                        String stderr = Str.getString(stderrStream.toByteArray(), encoding);
141                        // Make sure the channel is closed
142                        waitForClosed(exec, waitForClosedSleepMillis);
143                        // Return the result of executing the command
144                        return ChannelUtils.getExecutionResult(exec.getExitStatus(), start, command, stdin, stdout, stderr, encoding);
145                } catch (Exception e) {
146                        throw new IllegalStateException(e);
147                } finally {
148                        // Cleanup
149                        IOUtils.closeQuietly(stdinStream);
150                        IOUtils.closeQuietly(stdoutStream);
151                        IOUtils.closeQuietly(stderrStream);
152                        closeQuietly(exec);
153                }
154        }
155
156        @Override
157        public void executeNoWait(String command) {
158                Assert.notBlank(command);
159                ChannelExec exec = null;
160                try {
161                        // Open an exec channel
162                        exec = (ChannelExec) session.openChannel(EXEC);
163                        // Convert the command string to bytes
164                        byte[] commandBytes = Str.getBytes(command, encoding);
165                        // Store the command on the exec channel
166                        exec.setCommand(commandBytes);
167                        // Execute the command.
168                        // This consumes anything from stdin and stores output in stdout/stderr
169                        connect(exec, null);
170                } catch (Exception e) {
171                        throw new IllegalStateException(e);
172                } finally {
173                        closeQuietly(exec);
174                }
175        }
176
177        protected InputStream getInputStream(String s, String encoding) {
178                if (s == null) {
179                        return null;
180                } else {
181                        return new ByteArrayInputStream(Str.getBytes(s, encoding));
182                }
183        }
184
185        protected void waitForClosed(ChannelExec exec, long millis) {
186                while (!exec.isClosed()) {
187                        sleep(millis);
188                }
189        }
190
191        protected void sleep(long millis) {
192                try {
193                        Thread.sleep(millis);
194                } catch (InterruptedException e) {
195                        throw new IllegalStateException(e);
196                }
197        }
198
199        @Override
200        public RemoteFile getWorkingDirectory() {
201                try {
202                        String workingDirectory = sftp.pwd();
203                        return getMetaData(workingDirectory);
204                } catch (SftpException e) {
205                        throw new IllegalStateException(e);
206                }
207        }
208
209        protected void validate() {
210                Assert.isTrue(SSHUtils.isValidPort(port));
211                Assert.notBlank(hostname);
212                Assert.notBlank(encoding);
213        }
214
215        protected void logOpen() {
216                logger.info("Opening secure channel [{}] encoding={}", ChannelUtils.getLocation(username, hostname), encoding);
217                logger.debug("Private key files - {}", CollectionUtils.toEmptyList(privateKeys).size());
218                logger.debug("Private key strings - {}", CollectionUtils.toEmptyList(privateKeyStrings).size());
219                logger.debug("Private key config file - {}", config);
220                logger.debug("Private key config file use - {}", useConfigFile);
221                logger.debug("Include default private key locations - {}", includeDefaultPrivateKeyLocations);
222                logger.debug("Known hosts file - {}", knownHosts);
223                logger.debug("Port - {}", port);
224                logger.debug("Connect timeout - {}", connectTimeout);
225                logger.debug("Strict host key checking - {}", strictHostKeyChecking);
226                logger.debug("Configuring channel with {} custom options", PropertyUtils.toEmpty(options).size());
227                if (options != null) {
228                        PropertyUtils.debug(options);
229                }
230        }
231
232        protected ChannelSftp openSftpChannel(Session session, Integer timeout) throws JSchException {
233                ChannelSftp sftp = (ChannelSftp) session.openChannel(SFTP);
234                connect(sftp, timeout);
235                return sftp;
236        }
237
238        protected void connect(Channel channel, Integer timeout) throws JSchException {
239                if (timeout == null) {
240                        channel.connect();
241                } else {
242                        channel.connect(timeout);
243                }
244        }
245
246        protected void closeQuietly(Session session) {
247                if (session != null) {
248                        session.disconnect();
249                }
250        }
251
252        protected void closeQuietly(Channel channel) {
253                if (channel != null) {
254                        channel.disconnect();
255                }
256        }
257
258        @Deprecated
259        protected Properties getSessionProperties(Properties options, boolean strictHostKeyChecking) {
260                Properties properties = new Properties();
261                if (options != null) {
262                        properties.putAll(options);
263                }
264                if (!strictHostKeyChecking) {
265                        properties.setProperty(SSHUtils.STRICT_HOST_KEY_CHECKING, SSHUtils.NO);
266                }
267                return properties;
268        }
269
270        protected Session openSession(JSch jsch) throws JSchException {
271                Session session = jsch.getSession(username, hostname, port);
272                session.setConfig(getSessionProperties(options, strictHostKeyChecking));
273                if (connectTimeout == null) {
274                        session.connect();
275                } else {
276                        session.connect(connectTimeout);
277                }
278                return session;
279        }
280
281        protected JSch getJSch() throws JSchException {
282                List<File> uniquePrivateKeyFiles = getUniquePrivateKeyFiles();
283                logger.debug("Located {} private keys on the file system", uniquePrivateKeyFiles.size());
284                JSch jsch = getJSch(uniquePrivateKeyFiles, privateKeyStrings);
285                if (strictHostKeyChecking && knownHosts != null) {
286                        String path = LocationUtils.getCanonicalPath(knownHosts);
287                        jsch.setKnownHosts(path);
288                }
289                return jsch;
290        }
291
292        protected JSch getJSch(List<File> privateKeys, List<String> privateKeyStrings) throws JSchException {
293                JSch jsch = new JSch();
294                for (File privateKey : privateKeys) {
295                        String path = LocationUtils.getCanonicalPath(privateKey);
296                        jsch.addIdentity(path);
297                }
298                int count = 0;
299                for (String privateKeyString : CollectionUtils.toEmptyList(privateKeyStrings)) {
300                        String name = "privateKeyString-" + Integer.toString(count++);
301                        byte[] bytes = Str.getBytes(privateKeyString, encoding);
302                        jsch.addIdentity(name, bytes, null, null);
303                }
304                return jsch;
305        }
306
307        @Deprecated
308        protected List<File> getUniquePrivateKeyFiles() {
309                List<String> paths = new ArrayList<String>();
310                if (privateKeys != null) {
311                        for (File privateKey : privateKeys) {
312                                paths.add(LocationUtils.getCanonicalPath(privateKey));
313                        }
314                }
315                if (useConfigFile) {
316                        for (String path : SSHUtils.getFilenames(config)) {
317                                paths.add(path);
318                        }
319                }
320                if (includeDefaultPrivateKeyLocations) {
321                        for (String path : SSHUtils.PRIVATE_KEY_DEFAULTS) {
322                                paths.add(path);
323                        }
324                }
325                List<String> uniquePaths = CollectionUtils.getUniqueStrings(paths);
326                return SSHUtils.getExistingAndReadable(uniquePaths);
327        }
328
329        @Override
330        public RemoteFile getMetaData(String absolutePath) {
331                Assert.hasLength(absolutePath);
332                RemoteFile file = new RemoteFile();
333                file.setAbsolutePath(absolutePath);
334                fillInAttributes(file, absolutePath);
335                return file;
336        }
337
338        @Override
339        public void deleteFile(String absolutePath) {
340                RemoteFile file = getMetaData(absolutePath);
341                if (isStatus(file, Status.MISSING)) {
342                        return;
343                }
344                if (file.isDirectory()) {
345                        throw new IllegalArgumentException("[" + ChannelUtils.getLocation(username, hostname, file) + "] is a directory.");
346                }
347                try {
348                        sftp.rm(absolutePath);
349                } catch (SftpException e) {
350                        throw new IllegalStateException(e);
351                }
352        }
353
354        @Override
355        public boolean exists(String absolutePath) {
356                RemoteFile file = getMetaData(absolutePath);
357                return isStatus(file, Status.EXISTS);
358        }
359
360        @Override
361        public boolean isDirectory(String absolutePath) {
362                RemoteFile file = getMetaData(absolutePath);
363                return isStatus(file, Status.EXISTS) && file.isDirectory();
364        }
365
366        protected void fillInAttributes(RemoteFile file) {
367                fillInAttributes(file, file.getAbsolutePath());
368        }
369
370        protected void fillInAttributes(RemoteFile file, String path) {
371                try {
372                        SftpATTRS attributes = sftp.stat(path);
373                        fillInAttributes(file, attributes);
374                } catch (SftpException e) {
375                        handleNoSuchFileException(file, e);
376                }
377        }
378
379        protected void fillInAttributes(RemoteFile file, SftpATTRS attributes) {
380                file.setDirectory(attributes.isDir());
381                file.setPermissions(attributes.getPermissions());
382                file.setUserId(attributes.getUId());
383                file.setGroupId(attributes.getGId());
384                file.setSize(attributes.getSize());
385                file.setStatus(Status.EXISTS);
386        }
387
388        @Override
389        public void copyFile(File source, RemoteFile destination) {
390                Assert.notNull(source);
391                Assert.isTrue(source.exists());
392                Assert.isTrue(!source.isDirectory());
393                Assert.isTrue(source.canRead());
394                copyLocationToFile(LocationUtils.getCanonicalURLString(source), destination);
395        }
396
397        @Override
398        public void copyFileToDirectory(File source, RemoteFile destination) {
399                RemoteFile clone = clone(destination);
400                String filename = source.getName();
401                addFilenameToPath(clone, filename);
402                copyFile(source, clone);
403        }
404
405        protected RemoteFile clone(RemoteFile file) {
406                try {
407                        RemoteFile clone = new RemoteFile();
408                        BeanUtils.copyProperties(clone, file);
409                        return clone;
410                } catch (IllegalAccessException e) {
411                        throw new IllegalStateException(e);
412                } catch (InvocationTargetException e) {
413                        throw new IllegalStateException(e);
414                }
415        }
416
417        @Override
418        public void copyLocationToFile(String location, RemoteFile destination) {
419                Assert.notNull(location);
420                Assert.isTrue(LocationUtils.exists(location), location + " does not exist");
421                InputStream in = null;
422                try {
423                        in = LocationUtils.getInputStream(location);
424                        copyInputStreamToFile(in, destination);
425                } catch (Exception e) {
426                        throw new IllegalStateException(e);
427                } finally {
428                        IOUtils.closeQuietly(in);
429                }
430        }
431
432        @Override
433        public void copyStringToFile(String string, RemoteFile destination) {
434                Assert.notNull(string);
435                Assert.notBlank(encoding);
436                InputStream in = new ByteArrayInputStream(Str.getBytes(string, encoding));
437                copyInputStreamToFile(in, destination);
438                IOUtils.closeQuietly(in);
439        }
440
441        @Override
442        public String toString(RemoteFile source) {
443                Assert.notNull(source);
444                Assert.hasText(source.getAbsolutePath());
445                Assert.notBlank(encoding);
446                ByteArrayOutputStream out = new ByteArrayOutputStream();
447                try {
448                        copyFile(source, out);
449                        return out.toString(encoding);
450                } catch (IOException e) {
451                        throw new IllegalStateException("Unexpected IO error", e);
452                } finally {
453                        IOUtils.closeQuietly(out);
454                }
455        }
456
457        @Override
458        public void copyInputStreamToFile(InputStream source, RemoteFile destination) {
459                Assert.notNull(source);
460                try {
461                        createDirectories(destination);
462                        sftp.put(source, destination.getAbsolutePath());
463                } catch (SftpException e) {
464                        throw new IllegalStateException(e);
465                }
466        }
467
468        protected String getAbsolutePath(String absolutePath, String filename) {
469                if (StringUtils.endsWith(absolutePath, FORWARDSLASH)) {
470                        return absolutePath + filename;
471                } else {
472                        return absolutePath + FORWARDSLASH + filename;
473                }
474        }
475
476        protected void addFilenameToPath(RemoteFile destination, String filename) {
477                String newAbsolutePath = getAbsolutePath(destination.getAbsolutePath(), filename);
478                destination.setAbsolutePath(newAbsolutePath);
479                destination.setDirectory(false);
480        }
481
482        @Override
483        public void copyLocationToDirectory(String location, RemoteFile destination) {
484                RemoteFile clone = clone(destination);
485                String filename = LocationUtils.getFilename(location);
486                addFilenameToPath(clone, filename);
487                copyLocationToFile(location, clone);
488        }
489
490        @Override
491        public void copyFile(RemoteFile source, File destination) {
492                OutputStream out = null;
493                try {
494                        out = new BufferedOutputStream(FileUtils.openOutputStream(destination));
495                        copyFile(source, out);
496                } catch (Exception e) {
497                        throw new IllegalStateException(e);
498                } finally {
499                        IOUtils.closeQuietly(out);
500                }
501        }
502
503        @Override
504        public void copyRemoteFile(String absolutePath, OutputStream out) throws IOException {
505                try {
506                        sftp.get(absolutePath, out);
507                } catch (SftpException e) {
508                        throw new IOException("Unexpected IO error", e);
509                }
510        }
511
512        @Override
513        public void copyFile(RemoteFile source, OutputStream out) throws IOException {
514                copyRemoteFile(source.getAbsolutePath(), out);
515        }
516
517        @Override
518        public void copyFileToDirectory(RemoteFile source, File destination) {
519                String filename = FilenameUtils.getName(source.getAbsolutePath());
520                File newDestination = new File(destination, filename);
521                copyFile(source, newDestination);
522        }
523
524        @Override
525        public void createDirectory(RemoteFile dir) {
526                Assert.isTrue(dir.isDirectory());
527                try {
528                        createDirectories(dir);
529                } catch (SftpException e) {
530                        throw new IllegalStateException(e);
531                }
532        }
533
534        protected void createDirectories(RemoteFile file) throws SftpException {
535                boolean directoryIndicator = file.isDirectory();
536                fillInAttributes(file);
537                validate(file, directoryIndicator);
538                List<String> directories = LocationUtils.getNormalizedPathFragments(file.getAbsolutePath(), file.isDirectory());
539                for (String directory : directories) {
540                        RemoteFile parentDir = new RemoteFile(directory);
541                        fillInAttributes(parentDir);
542                        validate(parentDir, true);
543                        if (!isStatus(parentDir, Status.EXISTS)) {
544                                mkdir(parentDir);
545                        }
546                }
547        }
548
549        protected boolean isStatus(RemoteFile file, Status status) {
550                return file.getStatus().equals(status);
551        }
552
553        protected void validate(RemoteFile file, Status... allowed) {
554                for (Status status : allowed) {
555                        if (isStatus(file, status)) {
556                                return;
557                        }
558                }
559                throw new IllegalArgumentException("Invalid status - " + file.getStatus());
560        }
561
562        protected boolean validate(RemoteFile file, boolean directoryIndicator) {
563                // Make sure file is not in UNKNOWN status
564                validate(file, Status.MISSING, Status.EXISTS);
565
566                // Convenience flags
567                boolean missing = isStatus(file, Status.MISSING);
568                boolean exists = isStatus(file, Status.EXISTS);
569
570                // Compare the actual file type to the file type it needs to be
571                boolean correctFileType = file.isDirectory() == directoryIndicator;
572
573                // Is everything as it should be?
574                boolean valid = missing || exists && correctFileType;
575                if (valid) {
576                        return true;
577                } else {
578                        // Something has gone awry
579                        throw new IllegalArgumentException(getInvalidExistingFileMessage(file));
580                }
581        }
582
583        protected String getInvalidExistingFileMessage(RemoteFile existing) {
584                if (existing.isDirectory()) {
585                        return "[" + ChannelUtils.getLocation(username, hostname, existing) + "] is an existing directory. Unable to create file.";
586                } else {
587                        return "[" + ChannelUtils.getLocation(username, hostname, existing) + "] is an existing file. Unable to create directory.";
588                }
589        }
590
591        protected void mkdir(RemoteFile dir) {
592                try {
593                        String path = dir.getAbsolutePath();
594                        logger.debug("Creating [{}]", path);
595                        sftp.mkdir(path);
596                        setAttributes(dir);
597                } catch (SftpException e) {
598                        throw new IllegalStateException(e);
599                }
600        }
601
602        protected void setAttributes(RemoteFile file) throws SftpException {
603                String path = file.getAbsolutePath();
604                if (file.getPermissions() != null) {
605                        sftp.chmod(file.getPermissions(), path);
606                }
607                if (file.getGroupId() != null) {
608                        sftp.chgrp(file.getGroupId(), path);
609                }
610                if (file.getUserId() != null) {
611                        sftp.chown(file.getUserId(), path);
612                }
613        }
614
615        protected void handleNoSuchFileException(RemoteFile file, SftpException e) {
616                if (isNoSuchFileException(e)) {
617                        file.setStatus(Status.MISSING);
618                } else {
619                        throw new IllegalStateException(e);
620                }
621        }
622
623        protected boolean isNoSuchFileException(SftpException exception) {
624                return exception.id == ChannelSftp.SSH_FX_NO_SUCH_FILE;
625        }
626
627        public File getKnownHosts() {
628                return knownHosts;
629        }
630
631        public void setKnownHosts(File knownHosts) {
632                this.knownHosts = knownHosts;
633        }
634
635        public File getConfig() {
636                return config;
637        }
638
639        public void setConfig(File config) {
640                this.config = config;
641        }
642
643        public boolean isIncludeDefaultPrivateKeyLocations() {
644                return includeDefaultPrivateKeyLocations;
645        }
646
647        public void setIncludeDefaultPrivateKeyLocations(boolean includeDefaultPrivateKeyLocations) {
648                this.includeDefaultPrivateKeyLocations = includeDefaultPrivateKeyLocations;
649        }
650
651        public boolean isStrictHostKeyChecking() {
652                return strictHostKeyChecking;
653        }
654
655        public void setStrictHostKeyChecking(boolean strictHostKeyChecking) {
656                this.strictHostKeyChecking = strictHostKeyChecking;
657        }
658
659        public String getUsername() {
660                return username;
661        }
662
663        public void setUsername(String username) {
664                this.username = username;
665        }
666
667        public String getHostname() {
668                return hostname;
669        }
670
671        public void setHostname(String hostname) {
672                this.hostname = hostname;
673        }
674
675        public int getPort() {
676                return port;
677        }
678
679        public void setPort(int port) {
680                this.port = port;
681        }
682
683        public int getConnectTimeout() {
684                return connectTimeout;
685        }
686
687        public void setConnectTimeout(int connectTimeout) {
688                this.connectTimeout = connectTimeout;
689        }
690
691        public List<File> getPrivateKeys() {
692                return privateKeys;
693        }
694
695        public void setPrivateKeys(List<File> privateKeys) {
696                this.privateKeys = privateKeys;
697        }
698
699        public Properties getOptions() {
700                return options;
701        }
702
703        public void setOptions(Properties options) {
704                this.options = options;
705        }
706
707        public void setConnectTimeout(Integer connectTimeout) {
708                this.connectTimeout = connectTimeout;
709        }
710
711        public int getWaitForClosedSleepMillis() {
712                return waitForClosedSleepMillis;
713        }
714
715        public void setWaitForClosedSleepMillis(int waitForClosedSleepMillis) {
716                this.waitForClosedSleepMillis = waitForClosedSleepMillis;
717        }
718
719        public String getEncoding() {
720                return encoding;
721        }
722
723        public void setEncoding(String encoding) {
724                this.encoding = encoding;
725        }
726
727        public List<String> getPrivateKeyStrings() {
728                return privateKeyStrings;
729        }
730
731        public void setPrivateKeyStrings(List<String> privateKeyStrings) {
732                this.privateKeyStrings = privateKeyStrings;
733        }
734
735        public boolean isUseConfigFile() {
736                return useConfigFile;
737        }
738
739        public void setUseConfigFile(boolean useConfigFile) {
740                this.useConfigFile = useConfigFile;
741        }
742
743}