1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.types;
  18. import java.util.Enumeration;
  19. import java.util.Iterator;
  20. import java.util.HashSet;
  21. import java.util.Set;
  22. import java.util.Hashtable;
  23. import java.util.Properties;
  24. import java.util.Stack;
  25. import java.util.Vector;
  26. import org.apache.tools.ant.BuildException;
  27. import org.apache.tools.ant.Project;
  28. import org.apache.tools.ant.PropertyHelper;
  29. import org.apache.tools.ant.util.FileNameMapper;
  30. import org.apache.tools.ant.util.regexp.RegexpMatcher;
  31. import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
  32. /**
  33. * A set of properties.
  34. *
  35. * @since Ant 1.6
  36. */
  37. public class PropertySet extends DataType {
  38. private boolean dynamic = true;
  39. private boolean negate = false;
  40. private Set cachedNames;
  41. private Vector ptyRefs = new Vector();
  42. private Vector setRefs = new Vector();
  43. private Mapper _mapper;
  44. public static class PropertyRef {
  45. private int count;
  46. private String name;
  47. private String regex;
  48. private String prefix;
  49. private String builtin;
  50. public void setName(String name) {
  51. assertValid("name", name);
  52. this.name = name;
  53. }
  54. public void setRegex(String regex) {
  55. assertValid("regex", regex);
  56. this.regex = regex;
  57. }
  58. public void setPrefix(String prefix) {
  59. assertValid("prefix", prefix);
  60. this.prefix = prefix;
  61. }
  62. public void setBuiltin(BuiltinPropertySetName b) {
  63. String builtin = b.getValue();
  64. assertValid("builtin", builtin);
  65. this.builtin = builtin;
  66. }
  67. private void assertValid(String attr, String value) {
  68. if (value == null || value.length() < 1) {
  69. throw new BuildException("Invalid attribute: " + attr);
  70. }
  71. if (++count != 1) {
  72. throw new BuildException("Attributes name, regex, and "
  73. + "prefix are mutually exclusive");
  74. }
  75. }
  76. public String toString() {
  77. return "name=" + name + ", regex=" + regex + ", prefix=" + prefix
  78. + ", builtin=" + builtin;
  79. }
  80. }
  81. public void appendName(String name) {
  82. PropertyRef ref = new PropertyRef();
  83. ref.setName(name);
  84. addPropertyref(ref);
  85. }
  86. public void appendRegex(String regex) {
  87. PropertyRef ref = new PropertyRef();
  88. ref.setRegex(regex);
  89. addPropertyref(ref);
  90. }
  91. public void appendPrefix(String prefix) {
  92. PropertyRef ref = new PropertyRef();
  93. ref.setPrefix(prefix);
  94. addPropertyref(ref);
  95. }
  96. public void appendBuiltin(BuiltinPropertySetName b) {
  97. PropertyRef ref = new PropertyRef();
  98. ref.setBuiltin(b);
  99. addPropertyref(ref);
  100. }
  101. public void setMapper(String type, String from, String to) {
  102. Mapper mapper = createMapper();
  103. Mapper.MapperType mapperType = new Mapper.MapperType();
  104. mapperType.setValue(type);
  105. mapper.setFrom(from);
  106. mapper.setTo(to);
  107. }
  108. public void addPropertyref(PropertyRef ref) {
  109. assertNotReference();
  110. ptyRefs.addElement(ref);
  111. }
  112. public void addPropertyset(PropertySet ref) {
  113. assertNotReference();
  114. setRefs.addElement(ref);
  115. }
  116. public Mapper createMapper() {
  117. assertNotReference();
  118. if (_mapper != null) {
  119. throw new BuildException("Too many <mapper>s!");
  120. }
  121. _mapper = new Mapper(getProject());
  122. return _mapper;
  123. }
  124. public void setDynamic(boolean dynamic) {
  125. assertNotReference();
  126. this.dynamic = dynamic;
  127. }
  128. public void setNegate(boolean negate) {
  129. assertNotReference();
  130. this.negate = negate;
  131. }
  132. public boolean getDynamic() {
  133. return isReference() ? getRef().dynamic : dynamic;
  134. }
  135. public Mapper getMapper() {
  136. return isReference() ? getRef()._mapper : _mapper;
  137. }
  138. public Properties getProperties() {
  139. Set names = null;
  140. Project prj = getProject();
  141. Hashtable props =
  142. prj == null ? System.getProperties() : prj.getProperties();
  143. if (getDynamic() || cachedNames == null) {
  144. names = new HashSet();
  145. if (isReference()) {
  146. getRef().addPropertyNames(names, props);
  147. } else {
  148. addPropertyNames(names, props);
  149. }
  150. // Add this PropertySet's nested PropertySets' property names.
  151. for (Enumeration e = setRefs.elements(); e.hasMoreElements();) {
  152. PropertySet set = (PropertySet) e.nextElement();
  153. names.addAll(set.getProperties().keySet());
  154. }
  155. if (negate) {
  156. //make a copy...
  157. HashSet complement = new HashSet(props.keySet());
  158. complement.removeAll(names);
  159. names = complement;
  160. }
  161. if (!getDynamic()) {
  162. cachedNames = names;
  163. }
  164. } else {
  165. names = cachedNames;
  166. }
  167. FileNameMapper mapper = null;
  168. Mapper myMapper = getMapper();
  169. if (myMapper != null) {
  170. mapper = myMapper.getImplementation();
  171. }
  172. Properties properties = new Properties();
  173. for (Iterator iter = names.iterator(); iter.hasNext();) {
  174. String name = (String) iter.next();
  175. String value = (String) props.get(name);
  176. if (mapper != null) {
  177. String[] newname = mapper.mapFileName(name);
  178. if (newname != null) {
  179. name = newname[0];
  180. }
  181. }
  182. properties.setProperty(name, value);
  183. }
  184. return properties;
  185. }
  186. /**
  187. * @param names the output Set to fill with the property names
  188. * matching this PropertySet selection criteria.
  189. * @param properties the current Project properties, passed in to
  190. * avoid needless duplication of the Hashtable during recursion.
  191. */
  192. private void addPropertyNames(Set names, Hashtable properties) {
  193. Project prj = getProject();
  194. // Add this PropertySet's property names.
  195. for (Enumeration e = ptyRefs.elements(); e.hasMoreElements();) {
  196. PropertyRef ref = (PropertyRef) e.nextElement();
  197. if (ref.name != null) {
  198. if (prj != null && prj.getProperty(ref.name) != null) {
  199. names.add(ref.name);
  200. }
  201. } else if (ref.prefix != null) {
  202. for (Enumeration p = properties.keys(); p.hasMoreElements();) {
  203. String name = (String) p.nextElement();
  204. if (name.startsWith(ref.prefix)) {
  205. names.add(name);
  206. }
  207. }
  208. } else if (ref.regex != null) {
  209. RegexpMatcherFactory matchMaker = new RegexpMatcherFactory();
  210. RegexpMatcher matcher = matchMaker.newRegexpMatcher();
  211. matcher.setPattern(ref.regex);
  212. for (Enumeration p = properties.keys(); p.hasMoreElements();) {
  213. String name = (String) p.nextElement();
  214. if (matcher.matches(name)) {
  215. names.add(name);
  216. }
  217. }
  218. } else if (ref.builtin != null) {
  219. if (ref.builtin.equals(BuiltinPropertySetName.ALL)) {
  220. names.addAll(properties.keySet());
  221. } else if (ref.builtin.equals(BuiltinPropertySetName.SYSTEM)) {
  222. names.addAll(System.getProperties().keySet());
  223. } else if (ref.builtin.equals(BuiltinPropertySetName
  224. .COMMANDLINE)) {
  225. names.addAll(getProject().getUserProperties().keySet());
  226. } else {
  227. throw new BuildException("Impossible: Invalid builtin "
  228. + "attribute!");
  229. }
  230. } else {
  231. throw new BuildException("Impossible: Invalid PropertyRef!");
  232. }
  233. }
  234. }
  235. /**
  236. * Performs the check for circular references and returns the
  237. * referenced FileList.
  238. */
  239. protected PropertySet getRef() {
  240. if (!isChecked()) {
  241. Stack stk = new Stack();
  242. stk.push(this);
  243. dieOnCircularReference(stk, getProject());
  244. }
  245. Object o = getRefid().getReferencedObject(getProject());
  246. if (!(o instanceof PropertySet)) {
  247. String msg = getRefid().getRefId()
  248. + " doesn\'t denote a propertyset";
  249. throw new BuildException(msg);
  250. } else {
  251. return (PropertySet) o;
  252. }
  253. }
  254. /**
  255. * Sets the value of the refid attribute.
  256. *
  257. * @param r the reference this datatype should point to.
  258. * @throws BuildException if another attribute was set, since
  259. * refid and all other attributes are mutually exclusive.
  260. */
  261. public final void setRefid(Reference r) {
  262. if (!noAttributeSet) {
  263. throw tooManyAttributes();
  264. }
  265. super.setRefid(r);
  266. }
  267. /**
  268. * Ensures this data type is not a reference.
  269. *
  270. * <p>Calling this method as the first line of every bean method of
  271. * this data type (setXyz, addXyz, createXyz) ensure proper handling
  272. * of the refid attribute.</p>
  273. *
  274. * @throws BuildException if the refid attribute was already set, since
  275. * refid and all other attributes are mutually exclusive.
  276. */
  277. protected final void assertNotReference() {
  278. if (isReference()) {
  279. throw tooManyAttributes();
  280. }
  281. noAttributeSet = false;
  282. }
  283. private boolean noAttributeSet = true;
  284. /**
  285. * Used for propertyref's builtin attribute.
  286. */
  287. public static class BuiltinPropertySetName extends EnumeratedAttribute {
  288. static final String ALL = "all";
  289. static final String SYSTEM = "system";
  290. static final String COMMANDLINE = "commandline";
  291. public String[] getValues() {
  292. return new String[] {ALL, SYSTEM, COMMANDLINE};
  293. }
  294. }
  295. } // END class PropertySet