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 }