1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.maven.plugins.invoker;
20
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.Set;
25
26 import org.apache.maven.project.MavenProject;
27 import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
28
29 /**
30 * A map-like source to interpolate expressions.
31 *
32 * @author Olivier Lamy
33 * @since 1.1
34 */
35 class CompositeMap implements Map<String, Object> {
36
37 /**
38 * The Maven project from which to extract interpolated values, never <code>null</code>.
39 */
40 private MavenProject mavenProject;
41
42 /**
43 * The set of additional properties from which to extract interpolated values, never <code>null</code>.
44 */
45 private Map<String, Object> properties;
46
47 /**
48 * Flag indicating to escape XML special characters.
49 */
50 private final boolean escapeXml;
51
52 /**
53 * Creates a new interpolation source backed by the specified Maven project and some user-specified properties.
54 *
55 * @param mavenProject The Maven project from which to extract interpolated values, must not be <code>null</code>.
56 * @param properties The set of additional properties from which to extract interpolated values, may be
57 * <code>null</code>.
58 * @param escapeXml {@code true}, to escape any XML special characters; {@code false}, to not perform any escaping.
59 */
60 protected CompositeMap(MavenProject mavenProject, Map<String, Object> properties, boolean escapeXml) {
61 if (mavenProject == null) {
62 throw new IllegalArgumentException("no project specified");
63 }
64 this.mavenProject = mavenProject;
65 this.properties = properties == null ? new HashMap<String, Object>() : properties;
66 this.escapeXml = escapeXml;
67 }
68
69 /**
70 * {@inheritDoc}
71 *
72 * @see java.util.Map#clear()
73 */
74 public void clear() {
75 // nothing here
76 }
77
78 /**
79 * {@inheritDoc}
80 *
81 * @see java.util.Map#containsKey(java.lang.Object)
82 */
83 public boolean containsKey(Object key) {
84 if (!(key instanceof String)) {
85 return false;
86 }
87
88 String expression = (String) key;
89 if (expression.startsWith("project.") || expression.startsWith("pom.")) {
90 try {
91 Object evaluated = ReflectionValueExtractor.evaluate(expression, this.mavenProject);
92 if (evaluated != null) {
93 return true;
94 }
95 } catch (Exception e) {
96 // uhm do we have to throw a RuntimeException here ?
97 }
98 }
99
100 return properties.containsKey(key) || mavenProject.getProperties().containsKey(key);
101 }
102
103 /**
104 * {@inheritDoc}
105 *
106 * @see java.util.Map#containsValue(java.lang.Object)
107 */
108 public boolean containsValue(Object value) {
109 throw new UnsupportedOperationException();
110 }
111
112 /**
113 * {@inheritDoc}
114 *
115 * @see java.util.Map#entrySet()
116 */
117 public Set<Entry<String, Object>> entrySet() {
118 throw new UnsupportedOperationException();
119 }
120
121 /**
122 * {@inheritDoc}
123 *
124 * @see java.util.Map#get(java.lang.Object)
125 */
126 public Object get(Object key) {
127 if (!(key instanceof String)) {
128 return null;
129 }
130
131 Object value = null;
132 String expression = (String) key;
133 if (expression.startsWith("project.") || expression.startsWith("pom.")) {
134 try {
135 Object evaluated = ReflectionValueExtractor.evaluate(expression, this.mavenProject);
136 if (evaluated != null) {
137 value = evaluated;
138 }
139 } catch (Exception e) {
140 // uhm do we have to throw a RuntimeException here ?
141 }
142 }
143
144 if (value == null) {
145 value = properties.get(key);
146 }
147
148 if (value == null) {
149 value = this.mavenProject.getProperties().get(key);
150 }
151
152 if (value != null && this.escapeXml) {
153 value = value.toString()
154 .replaceAll("\"", """)
155 .replaceAll("<", "<")
156 .replaceAll(">", ">")
157 .replaceAll("&", "&");
158 }
159
160 return value;
161 }
162
163 /**
164 * {@inheritDoc}
165 *
166 * @see java.util.Map#isEmpty()
167 */
168 public boolean isEmpty() {
169 return this.mavenProject.getProperties().isEmpty() && this.properties.isEmpty();
170 }
171
172 /**
173 * {@inheritDoc}
174 *
175 * @see java.util.Map#keySet()
176 */
177 public Set<String> keySet() {
178 throw new UnsupportedOperationException();
179 }
180
181 /**
182 * {@inheritDoc}
183 *
184 * @see java.util.Map#put(java.lang.Object, java.lang.Object)
185 */
186 public Object put(String key, Object value) {
187 throw new UnsupportedOperationException();
188 }
189
190 /**
191 * {@inheritDoc}
192 *
193 * @see java.util.Map#putAll(java.util.Map)
194 */
195 public void putAll(Map<? extends String, ? extends Object> t) {
196 throw new UnsupportedOperationException();
197 }
198
199 /**
200 * {@inheritDoc}
201 *
202 * @see java.util.Map#remove(java.lang.Object)
203 */
204 public Object remove(Object key) {
205 throw new UnsupportedOperationException();
206 }
207
208 /**
209 * {@inheritDoc}
210 *
211 * @see java.util.Map#size()
212 */
213 public int size() {
214 throw new UnsupportedOperationException();
215 }
216
217 /**
218 * {@inheritDoc}
219 *
220 * @see java.util.Map#values()
221 */
222 public Collection<Object> values() {
223 throw new UnsupportedOperationException();
224 }
225 }