PageRenderTime 30ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/flow/src/java/org/apache/struts/flow/core/location/LocationAttributes.java

https://github.com/apache/struts-sandbox
Java | 349 lines | 148 code | 42 blank | 159 comment | 23 complexity | 407ba9d6f59c770e2dabde545eed250f MD5 | raw file
  1. /*
  2. * Copyright 2005 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. package org.apache.struts.flow.core.location;
  17. import org.w3c.dom.Attr;
  18. import org.w3c.dom.Element;
  19. import org.w3c.dom.Node;
  20. import org.w3c.dom.NodeList;
  21. import org.xml.sax.Attributes;
  22. import org.xml.sax.ContentHandler;
  23. import org.xml.sax.Locator;
  24. import org.xml.sax.SAXException;
  25. import org.xml.sax.helpers.AttributesImpl;
  26. /**
  27. * A class to handle location information stored in attributes.
  28. * These attributes are typically setup using {@link org.apache.struts.flow.core.location.LocationAttributes.Pipe}
  29. * which augments the SAX stream with additional attributes, e.g.:
  30. * <pre>
  31. * &lt;root xmlns:loc="http://apache.org/cocoon/location"
  32. * loc:src="file://path/to/file.xml"
  33. * loc:line="1" loc:column="1"&gt;
  34. * &lt;foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/&gt;
  35. * &lt;/root&gt;
  36. * </pre>
  37. *
  38. * @see org.apache.struts.flow.core.location.LocationAttributes.Pipe
  39. * @since 2.1.8
  40. * @version $Id: LocationAttributes.java 328390 2005-10-25 15:37:05Z sylvain $
  41. */
  42. public class LocationAttributes {
  43. /** Prefix for the location namespace */
  44. public static final String PREFIX = "loc";
  45. /** Namespace URI for location attributes */
  46. public static final String URI = "http://apache.org/cocoon/location";
  47. /** Attribute name for the location URI */
  48. public static final String SRC_ATTR = "src";
  49. /** Attribute name for the line number */
  50. public static final String LINE_ATTR = "line";
  51. /** Attribute name for the column number */
  52. public static final String COL_ATTR = "column";
  53. /** Attribute qualified name for the location URI */
  54. public static final String Q_SRC_ATTR = "loc:src";
  55. /** Attribute qualified name for the line number */
  56. public static final String Q_LINE_ATTR = "loc:line";
  57. /** Attribute qualified name for the column number */
  58. public static final String Q_COL_ATTR = "loc:column";
  59. // Private constructor, we only have static methods
  60. private LocationAttributes() {
  61. // Nothing
  62. }
  63. /**
  64. * Add location attributes to a set of SAX attributes.
  65. *
  66. * @param locator the <code>Locator</code> (can be null)
  67. * @param attrs the <code>Attributes</code> where locator information should be added
  68. * @return
  69. */
  70. public static Attributes addLocationAttributes(Locator locator, Attributes attrs) {
  71. if (locator == null || attrs.getIndex(URI, SRC_ATTR) != -1) {
  72. // No location information known, or already has it
  73. return attrs;
  74. }
  75. // Get an AttributeImpl so that we can add new attributes.
  76. AttributesImpl newAttrs = attrs instanceof AttributesImpl ?
  77. (AttributesImpl)attrs : new AttributesImpl(attrs);
  78. newAttrs.addAttribute(URI, SRC_ATTR, Q_SRC_ATTR, "CDATA", locator.getSystemId());
  79. newAttrs.addAttribute(URI, LINE_ATTR, Q_LINE_ATTR, "CDATA", Integer.toString(locator.getLineNumber()));
  80. newAttrs.addAttribute(URI, COL_ATTR, Q_COL_ATTR, "CDATA", Integer.toString(locator.getColumnNumber()));
  81. return newAttrs;
  82. }
  83. /**
  84. * Returns the {@link Location} of an element (SAX flavor).
  85. *
  86. * @param attrs the element's attributes that hold the location information
  87. * @param description a description for the location (can be null)
  88. * @return a {@link Location} object
  89. */
  90. public static Location getLocation(Attributes attrs, String description) {
  91. String src = attrs.getValue(URI, SRC_ATTR);
  92. if (src == null) {
  93. return Location.UNKNOWN;
  94. }
  95. return new LocationImpl(description, src, getLine(attrs), getColumn(attrs));
  96. }
  97. /**
  98. * Returns the location of an element (SAX flavor). If the location is to be kept
  99. * into an object built from this element, consider using {@link #getLocation(Attributes)}
  100. * and the {@link Locatable} interface.
  101. *
  102. * @param attrs the element's attributes that hold the location information
  103. * @return a location string as defined by {@link Location#toString()}.
  104. */
  105. public static String getLocationString(Attributes attrs) {
  106. String src = attrs.getValue(URI, SRC_ATTR);
  107. if (src == null) {
  108. return LocationUtils.UNKNOWN_STRING;
  109. }
  110. return src + ":" + attrs.getValue(URI, LINE_ATTR) + ":" + attrs.getValue(URI, COL_ATTR);
  111. }
  112. /**
  113. * Returns the URI of an element (SAX flavor)
  114. *
  115. * @param attrs the element's attributes that hold the location information
  116. * @return the element's URI or "<code>[unknown location]</code>" if <code>attrs</code>
  117. * has no location information.
  118. */
  119. public static String getURI(Attributes attrs) {
  120. String src = attrs.getValue(URI, SRC_ATTR);
  121. return src != null ? src : LocationUtils.UNKNOWN_STRING;
  122. }
  123. /**
  124. * Returns the line number of an element (SAX flavor)
  125. *
  126. * @param attrs the element's attributes that hold the location information
  127. * @return the element's line number or <code>-1</code> if <code>attrs</code>
  128. * has no location information.
  129. */
  130. public static int getLine(Attributes attrs) {
  131. String line = attrs.getValue(URI, LINE_ATTR);
  132. return line != null ? Integer.parseInt(line) : -1;
  133. }
  134. /**
  135. * Returns the column number of an element (SAX flavor)
  136. *
  137. * @param attrs the element's attributes that hold the location information
  138. * @return the element's column number or <code>-1</code> if <code>attrs</code>
  139. * has no location information.
  140. */
  141. public static int getColumn(Attributes attrs) {
  142. String col = attrs.getValue(URI, COL_ATTR);
  143. return col != null ? Integer.parseInt(col) : -1;
  144. }
  145. /**
  146. * Returns the {@link Location} of an element (DOM flavor).
  147. *
  148. * @param attrs the element that holds the location information
  149. * @param description a description for the location (if <code>null</code>, the element's name is used)
  150. * @return a {@link Location} object
  151. */
  152. public static Location getLocation(Element elem, String description) {
  153. Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
  154. if (srcAttr == null) {
  155. return Location.UNKNOWN;
  156. }
  157. return new LocationImpl(description == null ? elem.getNodeName() : description,
  158. srcAttr.getValue(), getLine(elem), getColumn(elem));
  159. }
  160. /**
  161. * Same as <code>getLocation(elem, null)</code>.
  162. */
  163. public static Location getLocation(Element elem) {
  164. return getLocation(elem, null);
  165. }
  166. /**
  167. * Returns the location of an element that has been processed by this pipe (DOM flavor).
  168. * If the location is to be kept into an object built from this element, consider using
  169. * {@link #getLocation(Element)} and the {@link Locatable} interface.
  170. *
  171. * @param elem the element that holds the location information
  172. * @return a location string as defined by {@link Location#toString()}.
  173. */
  174. public static String getLocationString(Element elem) {
  175. Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
  176. if (srcAttr == null) {
  177. return LocationUtils.UNKNOWN_STRING;
  178. }
  179. return srcAttr.getValue() + ":" + elem.getAttributeNS(URI, LINE_ATTR) + ":" + elem.getAttributeNS(URI, COL_ATTR);
  180. }
  181. /**
  182. * Returns the URI of an element (DOM flavor)
  183. *
  184. * @param elem the element that holds the location information
  185. * @return the element's URI or "<code>[unknown location]</code>" if <code>elem</code>
  186. * has no location information.
  187. */
  188. public static String getURI(Element elem) {
  189. Attr attr = elem.getAttributeNodeNS(URI, SRC_ATTR);
  190. return attr != null ? attr.getValue() : LocationUtils.UNKNOWN_STRING;
  191. }
  192. /**
  193. * Returns the line number of an element (DOM flavor)
  194. *
  195. * @param elem the element that holds the location information
  196. * @return the element's line number or <code>-1</code> if <code>elem</code>
  197. * has no location information.
  198. */
  199. public static int getLine(Element elem) {
  200. Attr attr = elem.getAttributeNodeNS(URI, LINE_ATTR);
  201. return attr != null ? Integer.parseInt(attr.getValue()) : -1;
  202. }
  203. /**
  204. * Returns the column number of an element (DOM flavor)
  205. *
  206. * @param elem the element that holds the location information
  207. * @return the element's column number or <code>-1</code> if <code>elem</code>
  208. * has no location information.
  209. */
  210. public static int getColumn(Element elem) {
  211. Attr attr = elem.getAttributeNodeNS(URI, COL_ATTR);
  212. return attr != null ? Integer.parseInt(attr.getValue()) : -1;
  213. }
  214. /**
  215. * Remove the location attributes from a DOM element.
  216. *
  217. * @param elem the element to remove the location attributes from.
  218. * @param recurse if <code>true</code>, also remove location attributes on descendant elements.
  219. */
  220. public static void remove(Element elem, boolean recurse) {
  221. elem.removeAttributeNS(URI, SRC_ATTR);
  222. elem.removeAttributeNS(URI, LINE_ATTR);
  223. elem.removeAttributeNS(URI, COL_ATTR);
  224. if (recurse) {
  225. NodeList children = elem.getChildNodes();
  226. for (int i = 0; i < children.getLength(); i++) {
  227. Node child = children.item(i);
  228. if (child.getNodeType() == Node.ELEMENT_NODE) {
  229. remove((Element)child, recurse);
  230. }
  231. }
  232. }
  233. }
  234. /**
  235. * A SAX filter that adds the information available from the <code>Locator</code> as attributes.
  236. * The purpose of having location as attributes is to allow this information to survive transformations
  237. * of the document (an XSL could copy these attributes over) or conversion of SAX events to a DOM.
  238. * <p>
  239. * The location is added as 3 attributes in a specific namespace to each element.
  240. * <pre>
  241. * &lt;root xmlns:loc="http://apache.org/cocoon/location"
  242. * loc:src="file://path/to/file.xml"
  243. * loc:line="1" loc:column="1"&gt;
  244. * &lt;foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/&gt;
  245. * &lt;/root&gt;
  246. * </pre>
  247. * <strong>Note:</strong> Although this adds a lot of information to the serialized form of the document,
  248. * the overhead in SAX events is not that big, as attribute names are interned, and all <code>src</code>
  249. * attributes point to the same string.
  250. *
  251. * @see org.apache.struts.flow.core.location.LocationAttributes
  252. * @since 2.1.8
  253. */
  254. public static class Pipe implements ContentHandler {
  255. private Locator locator;
  256. private ContentHandler nextHandler;
  257. /**
  258. * Create a filter. It has to be chained to another handler to be really useful.
  259. */
  260. public Pipe() {
  261. }
  262. /**
  263. * Create a filter that is chained to another handler.
  264. * @param next the next handler in the chain.
  265. */
  266. public Pipe(ContentHandler next) {
  267. nextHandler = next;
  268. }
  269. public void setDocumentLocator(Locator locator) {
  270. this.locator = locator;
  271. nextHandler.setDocumentLocator(locator);
  272. }
  273. public void startDocument() throws SAXException {
  274. nextHandler.startDocument();
  275. nextHandler.startPrefixMapping(LocationAttributes.PREFIX, LocationAttributes.URI);
  276. }
  277. public void endDocument() throws SAXException {
  278. endPrefixMapping(LocationAttributes.PREFIX);
  279. nextHandler.endDocument();
  280. }
  281. public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
  282. // Add location attributes to the element
  283. nextHandler.startElement(uri, loc, raw, LocationAttributes.addLocationAttributes(locator, attrs));
  284. }
  285. public void endElement(String arg0, String arg1, String arg2) throws SAXException {
  286. nextHandler.endElement(arg0, arg1, arg2);
  287. }
  288. public void startPrefixMapping(String arg0, String arg1) throws SAXException {
  289. nextHandler.startPrefixMapping(arg0, arg1);
  290. }
  291. public void endPrefixMapping(String arg0) throws SAXException {
  292. nextHandler.endPrefixMapping(arg0);
  293. }
  294. public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
  295. nextHandler.characters(arg0, arg1, arg2);
  296. }
  297. public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
  298. nextHandler.ignorableWhitespace(arg0, arg1, arg2);
  299. }
  300. public void processingInstruction(String arg0, String arg1) throws SAXException {
  301. nextHandler.processingInstruction(arg0, arg1);
  302. }
  303. public void skippedEntity(String arg0) throws SAXException {
  304. nextHandler.skippedEntity(arg0);
  305. }
  306. }
  307. }