View Javadoc

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          // set attributes
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         // references can be coppied in blind
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         // attributes
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             // Check to see if there is a value attribute
135             if (attribute.hasAttribute("value")) {
136                 setAttribute(attributeName, (String) EncryptionManager.decrypt(attribute.getAttribute("value")));
137                 continue;
138             }
139 
140             // Check to see if there is a null attribute
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             // If there are no contents, then it's to be cleared
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         // references
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             // If there is no pattern, then its an empty set, so its a
171             // cleared value
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         // attributes
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                         // NOTE: Construct a new document to handle mixed content attribute values
376                         //       then add nodes which are children of the first node.  This allows
377                         //       value to be XML or text.
378                         //
379                         
380                         DocumentBuilderFactory factory = XmlUtil.newDocumentBuilderFactory();
381                         DocumentBuilder builder = factory.newDocumentBuilder();
382 
383                         // Wrap value in an element to be sure we can handle xml or text values
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                             // Import the child (and its children) into the new document
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         // cleared attributes
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         // Null attributes
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         // references
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         // cleared references
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             //todo: use the Configuration's ClassLoader to load the attribute, if this ever becomes an issue
508             throw new InvalidAttributeException("Unable to store attribute type " + type);
509         }
510     }
511 }