1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * 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, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.geronimo.system.configuration;
19
20 import java.beans.PropertyEditor;
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.io.StringWriter;
24 import java.io.Serializable;
25 import java.io.StringReader;
26 import java.net.URI;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.LinkedHashMap;
32 import java.util.LinkedHashSet;
33 import java.util.Map;
34 import java.util.Set;
35
36 import javax.xml.parsers.DocumentBuilderFactory;
37 import javax.xml.parsers.DocumentBuilder;
38
39 import org.apache.geronimo.common.propertyeditor.PropertyEditors;
40 import org.apache.geronimo.gbean.AbstractName;
41 import org.apache.geronimo.gbean.AbstractNameQuery;
42 import org.apache.geronimo.gbean.GAttributeInfo;
43 import org.apache.geronimo.gbean.GBeanData;
44 import org.apache.geronimo.gbean.GBeanInfo;
45 import org.apache.geronimo.gbean.ReferencePatterns;
46 import org.apache.geronimo.kernel.InvalidGBeanException;
47 import org.apache.geronimo.kernel.util.XmlUtil;
48 import org.apache.geronimo.kernel.repository.Artifact;
49 import org.apache.geronimo.util.EncryptionManager;
50 import org.w3c.dom.Element;
51 import org.w3c.dom.Node;
52 import org.w3c.dom.NodeList;
53 import org.w3c.dom.Document;
54 import org.xml.sax.InputSource;
55
56 /**
57 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
58 */
59 public class GBeanOverride implements Serializable {
60 private final Object name;
61 private boolean load;
62 private final Map attributes = new LinkedHashMap();
63 private final Map references = new LinkedHashMap();
64 private final ArrayList clearAttributes = new ArrayList();
65 private final ArrayList nullAttributes = new ArrayList();
66 private final ArrayList clearReferences = new ArrayList();
67 private final String gbeanInfo;
68
69 public GBeanOverride(String name, boolean load) {
70 this.name = name;
71 this.load = load;
72 gbeanInfo = null;
73 }
74
75 public GBeanOverride(AbstractName name, boolean load) {
76 this.name = name;
77 this.load = load;
78 gbeanInfo = null;
79 }
80
81 public GBeanOverride(GBeanData gbeanData) throws InvalidAttributeException {
82 GBeanInfo gbeanInfo = gbeanData.getGBeanInfo();
83 this.gbeanInfo = gbeanInfo.getSourceClass();
84 if (this.gbeanInfo == null) {
85 throw new IllegalArgumentException("GBeanInfo must have a source class set");
86 }
87 name = gbeanData.getAbstractName();
88 load = true;
89
90
91 for (Iterator iterator = gbeanData.getAttributes().entrySet().iterator(); iterator.hasNext();) {
92 Map.Entry entry = (Map.Entry) iterator.next();
93 String attributeName = (String) entry.getKey();
94 GAttributeInfo attributeInfo = gbeanInfo.getAttribute(attributeName);
95 if (attributeInfo == null) {
96 throw new InvalidAttributeException("No attribute: " + attributeName + " for gbean: " + gbeanData.getAbstractName());
97 }
98 Object attributeValue = entry.getValue();
99 setAttribute(attributeName, attributeValue, attributeInfo.getType());
100 }
101
102
103 references.putAll(gbeanData.getReferences());
104 }
105
106 public GBeanOverride(Element gbean) throws InvalidGBeanException {
107 String nameString = gbean.getAttribute("name");
108 if (nameString.indexOf('?') > -1) {
109 name = new AbstractName(URI.create(nameString));
110 } else {
111 name = nameString;
112 }
113
114 String gbeanInfoString = gbean.getAttribute("gbeanInfo");
115 if (gbeanInfoString.length() > 0) {
116 gbeanInfo = gbeanInfoString;
117 } else {
118 gbeanInfo = null;
119 }
120 if (gbeanInfo != null && !(name instanceof AbstractName)) {
121 throw new InvalidGBeanException("A gbean element using the gbeanInfo attribute must be specified using a full AbstractName: name=" + nameString);
122 }
123
124 String loadString = gbean.getAttribute("load");
125 load = !"false".equals(loadString);
126
127
128 NodeList attributes = gbean.getElementsByTagName("attribute");
129 for (int a = 0; a < attributes.getLength(); a++) {
130 Element attribute = (Element) attributes.item(a);
131
132 String attributeName = attribute.getAttribute("name");
133
134
135 if (attribute.hasAttribute("value")) {
136 setAttribute(attributeName, (String) EncryptionManager.decrypt(attribute.getAttribute("value")));
137 continue;
138 }
139
140
141 if (attribute.hasAttribute("null")) {
142 String nullString = attribute.getAttribute("null");
143 if (nullString.equals("true")) {
144 setNullAttribute(attributeName);
145 continue;
146 }
147 }
148
149 String rawAttribute = getContentsAsText(attribute);
150
151 if (rawAttribute.length() == 0) {
152 setClearAttribute(attributeName);
153 continue;
154 }
155 String attributeValue = (String) EncryptionManager.decrypt(rawAttribute);
156
157 setAttribute(attributeName, attributeValue);
158 }
159
160
161 NodeList references = gbean.getElementsByTagName("reference");
162 for (int r = 0; r < references.getLength(); r++) {
163 Element reference = (Element) references.item(r);
164
165 String referenceName = reference.getAttribute("name");
166
167 Set objectNamePatterns = new LinkedHashSet();
168 NodeList patterns = reference.getElementsByTagName("pattern");
169
170
171
172 if (patterns.getLength() == 0) {
173 setClearReference(referenceName);
174 continue;
175 }
176
177 for (int p = 0; p < patterns.getLength(); p++) {
178 Element pattern = (Element) patterns.item(p);
179 if (pattern == null)
180 continue;
181
182 String groupId = getChildAsText(pattern, "groupId");
183 String artifactId = getChildAsText(pattern, "artifactId");
184 String version = getChildAsText(pattern, "version");
185 String type = getChildAsText(pattern, "type");
186 String module = getChildAsText(pattern, "module");
187 String name = getChildAsText(pattern, "name");
188
189 Artifact referenceArtifact = null;
190 if (artifactId != null) {
191 referenceArtifact = new Artifact(groupId, artifactId, version, type);
192 }
193 Map nameMap = new HashMap();
194 if (module != null) {
195 nameMap.put("module", module);
196 }
197 if (name != null) {
198 nameMap.put("name", name);
199 }
200 AbstractNameQuery abstractNameQuery = new AbstractNameQuery(referenceArtifact, nameMap, Collections.EMPTY_SET);
201 objectNamePatterns.add(abstractNameQuery);
202 }
203
204 setReferencePatterns(referenceName, new ReferencePatterns(objectNamePatterns));
205 }
206 }
207
208 private static String getChildAsText(Element element, String name) throws InvalidGBeanException {
209 NodeList children = element.getElementsByTagName(name);
210 if (children == null || children.getLength() == 0) {
211 return null;
212 }
213 if (children.getLength() > 1) {
214 throw new InvalidGBeanException("invalid name, too many parts named: " + name);
215 }
216 return getContentsAsText((Element) children.item(0));
217 }
218
219 private static String getContentsAsText(Element element) throws InvalidGBeanException {
220 String value = "";
221 NodeList text = element.getChildNodes();
222 for (int t = 0; t < text.getLength(); t++) {
223 Node n = text.item(t);
224 if (n.getNodeType() == Node.TEXT_NODE) {
225 value += n.getNodeValue();
226 } else {
227 StringWriter sw = new StringWriter();
228 PrintWriter pw = new PrintWriter(sw);
229 OutputFormat of = new OutputFormat(Method.XML, null, false);
230 of.setOmitXMLDeclaration(true);
231 XMLSerializer serializer = new XMLSerializer(pw, of);
232 try {
233 serializer.prepare();
234 serializer.serializeNode(n);
235 value += sw.toString();
236 } catch (IOException ioe) {
237 throw new InvalidGBeanException("Error serializing GBean element", ioe);
238 }
239 }
240 }
241 return value.trim();
242 }
243
244 public Object getName() {
245 return name;
246 }
247
248 public String getGBeanInfo() {
249 return gbeanInfo;
250 }
251
252 public boolean isLoad() {
253 return load;
254 }
255
256 public void setLoad(boolean load) {
257 this.load = load;
258 }
259
260 public Map getAttributes() {
261 return attributes;
262 }
263
264 public String getAttribute(String attributeName) {
265 return (String) attributes.get(attributeName);
266 }
267
268 public ArrayList getClearAttributes() {
269 return clearAttributes;
270 }
271
272 public ArrayList getNullAttributes() {
273 return nullAttributes;
274 }
275
276 public boolean getNullAttribute(String attributeName) {
277 return nullAttributes.contains(attributeName);
278 }
279
280 public boolean getClearAttribute(String attributeName) {
281 return clearAttributes.contains(attributeName);
282 }
283
284 public ArrayList getClearReferences() {
285 return clearReferences;
286 }
287
288 public boolean getClearReference(String referenceName) {
289 return clearReferences.contains(referenceName);
290 }
291
292 public void setClearAttribute(String attributeName) {
293 if (!clearAttributes.contains(attributeName))
294 clearAttributes.add(attributeName);
295 }
296
297 public void setNullAttribute(String attributeName) {
298 if (!nullAttributes.contains(attributeName))
299 nullAttributes.add(attributeName);
300 }
301
302 public void setClearReference(String referenceName) {
303 if (!clearReferences.contains(referenceName))
304 clearReferences.add(referenceName);
305 }
306
307 public void setAttribute(String attributeName, Object attributeValue, String attributeType) throws InvalidAttributeException {
308 String stringValue = getAsText(attributeValue, attributeType);
309 attributes.put(attributeName, stringValue);
310 }
311
312 public void setAttribute(String attributeName, String attributeValue) {
313 attributes.put(attributeName, attributeValue);
314 }
315
316 public Map getReferences() {
317 return references;
318 }
319
320 public ReferencePatterns getReferencePatterns(String name) {
321 return (ReferencePatterns) references.get(name);
322 }
323
324 public void setReferencePatterns(String name, ReferencePatterns patterns) {
325 references.put(name, patterns);
326 }
327
328 /**
329 * Creates a new child of the supplied parent with the data for this
330 * GBeanOverride, adds it to the parent, and then returns the new
331 * child element.
332 */
333 public Element writeXml(Document doc, Element parent) {
334 String gbeanName;
335 if (name instanceof String) {
336 gbeanName = (String) name;
337 } else {
338 gbeanName = name.toString();
339 }
340
341 Element gbean = doc.createElement("gbean");
342 parent.appendChild(gbean);
343 gbean.setAttribute("name", gbeanName);
344 if (gbeanInfo != null) {
345 gbean.setAttribute("gbeanInfo", gbeanInfo);
346 }
347 if (!load) {
348 gbean.setAttribute("load", "false");
349 }
350
351
352 for (Iterator iterator = attributes.entrySet().iterator(); iterator.hasNext();) {
353 Map.Entry entry = (Map.Entry) iterator.next();
354 String name = (String) entry.getKey();
355 String value = (String) entry.getValue();
356 if (value == null) {
357 setNullAttribute(name);
358 }
359 else {
360 if (getNullAttribute(name)) {
361 nullAttributes.remove(name);
362 }
363 if (name.toLowerCase().indexOf("password") > -1) {
364 value = EncryptionManager.encrypt(value);
365 }
366 Element attribute = doc.createElement("attribute");
367 attribute.setAttribute("name", name);
368 gbean.appendChild(attribute);
369 if (value.length() == 0) {
370 attribute.setAttribute("value", "");
371 }
372 else {
373 try {
374
375
376
377
378
379
380 DocumentBuilderFactory factory = XmlUtil.newDocumentBuilderFactory();
381 DocumentBuilder builder = factory.newDocumentBuilder();
382
383
384 String xml = "<fragment>" + value + "</fragment>";
385 InputSource input = new InputSource(new StringReader(xml));
386 Document fragment = builder.parse(input);
387
388 Node root = fragment.getFirstChild();
389 NodeList children = root.getChildNodes();
390 for (int i=0; i<children.getLength(); i++) {
391 Node child = children.item(i);
392
393
394 child = doc.importNode(child, true);
395 attribute.appendChild(child);
396 }
397 }
398 catch (Exception e) {
399 throw new RuntimeException("Failed to write attribute value fragment: " + e.getMessage(), e);
400 }
401 }
402 }
403 }
404
405
406 for (Iterator iterator = clearAttributes.iterator(); iterator.hasNext();) {
407 String name = (String) iterator.next();
408 Element attribute = doc.createElement("attribute");
409 gbean.appendChild(attribute);
410 attribute.setAttribute("name", name);
411 }
412
413
414 for (Iterator iterator = nullAttributes.iterator(); iterator.hasNext();) {
415 String name = (String) iterator.next();
416 Element attribute = doc.createElement("attribute");
417 gbean.appendChild(attribute);
418 attribute.setAttribute("name", name);
419 attribute.setAttribute("null", "true");
420 }
421
422
423 for (Iterator iterator = references.entrySet().iterator(); iterator.hasNext();) {
424 Map.Entry entry = (Map.Entry) iterator.next();
425 String name = (String) entry.getKey();
426 ReferencePatterns patterns = (ReferencePatterns) entry.getValue();
427
428 Element reference = doc.createElement("reference");
429 reference.setAttribute("name", name);
430 gbean.appendChild(reference);
431
432 Set patternSet;
433 if (patterns.isResolved()) {
434 patternSet = Collections.singleton(new AbstractNameQuery(patterns.getAbstractName()));
435 } else {
436 patternSet = patterns.getPatterns();
437 }
438
439 for (Iterator patternIterator = patternSet.iterator(); patternIterator.hasNext();) {
440 AbstractNameQuery pattern = (AbstractNameQuery) patternIterator.next();
441 Element pat = doc.createElement("pattern");
442 reference.appendChild(pat);
443 Artifact artifact = pattern.getArtifact();
444
445 if (artifact != null) {
446 if (artifact.getGroupId() != null) {
447 Element group = doc.createElement("groupId");
448 group.appendChild(doc.createTextNode(artifact.getGroupId()));
449 pat.appendChild(group);
450 }
451 if (artifact.getArtifactId() != null) {
452 Element art = doc.createElement("artifactId");
453 art.appendChild(doc.createTextNode(artifact.getArtifactId()));
454 pat.appendChild(art);
455 }
456 if (artifact.getVersion() != null) {
457 Element version = doc.createElement("version");
458 version.appendChild(doc.createTextNode(artifact.getVersion().toString()));
459 pat.appendChild(version);
460 }
461 if (artifact.getType() != null) {
462 Element type = doc.createElement("type");
463 type.appendChild(doc.createTextNode(artifact.getType()));
464 pat.appendChild(type);
465 }
466 }
467
468 Map nameMap = pattern.getName();
469 if (nameMap.get("module") != null) {
470 Element module = doc.createElement("module");
471 module.appendChild(doc.createTextNode(nameMap.get("module").toString()));
472 pat.appendChild(module);
473 }
474
475 if (nameMap.get("name") != null) {
476 Element patName = doc.createElement("name");
477 patName.appendChild(doc.createTextNode(nameMap.get("name").toString()));
478 pat.appendChild(patName);
479 }
480 }
481 }
482
483
484 for (Iterator iterator = clearReferences.iterator(); iterator.hasNext();) {
485 String name = (String) iterator.next();
486 Element reference = doc.createElement("reference");
487 reference.setAttribute("name", name);
488 gbean.appendChild(reference);
489 }
490
491 return gbean;
492 }
493
494 public static String getAsText(Object value, String type) throws InvalidAttributeException {
495 try {
496 String attributeStringValue = null;
497 if (value != null) {
498 PropertyEditor editor = PropertyEditors.findEditor(type, GBeanOverride.class.getClassLoader());
499 if (editor == null) {
500 throw new InvalidAttributeException("Unable to format attribute of type " + type + "; no editor found");
501 }
502 editor.setValue(value);
503 attributeStringValue = editor.getAsText();
504 }
505 return attributeStringValue;
506 } catch (ClassNotFoundException e) {
507
508 throw new InvalidAttributeException("Unable to store attribute type " + type);
509 }
510 }
511 }