001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.aegis.util;
019:
020: import java.net.MalformedURLException;
021: import java.net.URL;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.StringTokenizer;
025:
026: import javax.xml.namespace.NamespaceContext;
027: import javax.xml.namespace.QName;
028: import javax.xml.stream.XMLStreamException;
029: import javax.xml.stream.XMLStreamReader;
030: import javax.xml.stream.XMLStreamWriter;
031:
032: import org.apache.cxf.aegis.DatabindingException;
033: import org.apache.cxf.helpers.JavaUtils;
034: import org.jdom.Element;
035: import org.jdom.Namespace;
036:
037: /**
038: * Namespace utilities.
039: *
040: * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
041: * @author <a href="mailto:poutsma@mac.com">Arjen Poutsma</a>
042: */
043: public final class NamespaceHelper {
044:
045: private NamespaceHelper() {
046: //utility class
047: }
048:
049: /**
050: * Create a unique namespace uri/prefix combination.
051: *
052: * @param nsUri
053: * @return The namespace with the specified URI. If one doesn't exist, one
054: * is created.
055: */
056: public static String getUniquePrefix(Element element,
057: String namespaceURI) {
058: String prefix = getPrefix(element, namespaceURI);
059:
060: if (prefix == null) {
061: prefix = getUniquePrefix(element);
062: element.addNamespaceDeclaration(Namespace.getNamespace(
063: prefix, namespaceURI));
064: }
065: return prefix;
066: }
067:
068: public static String getPrefix(Element element, String namespaceURI) {
069: if (element.getNamespaceURI().equals(namespaceURI)) {
070: return element.getNamespacePrefix();
071: }
072:
073: List namespaces = element.getAdditionalNamespaces();
074:
075: for (Iterator itr = namespaces.iterator(); itr.hasNext();) {
076: Namespace ns = (Namespace) itr.next();
077:
078: if (ns.getURI().equals(namespaceURI)) {
079: return ns.getPrefix();
080: }
081: }
082:
083: if (element.getParentElement() != null) {
084: return getPrefix(element.getParentElement(), namespaceURI);
085: } else {
086: return null;
087: }
088: }
089:
090: public static void getPrefixes(Element element,
091: String namespaceURI, List<String> prefixes) {
092: if (element.getNamespaceURI().equals(namespaceURI)) {
093: prefixes.add(element.getNamespacePrefix());
094: }
095:
096: List namespaces = element.getAdditionalNamespaces();
097:
098: for (Iterator itr = namespaces.iterator(); itr.hasNext();) {
099: Namespace ns = (Namespace) itr.next();
100:
101: if (ns.getURI().equals(namespaceURI)) {
102: prefixes.add(ns.getPrefix());
103: }
104: }
105:
106: if (element.getParentElement() != null) {
107: getPrefixes(element.getParentElement(), namespaceURI,
108: prefixes);
109: }
110: }
111:
112: private static String getUniquePrefix(Element el) {
113: int n = 1;
114:
115: while (true) {
116: String nsPrefix = "ns" + n;
117:
118: if (el.getNamespace(nsPrefix) == null) {
119: return nsPrefix;
120: }
121:
122: n++;
123: }
124: }
125:
126: /**
127: * Create a unique namespace uri/prefix combination.
128: *
129: * @param nsUri
130: * @return The namespace with the specified URI. If one doesn't exist, one
131: * is created.
132: * @throws XMLStreamException
133: */
134: public static String getUniquePrefix(XMLStreamWriter writer,
135: String namespaceURI, boolean declare)
136: throws XMLStreamException {
137: String prefix = writer.getNamespaceContext().getPrefix(
138: namespaceURI);
139: if (prefix == null) {
140: prefix = getUniquePrefix(writer);
141:
142: if (declare) {
143: writer.setPrefix(prefix, namespaceURI);
144: writer.writeNamespace(prefix, namespaceURI);
145: }
146: }
147:
148: return prefix;
149: }
150:
151: public static String getUniquePrefix(XMLStreamWriter writer) {
152: int n = 1;
153:
154: while (true) {
155: String nsPrefix = "ns" + n;
156:
157: if (writer.getNamespaceContext().getNamespaceURI(nsPrefix) == null) {
158: return nsPrefix;
159: }
160:
161: n++;
162: }
163: }
164:
165: /**
166: * Generates the name of a XML namespace from a given class name and
167: * protocol. The returned namespace will take the form
168: * <code>protocol://domain</code>, where <code>protocol</code> is the
169: * given protocol, and <code>domain</code> the inversed package name of
170: * the given class name. <p/> For instance, if the given class name is
171: * <code>org.codehaus.xfire.services.Echo</code>, and the protocol is
172: * <code>http</code>, the resulting namespace would be
173: * <code>http://services.xfire.codehaus.org</code>.
174: *
175: * @param className the class name
176: * @param protocol the protocol (eg. <code>http</code>)
177: * @return the namespace
178: */
179: public static String makeNamespaceFromClassName(String className,
180: String protocol) {
181: int index = className.lastIndexOf(".");
182:
183: if (index == -1) {
184: return protocol + "://" + "DefaultNamespace";
185: }
186:
187: String packageName = className.substring(0, index);
188:
189: StringTokenizer st = new StringTokenizer(packageName, ".");
190: String[] words = new String[st.countTokens()];
191:
192: for (int i = 0; i < words.length; ++i) {
193: words[i] = st.nextToken();
194: }
195:
196: StringBuffer sb = new StringBuffer(80);
197:
198: for (int i = words.length - 1; i >= 0; --i) {
199: String word = words[i];
200:
201: // seperate with dot
202: if (i != words.length - 1) {
203: sb.append('.');
204: }
205:
206: sb.append(word);
207: }
208:
209: return protocol + "://" + sb.toString();
210: }
211:
212: /**
213: * Method makePackageName
214: *
215: * @param namespace
216: * @return
217: */
218: public static String makePackageName(String namespace) {
219:
220: String hostname = null;
221: String path = "";
222:
223: // get the target namespace of the document
224: try {
225: URL u = new URL(namespace);
226:
227: hostname = u.getHost();
228: path = u.getPath();
229: } catch (MalformedURLException e) {
230: if (namespace.indexOf(":") > -1) {
231: hostname = namespace
232: .substring(namespace.indexOf(":") + 1);
233:
234: if (hostname.indexOf("/") > -1) {
235: hostname = hostname.substring(0, hostname
236: .indexOf("/"));
237: }
238: } else {
239: hostname = namespace;
240: }
241: }
242:
243: // if we didn't file a hostname, bail
244: if (hostname == null) {
245: return null;
246: }
247:
248: // convert illegal java identifier
249: hostname = hostname.replace('-', '_');
250: path = path.replace('-', '_');
251:
252: // chomp off last forward slash in path, if necessary
253: if ((path.length() > 0)
254: && (path.charAt(path.length() - 1) == '/')) {
255: path = path.substring(0, path.length() - 1);
256: }
257:
258: // tokenize the hostname and reverse it
259: StringTokenizer st = new StringTokenizer(hostname, ".:");
260: String[] words = new String[st.countTokens()];
261:
262: for (int i = 0; i < words.length; ++i) {
263: words[i] = st.nextToken();
264: }
265:
266: StringBuffer sb = new StringBuffer(namespace.length());
267:
268: for (int i = words.length - 1; i >= 0; --i) {
269: addWordToPackageBuffer(sb, words[i], i == words.length - 1);
270: }
271:
272: // tokenize the path
273: StringTokenizer st2 = new StringTokenizer(path, "/");
274:
275: while (st2.hasMoreTokens()) {
276: addWordToPackageBuffer(sb, st2.nextToken(), false);
277: }
278:
279: return sb.toString();
280: }
281:
282: /**
283: * Massage <tt>word</tt> into a form suitable for use in a Java package
284: * name. Append it to the target string buffer with a <tt>.</tt> delimiter
285: * iff <tt>word</tt> is not the first word in the package name.
286: *
287: * @param sb the buffer to append to
288: * @param word the word to append
289: * @param firstWord a flag indicating whether this is the first word
290: */
291: private static void addWordToPackageBuffer(StringBuffer sb,
292: String word, boolean firstWord) {
293:
294: if (JavaUtils.isJavaKeyword(word)) {
295: word = JavaUtils.makeNonJavaKeyword(word);
296: }
297:
298: // separate with dot after the first word
299: if (!firstWord) {
300: sb.append('.');
301: }
302:
303: // prefix digits with underscores
304: if (Character.isDigit(word.charAt(0))) {
305: sb.append('_');
306: }
307:
308: // replace periods with underscores
309: if (word.indexOf('.') != -1) {
310: char[] buf = word.toCharArray();
311:
312: for (int i = 0; i < word.length(); i++) {
313: if (buf[i] == '.') {
314: buf[i] = '_';
315: }
316: }
317:
318: word = new String(buf);
319: }
320:
321: sb.append(word);
322: }
323:
324: /**
325: * Reads a QName from the element text. Reader must be positioned at the
326: * start tag.
327: *
328: * @param reader
329: * @return
330: * @throws XMLStreamException
331: */
332: public static QName readQName(XMLStreamReader reader)
333: throws XMLStreamException {
334: String value = reader.getElementText();
335: if (value == null) {
336: return null;
337: }
338:
339: int index = value.indexOf(":");
340:
341: if (index == -1) {
342: return new QName(value);
343: }
344:
345: String prefix = value.substring(0, index);
346: String localName = value.substring(index + 1);
347: String ns = reader.getNamespaceURI(prefix);
348:
349: if (ns == null || localName == null) {
350: throw new DatabindingException("Invalid QName in mapping: "
351: + value);
352: }
353:
354: return new QName(ns, localName, prefix);
355: }
356:
357: public static QName createQName(NamespaceContext nc, String value) {
358: if (value == null) {
359: return null;
360: }
361: int index = value.indexOf(':');
362: if (index == -1) {
363: return new QName(nc.getNamespaceURI(""), value, "");
364: } else {
365: String prefix = value.substring(0, index);
366: String localName = value.substring(index + 1);
367: String ns = nc.getNamespaceURI(prefix);
368: return new QName(ns, localName, prefix);
369: }
370: }
371:
372: public static QName createQName(Element e, String value,
373: String defaultNamespace) {
374: if (value == null) {
375: return null;
376: }
377:
378: int index = value.indexOf(":");
379:
380: if (index == -1) {
381: return new QName(defaultNamespace, value);
382: }
383:
384: String prefix = value.substring(0, index);
385: String localName = value.substring(index + 1);
386: Namespace jNS = e.getNamespace(prefix);
387: if (jNS == null) {
388: throw new DatabindingException(
389: "No namespace was found for prefix: " + prefix);
390: }
391:
392: String ns = jNS.getURI();
393:
394: if (ns == null || localName == null) {
395: throw new DatabindingException("Invalid QName in mapping: "
396: + value);
397: }
398:
399: return new QName(ns, localName, prefix);
400: }
401: }
|