001 /* 002 * JBoss DNA (http://www.jboss.org/dna) 003 * See the COPYRIGHT.txt file distributed with this work for information 004 * regarding copyright ownership. Some portions may be licensed 005 * to Red Hat, Inc. under one or more contributor license agreements. 006 * See the AUTHORS.txt file in the distribution for a full listing of 007 * individual contributors. 008 * 009 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA 010 * is licensed to you under the terms of the GNU Lesser General Public License as 011 * published by the Free Software Foundation; either version 2.1 of 012 * the License, or (at your option) any later version. 013 * 014 * JBoss DNA is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 017 * Lesser General Public License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this software; if not, write to the Free 021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 023 */ 024 package org.jboss.dna.graph.property.basic; 025 026 import java.io.InputStream; 027 import java.io.Reader; 028 import java.math.BigDecimal; 029 import java.net.URI; 030 import java.util.Calendar; 031 import java.util.Date; 032 import java.util.UUID; 033 import java.util.regex.Matcher; 034 import java.util.regex.Pattern; 035 import net.jcip.annotations.Immutable; 036 import org.jboss.dna.common.text.TextDecoder; 037 import org.jboss.dna.common.util.CheckArg; 038 import org.jboss.dna.graph.GraphI18n; 039 import org.jboss.dna.graph.property.Binary; 040 import org.jboss.dna.graph.property.DateTime; 041 import org.jboss.dna.graph.property.IoException; 042 import org.jboss.dna.graph.property.Name; 043 import org.jboss.dna.graph.property.NameFactory; 044 import org.jboss.dna.graph.property.NamespaceException; 045 import org.jboss.dna.graph.property.NamespaceRegistry; 046 import org.jboss.dna.graph.property.Path; 047 import org.jboss.dna.graph.property.PropertyType; 048 import org.jboss.dna.graph.property.Reference; 049 import org.jboss.dna.graph.property.ValueFactory; 050 import org.jboss.dna.graph.property.ValueFormatException; 051 052 /** 053 * The standard {@link ValueFactory} for {@link PropertyType#NAME} values. 054 * 055 * @author Randall Hauch 056 * @author John Verhaeg 057 */ 058 @Immutable 059 public class NameValueFactory extends AbstractValueFactory<Name> implements NameFactory { 060 061 // Non-escaped pattern: (\{([^}]*)\})?(.*) 062 protected static final String FULLY_QUALFIED_NAME_PATTERN_STRING = "\\{([^}]*)\\}(.*)"; 063 protected static final Pattern FULLY_QUALIFIED_NAME_PATTERN = Pattern.compile(FULLY_QUALFIED_NAME_PATTERN_STRING); 064 065 // Original pattern: (([^:/]*):)?([^:]*) 066 private static final String PREFIXED_NAME_PATTERN_STRING = "(([^:/]*):)?([^:]*)"; 067 private static final Pattern PREFIXED_NAME_PATTERN = Pattern.compile(PREFIXED_NAME_PATTERN_STRING); 068 069 private static Name BLANK_NAME; 070 private static Name ANY_NAME; 071 072 private final NamespaceRegistry namespaceRegistry; 073 074 public NameValueFactory( NamespaceRegistry namespaceRegistry, 075 TextDecoder decoder, 076 ValueFactory<String> stringValueFactory ) { 077 super(PropertyType.NAME, decoder, stringValueFactory); 078 CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry"); 079 this.namespaceRegistry = namespaceRegistry; 080 } 081 082 /** 083 * {@inheritDoc} 084 */ 085 public Name create( String value ) { 086 return create(value, getDecoder()); 087 } 088 089 /** 090 * {@inheritDoc} 091 */ 092 public Name create( String value, 093 TextDecoder decoder ) { 094 if (value == null) return null; 095 if (decoder == null) decoder = getDecoder(); 096 try { 097 if (value.length() == 0) { 098 if (BLANK_NAME == null) BLANK_NAME = new BasicName("", ""); 099 return BLANK_NAME; 100 } 101 char firstChar = value.charAt(0); 102 if (value.length() == 1 && firstChar == '*') { 103 if (ANY_NAME == null) ANY_NAME = new BasicName("", "*"); 104 return ANY_NAME; 105 } 106 if (firstChar != '{') { 107 // First, see whether the value fits the prefixed name pattern ... 108 Matcher matcher = PREFIXED_NAME_PATTERN.matcher(value); 109 if (matcher.matches()) { 110 String prefix = matcher.group(2); 111 String localName = matcher.group(3); 112 // Decode the parts ... 113 prefix = prefix == null ? "" : decoder.decode(prefix); 114 localName = decoder.decode(localName); 115 // Look for a namespace match ... 116 String namespaceUri = this.namespaceRegistry.getNamespaceForPrefix(prefix); 117 // Fail if no namespace is found ... 118 if (namespaceUri == null) { 119 throw new NamespaceException(GraphI18n.noNamespaceRegisteredForPrefix.text(prefix)); 120 } 121 return new BasicName(namespaceUri, localName); 122 } 123 } 124 // If it doesn't fit the prefixed pattern, then try the internal pattern 125 Matcher matcher = FULLY_QUALIFIED_NAME_PATTERN.matcher(value); 126 if (matcher.matches()) { 127 String namespaceUri = matcher.group(1); 128 String localName = matcher.group(2); 129 // Decode the parts ... 130 namespaceUri = decoder.decode(namespaceUri); 131 localName = decoder.decode(localName); 132 return new BasicName(namespaceUri, localName); 133 } 134 } catch (NamespaceException err) { 135 throw new ValueFormatException(value, getPropertyType(), 136 GraphI18n.errorConvertingType.text(String.class.getSimpleName(), 137 Name.class.getSimpleName(), 138 value), err); 139 } 140 throw new ValueFormatException(value, getPropertyType(), GraphI18n.errorConvertingType.text(String.class.getSimpleName(), 141 Name.class.getSimpleName(), 142 value)); 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 public Name create( String namespaceUri, 149 String localName ) { 150 return create(namespaceUri, localName, getDecoder()); 151 } 152 153 /** 154 * {@inheritDoc} 155 */ 156 public Name create( String namespaceUri, 157 String localName, 158 TextDecoder decoder ) { 159 CheckArg.isNotEmpty(localName, "localName"); 160 if (decoder == null) decoder = getDecoder(); 161 namespaceUri = namespaceUri != null ? decoder.decode(namespaceUri.trim()) : null; 162 localName = decoder.decode(localName.trim()); 163 return new BasicName(namespaceUri, localName); 164 } 165 166 /** 167 * {@inheritDoc} 168 */ 169 public Name create( int value ) { 170 throw new ValueFormatException(value, getPropertyType(), 171 GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 172 Integer.class.getSimpleName(), 173 value)); 174 } 175 176 /** 177 * {@inheritDoc} 178 */ 179 public Name create( long value ) { 180 throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 181 Long.class.getSimpleName(), 182 value)); 183 } 184 185 /** 186 * {@inheritDoc} 187 */ 188 public Name create( boolean value ) { 189 throw new ValueFormatException(value, getPropertyType(), 190 GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 191 Boolean.class.getSimpleName(), 192 value)); 193 } 194 195 /** 196 * {@inheritDoc} 197 */ 198 public Name create( float value ) { 199 throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 200 Float.class.getSimpleName(), 201 value)); 202 } 203 204 /** 205 * {@inheritDoc} 206 */ 207 public Name create( double value ) { 208 throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 209 Double.class.getSimpleName(), 210 value)); 211 } 212 213 /** 214 * {@inheritDoc} 215 */ 216 public Name create( BigDecimal value ) { 217 throw new ValueFormatException(value, getPropertyType(), 218 GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 219 BigDecimal.class.getSimpleName(), 220 value)); 221 } 222 223 /** 224 * {@inheritDoc} 225 */ 226 public Name create( Calendar value ) { 227 throw new ValueFormatException(value, getPropertyType(), 228 GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 229 Calendar.class.getSimpleName(), 230 value)); 231 } 232 233 /** 234 * {@inheritDoc} 235 */ 236 public Name create( Date value ) { 237 throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 238 Date.class.getSimpleName(), 239 value)); 240 } 241 242 /** 243 * {@inheritDoc} 244 * 245 * @see org.jboss.dna.graph.property.ValueFactory#create(org.jboss.dna.graph.property.DateTime) 246 */ 247 public Name create( DateTime value ) throws ValueFormatException { 248 throw new ValueFormatException(value, getPropertyType(), 249 GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 250 DateTime.class.getSimpleName(), 251 value)); 252 } 253 254 /** 255 * {@inheritDoc} 256 */ 257 public Name create( Name value ) { 258 return value; 259 } 260 261 /** 262 * {@inheritDoc} 263 */ 264 public Name create( Path value ) { 265 if (value == null) return null; 266 if (!value.isAbsolute() && value.size() == 1) { 267 // A relative name of length 1 is converted to a name 268 Path.Segment segment = value.getLastSegment(); 269 // Can only convert if the path has no SNS index ... 270 if (!segment.hasIndex()) return segment.getName(); 271 } 272 throw new ValueFormatException(value, getPropertyType(), GraphI18n.errorConvertingType.text(Path.class.getSimpleName(), 273 Name.class.getSimpleName(), 274 value)); 275 } 276 277 /** 278 * {@inheritDoc} 279 */ 280 public Name create( Reference value ) { 281 throw new ValueFormatException(value, getPropertyType(), 282 GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 283 Reference.class.getSimpleName(), 284 value)); 285 } 286 287 /** 288 * {@inheritDoc} 289 */ 290 public Name create( URI value ) { 291 if (value == null) return null; 292 String asciiString = value.toASCIIString(); 293 // Remove any leading "./" ... 294 if (asciiString.startsWith("./") && asciiString.length() > 2) { 295 asciiString = asciiString.substring(2); 296 } 297 if (asciiString.indexOf('/') == -1) { 298 return create(asciiString); 299 } 300 throw new ValueFormatException(value, getPropertyType(), GraphI18n.errorConvertingType.text(URI.class.getSimpleName(), 301 Path.class.getSimpleName(), 302 value)); 303 } 304 305 /** 306 * {@inheritDoc} 307 * 308 * @see org.jboss.dna.graph.property.ValueFactory#create(java.util.UUID) 309 */ 310 public Name create( UUID value ) throws IoException { 311 throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(), 312 UUID.class.getSimpleName(), 313 value)); 314 } 315 316 /** 317 * {@inheritDoc} 318 */ 319 public Name create( byte[] value ) { 320 // First attempt to create a string from the value, then a long from the string ... 321 return create(getStringValueFactory().create(value)); 322 } 323 324 /** 325 * {@inheritDoc} 326 * 327 * @see org.jboss.dna.graph.property.ValueFactory#create(org.jboss.dna.graph.property.Binary) 328 */ 329 public Name create( Binary value ) throws ValueFormatException, IoException { 330 // First create a string and then create the boolean from the string value ... 331 return create(getStringValueFactory().create(value)); 332 } 333 334 /** 335 * {@inheritDoc} 336 */ 337 public Name create( InputStream stream, 338 long approximateLength ) throws IoException { 339 // First attempt to create a string from the value, then a double from the string ... 340 return create(getStringValueFactory().create(stream, approximateLength)); 341 } 342 343 /** 344 * {@inheritDoc} 345 */ 346 public Name create( Reader reader, 347 long approximateLength ) throws IoException { 348 // First attempt to create a string from the value, then a double from the string ... 349 return create(getStringValueFactory().create(reader, approximateLength)); 350 } 351 352 /** 353 * <p> 354 * {@inheritDoc} 355 * </p> 356 * 357 * @see org.jboss.dna.graph.property.NameFactory#getNamespaceRegistry() 358 */ 359 public NamespaceRegistry getNamespaceRegistry() { 360 return namespaceRegistry; 361 } 362 363 /** 364 * {@inheritDoc} 365 */ 366 @Override 367 protected Name[] createEmptyArray( int length ) { 368 return new Name[length]; 369 } 370 }