1 /*------------------------------------------------------------------------------
2 Name: PluginConfigSaxFactory.java
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 ------------------------------------------------------------------------------*/
6 package org.xmlBlaster.util;
7
8 import java.util.logging.Level;
9 import java.util.logging.Logger;
10
11 import org.xml.sax.Attributes;
12 import org.xmlBlaster.util.def.ErrorCode;
13
14
15 /**
16 * This class parses an xml string to generate an Attribute which can be used either in PluginConfig or on the
17 * normal properties server- or clientside.
18 * <p>
19 * @author <a href="mailto:michele@laghi.eu">Michele Laghi</a>
20 * @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a>
21 * @see <a href="http://www.xmlblaster.org/xmlBlaster/doc/requirements/engine.runlevel.html">engine.runlevel requirement</a>
22 * <pre>
23 * <action do='LOAD'
24 * onStartupRunlevel='3'
25 * sequence='5'
26 * onFail='RESOURCE_CONFIGURATION_PLUGINFAILED'/>
27 * </pre>
28 */
29 public class AttributeSaxFactory extends SaxHandlerBase
30 {
31 private String ME = "AttributeSaxFactory";
32 private final Global glob;
33 private static Logger log = Logger.getLogger(AttributeSaxFactory.class.getName());
34
35 private XmlBlasterException ex;
36
37 private I_AttributeUser attributeUser;
38 private String attributeKey;
39 private boolean attributeReplace; // replace ${xy} tokens? defaults to true since xmlBlaster v2.2 2012-01-09
40 private StringBuffer attributeValue;
41 private boolean inAttribute = false;
42 private boolean wrappedInCDATA = false; // for example: <attribute id='publishQos'><![CDATA[ bla ]]></attribute>
43 private boolean embeddedCDATA = false; // for example: <attribute id='publishQos'><qos><![CDATA[<expiration lifeTime='4000'/>]]></qos></attribute>
44 private int subTagCounter;
45
46 /**
47 * Can be used as singleton.
48 */
49 public AttributeSaxFactory(Global glob, I_AttributeUser attributeUser) {
50 super(glob);
51 setUseLexicalHandler(true); // to allow CDATA wrapped attributes
52 this.glob = glob;
53 this.attributeUser = attributeUser;
54 }
55
56 /**
57 * resets the factory (to be invoked before parsing)
58 */
59 public void reset(I_AttributeUser attributeUser) {
60 this.attributeUser = attributeUser;
61 this.ex = null; // reset the exeptions
62 this.wrappedInCDATA = false;
63 }
64
65 public boolean isInAttribute() {
66 return this.inAttribute;
67 }
68
69 /**
70 * Start element, event from SAX parser.
71 * <p />
72 * @param name Tag name
73 * @param attrs the attributes of the tag
74 */
75 public final void startElement(String uri, String localName, String name, Attributes attrs) {
76 if (this.ex != null ) return;
77
78 if ("attribute".equalsIgnoreCase(name)) {
79 this.inAttribute = true;
80 this.wrappedInCDATA = false;
81 this.attributeKey = attrs.getValue("id");
82 this.attributeReplace = true;
83 String replace = attrs.getValue("replace");
84 if (replace != null && "false".equalsIgnoreCase(replace))
85 this.attributeReplace = false;
86 this.attributeValue = new StringBuffer(1024);
87 if (this.attributeKey == null || this.attributeKey.length() < 1)
88 this.ex = new XmlBlasterException(this.glob, ErrorCode.RESOURCE_CONFIGURATION, ME + ".startElement", "the attributes in the <plugin> tag must have an non-empty 'id' attribute");
89 return;
90 }
91
92 if (this.inAttribute) {
93 this.subTagCounter++;
94 this.attributeValue.append("<").append(name);
95 for (int i=0; i<attrs.getLength(); i++) {
96 String qName = attrs.getQName(i);
97 String val = attrs.getValue(i);
98 this.attributeValue.append(" ").append(qName).append("='").append(val).append("'");
99 }
100 this.attributeValue.append(">");
101 }
102 else {
103 log.warning("startElement: unknown tag '" + name + "'");
104 }
105 }
106
107 public void startCDATA() {
108 if (log.isLoggable(Level.FINER)) log.finer("startCDATA");
109 this.wrappedInCDATA = true;
110 if (this.subTagCounter > 0) {
111 this.attributeValue.append("<![CDATA[");
112 this.embeddedCDATA = true;
113 }
114 }
115
116 /**
117 * The characters to be filled
118 */
119 public void characters(char[] ch, int start, int length) {
120 if (this.attributeValue != null)
121 this.attributeValue.append(ch, start, length);
122 }
123
124
125 /**
126 * End element, event from SAX parser.
127 * <p />
128 * @param name Tag name
129 */
130 public void endElement(String uri, String localName, String name) {
131 if (this.ex != null ) return;
132 if ("attribute".equalsIgnoreCase(name)) {
133 this.inAttribute = false;
134 this.subTagCounter = 0;
135 if (this.attributeKey != null && this.attributeValue != null) {
136 String val = this.attributeValue.toString();
137
138 /*if (val.startsWith("<![CDATA[")) {*/ //if (this.wrappedInCDATA) {
139 if (false) { // currently bypassed since we don't want to strip <![CDATA[
140 // Strip CDATA if ampersand '<![CDATA[' was used instead of '<![CDATA[':
141 int pos = val.indexOf("<![CDATA[");
142 if (pos >= 0) {
143 val = val.substring(pos+9);
144 }
145 pos = val.lastIndexOf("]]>");
146 if (pos >= 0) {
147 val = val.substring(0, pos);
148 }
149 }
150 if (this.attributeUser != null) {
151 this.attributeUser.addAttribute(this.attributeKey, val, this.attributeReplace);
152 if (this.wrappedInCDATA) {
153 this.attributeUser.wrapAttributeInCDATA(this.attributeKey);
154 this.wrappedInCDATA = false;
155 }
156 }
157 }
158 this.attributeKey = null;
159 this.attributeValue = null;
160 return;
161 }
162 if (this.inAttribute) {
163 if (this.embeddedCDATA) {
164 this.attributeValue.append("]]>");
165 this.embeddedCDATA = false;
166 }
167 this.attributeValue.append("</"+name+">");
168 this.subTagCounter--;
169 }
170 }
171
172 /**
173 * A human readable name of this factory
174 * @return "AttributeSaxFactory"
175 */
176 public String getName() {
177 return "AttributeSaxFactory";
178 }
179 }
syntax highlighted by Code2HTML, v. 0.9.1