mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
20.03.2025 102c67e24a4717d0a2f8cbc37bd660e8bf17b430
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
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2006-2008 Sun Microsystems, Inc.
 * Portions copyright 2014-2016 ForgeRock AS.
 */
package com.forgerock.opendj.cli;
 
import static com.forgerock.opendj.cli.CliMessages.*;
import static com.forgerock.opendj.util.StaticUtils.getExceptionMessage;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
 
import org.forgerock.i18n.LocalizableMessageBuilder;
 
/**
 * This class defines an argument whose value will be read from a file rather
 * than actually specified on the command-line. When a value is specified on the
 * command line, it will be treated as the path to the file containing the
 * actual value rather than the value itself. <BR>
 * <BR>
 * Note that if no filename is provided on the command line but a default
 * value is specified programmatically or if the default value is read from a
 * specified property, then that default value will be taken as the actual value
 * rather than a filename. <BR>
 * <BR>
 * Also note that this argument type assumes that the entire value for the
 * argument is on a single line in the specified file. If the file contains
 * multiple lines, then only the first line will be read.
 */
public final class FileBasedArgument extends Argument {
 
    /**
     * Returns a builder which can be used for incrementally constructing a new
     * {@link FileBasedArgument}.
     *
     * @param longIdentifier
     *         The generic long identifier that will be used to refer to this argument.
     * @return A builder to continue building the {@link FileBasedArgument}.
     */
    public static Builder builder(final String longIdentifier) {
        return new Builder(longIdentifier);
    }
 
    /** A fluent API for incrementally constructing {@link FileBasedArgument}. */
    public static final class Builder extends ArgumentBuilder<Builder, String, FileBasedArgument> {
        private Builder(final String longIdentifier) {
            super(longIdentifier);
        }
 
        @Override
        Builder getThis() {
            return this;
        }
 
        @Override
        public FileBasedArgument buildArgument() throws ArgumentException {
            return new FileBasedArgument(this);
        }
    }
 
    /** The mapping between filenames specified and the first lines read from those files. */
    private final Map<String, String> namesToValues = new LinkedHashMap<>();
 
    private FileBasedArgument(final Builder builder) throws ArgumentException {
        super(builder);
    }
 
    /**
     * Adds a value to the set of values for this argument. This should only be
     * called if the value is allowed by the <CODE>valueIsAcceptable</CODE>
     * method. Note that in this case, correct behavior depends on a previous
     * successful call to <CODE>valueIsAcceptable</CODE> so that the value read
     * from the file may be stored in the name-to-value hash and used in place
     * of the filename here.
     *
     * @param valueString
     *            The string representation of the value to add to this
     *            argument.
     */
    @Override
    public void addValue(final String valueString) {
        final String actualValue = namesToValues.get(valueString);
        if (actualValue != null) {
            super.addValue(actualValue);
        }
    }
 
    /**
     * Retrieves a map between the filenames specified on the command line and
     * the first lines read from those files.
     *
     * @return A map between the filenames specified on the command line and the
     *         first lines read from those files.
     */
    public Map<String, String> getNameToValueMap() {
        return namesToValues;
    }
 
    /**
     * Indicates whether the provided value is acceptable for use in this
     * argument.
     *
     * @param valueString
     *            The value for which to make the determination.
     * @param invalidReason
     *            A buffer into which the invalid reason may be written if the
     *            value is not acceptable.
     * @return <CODE>true</CODE> if the value is acceptable, or
     *         <CODE>false</CODE> if it is not.
     */
    @Override
    public boolean valueIsAcceptable(final String valueString,
            final LocalizableMessageBuilder invalidReason) {
        // First, make sure that the specified file exists.
        File valueFile;
        try {
            valueFile = new File(valueString);
            if (!valueFile.exists()) {
                invalidReason.append(ERR_FILEARG_NO_SUCH_FILE.get(valueString, longIdentifier));
                return false;
            }
        } catch (final Exception e) {
            invalidReason.append(ERR_FILEARG_CANNOT_VERIFY_FILE_EXISTENCE.get(
                    valueString, longIdentifier, getExceptionMessage(e)));
            return false;
        }
 
        // Open the file, read the first line and close the file.
        String line;
        try (BufferedReader reader = new BufferedReader(new FileReader(valueFile))) {
            line = reader.readLine();
        } catch (final FileNotFoundException e) {
            invalidReason.append(ERR_FILEARG_CANNOT_OPEN_FILE.get(valueString, longIdentifier, getExceptionMessage(e)));
            return false;
        } catch (final IOException e) {
            invalidReason.append(ERR_FILEARG_CANNOT_READ_FILE.get(valueString, longIdentifier, getExceptionMessage(e)));
            return false;
        }
 
        // If the line read is null, then that means the file was empty.
        if (line == null) {
            invalidReason.append(ERR_FILEARG_EMPTY_FILE.get(valueString, longIdentifier));
            return false;
        }
 
        // Store the value in the hash so it will be available for addValue.
        // We won't do any validation on the value itself, so anything that we
        // read will be considered acceptable.
        namesToValues.put(valueString, line);
        return true;
    }
}