001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.xml; 018 019import static org.apache.juneau.commons.utils.StringUtils.*; 020import static org.apache.juneau.commons.utils.ThrowableUtils.*; 021import static org.apache.juneau.commons.utils.Utils.*; 022 023import java.util.*; 024import java.util.concurrent.*; 025 026import org.apache.juneau.annotation.*; 027 028/** 029 * Represents a simple namespace mapping between a simple name and URI. 030 * 031 * <p> 032 * In general, the simple name will be used as the XML prefix mapping unless there are conflicts or prefix re-mappings 033 * in the serializer. 034 * 035 * <h5 class='section'>See Also:</h5><ul> 036 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/XmlBasics">XML Basics</a> 037 * </ul> 038 */ 039@Bean(sort = true) 040public class Namespace { 041 042 private static final ConcurrentHashMap<String,Namespace> CACHE = new ConcurrentHashMap<>(); 043 044 /** 045 * Converts the specified object into a {@link Namespace} object. 046 * 047 * <p> 048 * Can be any of following types: 049 * <ul> 050 * <li>A {@link Namespace} object 051 * <li>A string containing a name/value pair of the form <js>"name:uri"</js>. 052 * </ul> 053 * 054 * @param o The input. 055 * @return The namespace object, or <jk>null</jk> if the input was <jk>null</jk> or an empty JSON object. 056 */ 057 public static Namespace create(Object o) { 058 if (o == null) 059 return null; 060 if (o instanceof Namespace o2) 061 return o2; 062 if (o instanceof CharSequence o3) 063 return of(o3.toString()); 064 throw rex("Invalid object type passed to Namespace.create(Object): ''{0}''", cn(o)); 065 } 066 067 /** 068 * Converts the specified object into an array of {@link Namespace} object. 069 * 070 * <p> 071 * Can be any of following types: 072 * <ul> 073 * <li>A {@link Namespace} array 074 * <li>A comma-delimited string with key/value pairs of the form <js>"name:uri"</js>. 075 * <li>A <c>Collection</c> containing any of object that can be passed to {@link #createArray(Object)}. 076 * </ul> 077 * 078 * @param o The input. 079 * @return The namespace objects, or <jk>null</jk> if the input was <jk>null</jk> or an empty JSON object. 080 */ 081 public static Namespace[] createArray(Object o) { 082 083 if (o instanceof Namespace[]) 084 return (Namespace[])o; 085 086 if (o instanceof String[]) { 087 var ss = (String[])o; 088 var n = new Namespace[ss.length]; 089 for (var i = 0; i < ss.length; i++) 090 n[i] = create(ss[i]); 091 return n; 092 } 093 094 if (o instanceof CharSequence o2) { 095 var ss = splita(o2.toString()); 096 var n = new Namespace[ss.length]; 097 for (var i = 0; i < ss.length; i++) 098 n[i] = create(ss[i]); 099 return n; 100 } 101 102 if (o instanceof Collection o2) { 103 var n = new Namespace[o2.size()]; 104 var i = 0; 105 for (var o3 : o2) { 106 if (o3 instanceof Namespace o4) 107 n[i++] = o4; 108 else if (o3 instanceof CharSequence o4) 109 n[i++] = create(o4.toString()); 110 else 111 throw rex("Invalid type passed to NamespaceFactory.createArray: ''{0}''", cn(o)); 112 } 113 return n; 114 } 115 116 throw rex("Invalid type passed to NamespaceFactory.createArray: ''{0}''", cn(o)); 117 } 118 119 /** 120 * Create a {@link Namespace} from a <js>"name:uri"</js> string pair. 121 * 122 * @param key The key/pair string. 123 * @return The namespace object. 124 */ 125 public static Namespace of(String key) { 126 var n = CACHE.get(key); 127 if (nn(n)) 128 return n; 129 var i = key.indexOf(':'); 130 if (i == -1) 131 return of(key, null); 132 if (key.startsWith("http://") || key.startsWith("https://")) 133 return of(null, key); 134 return of(key.substring(0, i).trim(), key.substring(i + 1).trim()); 135 } 136 137 /** 138 * Create a {@link Namespace} with the specified name and URI. 139 * 140 * <p> 141 * Previously-encountered name/uri pairs return a cached copy. 142 * 143 * @param name The namespace name. See {@link Namespace#getName()}. 144 * @param uri The namespace URI. See {@link Namespace#getUri()}. 145 * @return The namespace object. 146 */ 147 public static Namespace of(String name, String uri) { 148 var key = name + ":" + uri; 149 var n = CACHE.get(key); 150 if (n == null) { 151 n = new Namespace(key, name, uri); 152 var n2 = CACHE.putIfAbsent(key, n); 153 return (n2 == null ? n : n2); 154 } 155 return n; 156 } 157 158 final String key, name, uri; 159 160 /** 161 * Constructor. 162 * 163 * @param name The short name of this schema. 164 * @param uri The URI of this schema. 165 */ 166 private Namespace(String key, String name, String uri) { 167 this.key = key; 168 this.name = name; 169 this.uri = uri; 170 } 171 172 /** 173 * Returns the namespace name. 174 * 175 * @return The namespace name. 176 */ 177 public String getName() { return name; } 178 179 /** 180 * Returns the namespace URI. 181 * 182 * @return The namespace URI. 183 */ 184 public String getUri() { return uri; } 185 186 @Override /* Overridden from Object */ 187 public String toString() { 188 return key; 189 } 190}