1 package org.codehaus.mojo.jaxb2.shared.environment.sysprops;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.maven.plugin.logging.Log;
23 import org.codehaus.mojo.jaxb2.AbstractJaxbMojo;
24 import org.codehaus.mojo.jaxb2.shared.Validate;
25 import org.codehaus.mojo.jaxb2.shared.environment.AbstractLogAwareFacet;
26
27 import java.util.ArrayList;
28 import java.util.List;
29
30 /**
31 * EnvironmentFacet which changes the value of a system property for the duration
32 * of executing a tool. This is required for tools (such as the JDK SchemaGen) which
33 * relies on environment or system properties being set for their execution.
34 * This faced accepts one key and two values (original/new values).
35 *
36 * @author <a href="mailto:lj@jguru.se">Lennart Jörelid</a>, jGuru Europe AB
37 * @since 2.1
38 */
39 public final class SystemPropertyChangeEnvironmentFacet extends AbstractLogAwareFacet {
40
41 /**
42 * Operation definitions indicating how a System property should be changed by this EnvironmentFacet.
43 */
44 public enum ChangeType {
45
46 /**
47 * Indicates that a System property should be added during {@code setup()}
48 * and removed during {@code restore()}. If the property was already present,
49 * this behaves like {@code #CHANGE}.
50 */
51 ADD,
52
53 /**
54 * Indicates that a System property should be removed during {@code setup()}
55 * and restored/re-added during {@code restore()}
56 */
57 REMOVE,
58
59 /**
60 * Indicates that a System property should be altered during {@code setup()}
61 * and restored during {@code restore()}
62 */
63 CHANGE
64 }
65
66 // Internal state
67 private ChangeType type;
68 private String key;
69 private String newValue;
70 private String originalValue;
71
72 /**
73 * Creates a SystemPropertyChange which will remove the supplied system property for the
74 * duration of this SystemPropertyChange. No exception will be thrown if the supplied System property
75 * key is not found in the present System.properties.
76 *
77 * @param log The active Maven Log.
78 * @param key A non-null key.
79 * @see SystemPropertyChangeEnvironmentFacet.ChangeType#REMOVE
80 */
81 private SystemPropertyChangeEnvironmentFacet(final Log log, final String key) {
82
83 // Delegate
84 super(log);
85
86 // Assign internal state
87 this.key = key;
88 this.type = ChangeType.REMOVE;
89 }
90
91 /**
92 * Creates a SystemPropertyChange which stores the current
93 *
94 * @param log The active Maven Log.
95 * @param key The key of the System property managed by this SystemPropertyChange.
96 * @param newValue The new value of this SystemPropertyChange.
97 */
98 private SystemPropertyChangeEnvironmentFacet(final Log log, final String key, final String newValue) {
99
100 // Delegate
101 super(log);
102
103 // Assign internal state
104 this.key = key;
105 this.originalValue = System.getProperty(key);
106 this.newValue = newValue;
107 this.type = existsAsSystemProperty(key) ? ChangeType.CHANGE : ChangeType.ADD;
108 }
109
110 /**
111 * {@inheritDoc}
112 */
113 @Override
114 public void setup() {
115
116 if (type == ChangeType.REMOVE) {
117 System.clearProperty(key);
118 } else {
119 System.setProperty(key, newValue);
120 }
121
122 if (log.isDebugEnabled()) {
123 log.debug("Setup " + toString());
124 }
125 }
126
127 /**
128 * {@inheritDoc}
129 */
130 @Override
131 public void restore() {
132
133 if (type == ChangeType.ADD) {
134 System.clearProperty(key);
135 } else {
136 System.setProperty(key, originalValue);
137 }
138
139 if (log.isDebugEnabled()) {
140 log.debug("Restored " + toString());
141 }
142 }
143
144 /**
145 * @return A Debug string representation of this SystemPropertyChangeEnvironmentFacet.
146 */
147 @Override
148 public String toString() {
149 final String toReturn = "SysProp key [" + key + "]\n"
150 + " ... Original value: [" + originalValue + "]\n"
151 + " ... Changed value : [" + newValue + "]";
152 return toReturn.replace("\n", AbstractJaxbMojo.NEWLINE);
153 }
154
155 /**
156 * Creates a SystemPropertyChangesBuilder which uses the supplied active Maven Log.
157 *
158 * @param mavenLog The active Maven Log to be used by all SystemPropertyChange objects created
159 * by this SystemPropertyChangesBuilder.
160 * @return A SystemPropertyChangesBuilder ready for use.
161 */
162 public static SystemPropertyChangesBuilder getBuilder(final Log mavenLog) {
163 return new SystemPropertyChangesBuilder(mavenLog);
164 }
165
166 /**
167 * Builder class intended to simplify creating SystemPropertyChange EnvironmentFacets.
168 */
169 public static class SystemPropertyChangesBuilder {
170
171 // Internal state
172 private List<SystemPropertyChangeEnvironmentFacet> toReturn;
173 private Log mavenLog;
174
175 private SystemPropertyChangesBuilder(final Log mavenLog) {
176
177 // Check sanity
178 Validate.notNull(mavenLog, "mavenLog");
179
180 // Assign internal state
181 this.toReturn = new ArrayList<SystemPropertyChangeEnvironmentFacet>();
182 this.mavenLog = mavenLog;
183 }
184
185 /**
186 * Adds a SystemPropertyChange which removes the named System property.
187 *
188 * @param propertyName The name of the system property for which to create a REMOVE-type SystemPropertyChange.
189 * @return This builder, for chaining.
190 * @see SystemPropertyChangeEnvironmentFacet.ChangeType#REMOVE
191 */
192 public SystemPropertyChangesBuilder remove(final String propertyName) {
193
194 // Check sanity
195 checkSanity(propertyName);
196
197 // Add the SystemPropertyChange.
198 toReturn.add(new SystemPropertyChangeEnvironmentFacet(mavenLog, propertyName));
199
200 // All done.
201 return this;
202 }
203
204 /**
205 * Adds a SystemPropertyChange which adds or changes the named System property.
206 *
207 * @param propertyName The name of the system property for which to create an
208 * ADD- or CREATE-type SystemPropertyChange.
209 * @param value The new value of the system property to set.
210 * @return This builder, for chaining.
211 * @see SystemPropertyChangeEnvironmentFacet.ChangeType#ADD
212 * @see SystemPropertyChangeEnvironmentFacet.ChangeType#CHANGE
213 */
214 public SystemPropertyChangesBuilder addOrChange(final String propertyName, final String value) {
215
216 // Check sanity
217 checkSanity(propertyName);
218
219 // Add the SystemPropertyChange.
220 toReturn.add(new SystemPropertyChangeEnvironmentFacet(mavenLog, propertyName, value));
221
222 // All done.
223 return this;
224 }
225
226 /**
227 * @return A List of SystemPropertyChange EnvironmentFacets which can be included as required into the
228 * ToolExecutionEnvironment.
229 */
230 public List<SystemPropertyChangeEnvironmentFacet> build() {
231 return toReturn;
232 }
233
234 //
235 // Private helpers
236 //
237
238 private void checkSanity(final String propertyName) {
239
240 // Check sanity
241 Validate.notEmpty(propertyName, "propertyName");
242
243 // Validate that the property name is not already present as a SystemPropertyChange.
244 for (SystemPropertyChangeEnvironmentFacet current : toReturn) {
245 if (current.key.equals(propertyName)) {
246 throw new IllegalArgumentException("A SystemPropertyChange for propertyName '"
247 + propertyName + "' is already present. Only one SystemPropertyChange per propertyName "
248 + "should be supplied.");
249 }
250 }
251 }
252 }
253
254 //
255 // Private helpers
256 //
257
258 private boolean existsAsSystemProperty(final String key) {
259 return System.getProperties().keySet().contains(key);
260 }
261 }