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.common.utils.Utils.*; 020import static org.apache.juneau.internal.ClassUtils.*; 021 022import java.util.*; 023import java.util.concurrent.*; 024 025import org.apache.juneau.*; 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 /** 046 * Create a {@link Namespace} with the specified name and URI. 047 * 048 * <p> 049 * Previously-encountered name/uri pairs return a cached copy. 050 * 051 * @param name The namespace name. See {@link Namespace#getName()}. 052 * @param uri The namespace URI. See {@link Namespace#getUri()}. 053 * @return The namespace object. 054 */ 055 public static Namespace of(String name, String uri) { 056 String key = name + ":" + uri; 057 Namespace n = CACHE.get(key); 058 if (n == null) { 059 n = new Namespace(key, name, uri); 060 Namespace n2 = CACHE.putIfAbsent(key, n); 061 return (n2 == null ? n : n2); 062 } 063 return n; 064 } 065 066 /** 067 * Create a {@link Namespace} from a <js>"name:uri"</js> string pair. 068 * 069 * @param key The key/pair string. 070 * @return The namespace object. 071 */ 072 public static Namespace of(String key) { 073 Namespace n = CACHE.get(key); 074 if (n != null) 075 return n; 076 int i = key.indexOf(':'); 077 if (i == -1) 078 return of(key, null); 079 if (key.startsWith("http://") || key.startsWith("https://")) 080 return of(null, key); 081 return of(key.substring(0, i).trim(), key.substring(i+1).trim()); 082 } 083 084 /** 085 * Converts the specified object into a {@link Namespace} object. 086 * 087 * <p> 088 * Can be any of following types: 089 * <ul> 090 * <li>A {@link Namespace} object 091 * <li>A string containing a name/value pair of the form <js>"name:uri"</js>. 092 * </ul> 093 * 094 * @param o The input. 095 * @return The namespace object, or <jk>null</jk> if the input was <jk>null</jk> or an empty JSON object. 096 */ 097 public static Namespace create(Object o) { 098 if (o == null) 099 return null; 100 if (o instanceof Namespace) 101 return (Namespace)o; 102 if (o instanceof CharSequence) 103 return of(o.toString()); 104 throw new BasicRuntimeException("Invalid object type passed to Namespace.create(Object): ''{0}''", className(o)); 105 } 106 107 /** 108 * Converts the specified object into an array of {@link Namespace} object. 109 * 110 * <p> 111 * Can be any of following types: 112 * <ul> 113 * <li>A {@link Namespace} array 114 * <li>A comma-delimited string with key/value pairs of the form <js>"name:uri"</js>. 115 * <li>A <c>Collection</c> containing any of object that can be passed to {@link #createArray(Object)}. 116 * </ul> 117 * 118 * @param o The input. 119 * @return The namespace objects, or <jk>null</jk> if the input was <jk>null</jk> or an empty JSON object. 120 */ 121 @SuppressWarnings("rawtypes") 122 public static Namespace[] createArray(Object o) { 123 124 if (o instanceof Namespace[]) 125 return (Namespace[])o; 126 127 if (o instanceof String[]) { 128 String[] ss = (String[])o; 129 Namespace[] n = new Namespace[ss.length]; 130 for (int i = 0; i < ss.length; i++) 131 n[i] = create(ss[i]); 132 return n; 133 } 134 135 if (o instanceof CharSequence) { 136 String[] ss = splita(o.toString()); 137 Namespace[] n = new Namespace[ss.length]; 138 for (int i = 0; i < ss.length; i++) 139 n[i] = create(ss[i]); 140 return n; 141 } 142 143 if (o instanceof Collection) { 144 Collection c = (Collection)o; 145 Namespace[] n = new Namespace[c.size()]; 146 int i = 0; 147 for (Object o2 : c){ 148 if (o2 instanceof Namespace) 149 n[i++] = (Namespace)o2; 150 else if (o2 instanceof CharSequence) 151 n[i++] = create(o2.toString()); 152 else 153 throw new BasicRuntimeException("Invalid type passed to NamespaceFactory.createArray: ''{0}''", o); 154 } 155 return n; 156 } 157 158 throw new BasicRuntimeException("Invalid type passed to NamespaceFactory.createArray: ''{0}''", o); 159 } 160 161 162 final String key, name, uri; 163 164 /** 165 * Constructor. 166 * 167 * @param name The short name of this schema. 168 * @param uri The URI of this schema. 169 */ 170 private Namespace(String key, String name, String uri) { 171 this.key = key; 172 this.name = name; 173 this.uri = uri; 174 } 175 176 /** 177 * Returns the namespace name. 178 * 179 * @return The namespace name. 180 */ 181 public String getName() { 182 return name; 183 } 184 185 /** 186 * Returns the namespace URI. 187 * 188 * @return The namespace URI. 189 */ 190 public String getUri() { 191 return uri; 192 } 193 194 @Override /* Object */ 195 public String toString() { 196 return key; 197 } 198}