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