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 }