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 }