View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6   * See the AUTHORS.txt file in the distribution for a full listing of 
7   * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.property.basic;
25  
26  import java.io.InputStream;
27  import java.io.Reader;
28  import java.math.BigDecimal;
29  import java.net.URI;
30  import java.util.Calendar;
31  import java.util.Date;
32  import java.util.UUID;
33  import java.util.regex.Matcher;
34  import java.util.regex.Pattern;
35  import net.jcip.annotations.Immutable;
36  import org.modeshape.common.text.TextDecoder;
37  import org.modeshape.common.util.CheckArg;
38  import org.modeshape.graph.GraphI18n;
39  import org.modeshape.graph.property.Binary;
40  import org.modeshape.graph.property.DateTime;
41  import org.modeshape.graph.property.IoException;
42  import org.modeshape.graph.property.Name;
43  import org.modeshape.graph.property.NameFactory;
44  import org.modeshape.graph.property.NamespaceException;
45  import org.modeshape.graph.property.NamespaceRegistry;
46  import org.modeshape.graph.property.Path;
47  import org.modeshape.graph.property.PropertyType;
48  import org.modeshape.graph.property.Reference;
49  import org.modeshape.graph.property.ValueFactory;
50  import org.modeshape.graph.property.ValueFormatException;
51  
52  /**
53   * The standard {@link ValueFactory} for {@link PropertyType#NAME} values.
54   */
55  @Immutable
56  public class NameValueFactory extends AbstractValueFactory<Name> implements NameFactory {
57  
58      // Non-escaped pattern: (\{([^}]*)\})?(.*)
59      protected static final String FULLY_QUALFIED_NAME_PATTERN_STRING = "\\{([^}]*)\\}(.*)";
60      protected static final Pattern FULLY_QUALIFIED_NAME_PATTERN = Pattern.compile(FULLY_QUALFIED_NAME_PATTERN_STRING);
61  
62      // Original pattern: (([^:/]*):)?([^:]*)
63      private static final String PREFIXED_NAME_PATTERN_STRING = "(([^:/]+):)?([^:]*)";
64      private static final Pattern PREFIXED_NAME_PATTERN = Pattern.compile(PREFIXED_NAME_PATTERN_STRING);
65  
66      private static Name BLANK_NAME;
67      private static Name ANY_NAME;
68  
69      private final NamespaceRegistry namespaceRegistry;
70  
71      public NameValueFactory( NamespaceRegistry namespaceRegistry,
72                               TextDecoder decoder,
73                               ValueFactory<String> stringValueFactory ) {
74          super(PropertyType.NAME, decoder, stringValueFactory);
75          CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry");
76          this.namespaceRegistry = namespaceRegistry;
77      }
78  
79      /**
80       * {@inheritDoc}
81       */
82      public Name create( String value ) {
83          return create(value, getDecoder());
84      }
85  
86      /**
87       * {@inheritDoc}
88       */
89      public Name create( String value,
90                          TextDecoder decoder ) {
91          if (value == null) return null;
92          if (decoder == null) decoder = getDecoder();
93          try {
94              if (value.length() == 0) {
95                  if (BLANK_NAME == null) BLANK_NAME = new BasicName("", "");
96                  return BLANK_NAME;
97              }
98              char firstChar = value.charAt(0);
99              if (value.length() == 1 && firstChar == '*') {
100                 if (ANY_NAME == null) ANY_NAME = new BasicName("", "*");
101                 return ANY_NAME;
102             }
103             if (firstChar != '{') {
104                 // First, see whether the value fits the prefixed name pattern ...
105                 Matcher matcher = PREFIXED_NAME_PATTERN.matcher(value);
106                 if (matcher.matches()) {
107                     String prefix = matcher.group(2);
108                     String localName = matcher.group(3);
109                     // Decode the parts ...
110                     prefix = prefix == null ? "" : decoder.decode(prefix);
111                     localName = decoder.decode(localName);
112                     // Look for a namespace match ...
113                     String namespaceUri = this.namespaceRegistry.getNamespaceForPrefix(prefix);
114                     // Fail if no namespace is found ...
115                     if (namespaceUri == null) {
116                         throw new NamespaceException(GraphI18n.noNamespaceRegisteredForPrefix.text(prefix));
117                     }
118                     return new BasicName(namespaceUri, localName);
119                 }
120             }
121             // If it doesn't fit the prefixed pattern, then try the internal pattern
122             Matcher matcher = FULLY_QUALIFIED_NAME_PATTERN.matcher(value);
123             if (matcher.matches()) {
124                 String namespaceUri = matcher.group(1);
125                 String localName = matcher.group(2);
126                 // Decode the parts ...
127                 return create(namespaceUri, localName, decoder);
128             }
129         } catch (NamespaceException err) {
130             throw new ValueFormatException(value, getPropertyType(),
131                                            GraphI18n.errorConvertingType.text(String.class.getSimpleName(),
132                                                                               Name.class.getSimpleName(),
133                                                                               value), err);
134         }
135         throw new ValueFormatException(value, getPropertyType(), GraphI18n.errorConvertingType.text(String.class.getSimpleName(),
136                                                                                                     Name.class.getSimpleName(),
137                                                                                                     value));
138     }
139 
140     /**
141      * {@inheritDoc}
142      */
143     public Name create( String namespaceUri,
144                         String localName ) {
145         return create(namespaceUri, localName, getDecoder());
146     }
147 
148     /**
149      * {@inheritDoc}
150      */
151     public Name create( String namespaceUri,
152                         String localName,
153                         TextDecoder decoder ) {
154         CheckArg.isNotEmpty(localName, "localName");
155         if (decoder == null) decoder = getDecoder();
156         namespaceUri = namespaceUri != null ? decoder.decode(namespaceUri.trim()) : null;
157         localName = decoder.decode(localName.trim());
158         return new BasicName(namespaceUri, localName);
159     }
160 
161     /**
162      * {@inheritDoc}
163      */
164     public Name create( int value ) {
165         throw new ValueFormatException(value, getPropertyType(),
166                                        GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
167                                                                           Integer.class.getSimpleName(),
168                                                                           value));
169     }
170 
171     /**
172      * {@inheritDoc}
173      */
174     public Name create( long value ) {
175         throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
176                                                                                                     Long.class.getSimpleName(),
177                                                                                                     value));
178     }
179 
180     /**
181      * {@inheritDoc}
182      */
183     public Name create( boolean value ) {
184         throw new ValueFormatException(value, getPropertyType(),
185                                        GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
186                                                                           Boolean.class.getSimpleName(),
187                                                                           value));
188     }
189 
190     /**
191      * {@inheritDoc}
192      */
193     public Name create( float value ) {
194         throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
195                                                                                                     Float.class.getSimpleName(),
196                                                                                                     value));
197     }
198 
199     /**
200      * {@inheritDoc}
201      */
202     public Name create( double value ) {
203         throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
204                                                                                                     Double.class.getSimpleName(),
205                                                                                                     value));
206     }
207 
208     /**
209      * {@inheritDoc}
210      */
211     public Name create( BigDecimal value ) {
212         throw new ValueFormatException(value, getPropertyType(),
213                                        GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
214                                                                           BigDecimal.class.getSimpleName(),
215                                                                           value));
216     }
217 
218     /**
219      * {@inheritDoc}
220      */
221     public Name create( Calendar value ) {
222         throw new ValueFormatException(value, getPropertyType(),
223                                        GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
224                                                                           Calendar.class.getSimpleName(),
225                                                                           value));
226     }
227 
228     /**
229      * {@inheritDoc}
230      */
231     public Name create( Date value ) {
232         throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
233                                                                                                     Date.class.getSimpleName(),
234                                                                                                     value));
235     }
236 
237     /**
238      * {@inheritDoc}
239      * 
240      * @see org.modeshape.graph.property.ValueFactory#create(org.modeshape.graph.property.DateTime)
241      */
242     public Name create( DateTime value ) throws ValueFormatException {
243         throw new ValueFormatException(value, getPropertyType(),
244                                        GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
245                                                                           DateTime.class.getSimpleName(),
246                                                                           value));
247     }
248 
249     /**
250      * {@inheritDoc}
251      */
252     public Name create( Name value ) {
253         return value;
254     }
255 
256     /**
257      * {@inheritDoc}
258      */
259     public Name create( Path value ) {
260         if (value == null) return null;
261         if (!value.isAbsolute() && value.size() == 1) {
262             // A relative name of length 1 is converted to a name
263             Path.Segment segment = value.getLastSegment();
264             // Can only convert if the path has no SNS index ...
265             if (!segment.hasIndex()) return segment.getName();
266         }
267         throw new ValueFormatException(value, getPropertyType(), GraphI18n.errorConvertingType.text(Path.class.getSimpleName(),
268                                                                                                     Name.class.getSimpleName(),
269                                                                                                     value));
270     }
271 
272     /**
273      * {@inheritDoc}
274      */
275     public Name create( Path.Segment segment ) {
276         if (segment == null) return null;
277         // Can only convert if the path has no SNS index ...
278         if (!segment.hasIndex()) return segment.getName();
279         throw new ValueFormatException(segment, getPropertyType(),
280                                        GraphI18n.errorConvertingType.text(Path.Segment.class.getSimpleName(),
281                                                                           Name.class.getSimpleName(),
282                                                                           segment));
283     }
284 
285     /**
286      * {@inheritDoc}
287      */
288     public Name create( Reference value ) {
289         throw new ValueFormatException(value, getPropertyType(),
290                                        GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
291                                                                           Reference.class.getSimpleName(),
292                                                                           value));
293     }
294 
295     /**
296      * {@inheritDoc}
297      */
298     public Name create( URI value ) {
299         if (value == null) return null;
300         String asciiString = value.toASCIIString();
301         // Remove any leading "./" ...
302         if (asciiString.startsWith("./") && asciiString.length() > 2) {
303             asciiString = asciiString.substring(2);
304         }
305         if (asciiString.indexOf('/') == -1) {
306             return create(asciiString);
307         }
308         throw new ValueFormatException(value, getPropertyType(), GraphI18n.errorConvertingType.text(URI.class.getSimpleName(),
309                                                                                                     Path.class.getSimpleName(),
310                                                                                                     value));
311     }
312 
313     /**
314      * {@inheritDoc}
315      * 
316      * @see org.modeshape.graph.property.ValueFactory#create(java.util.UUID)
317      */
318     public Name create( UUID value ) throws IoException {
319         throw new ValueFormatException(value, getPropertyType(), GraphI18n.unableToCreateValue.text(getPropertyType().getName(),
320                                                                                                     UUID.class.getSimpleName(),
321                                                                                                     value));
322     }
323 
324     /**
325      * {@inheritDoc}
326      */
327     public Name create( byte[] value ) {
328         // First attempt to create a string from the value, then a long from the string ...
329         return create(getStringValueFactory().create(value));
330     }
331 
332     /**
333      * {@inheritDoc}
334      * 
335      * @see org.modeshape.graph.property.ValueFactory#create(org.modeshape.graph.property.Binary)
336      */
337     public Name create( Binary value ) throws ValueFormatException, IoException {
338         // First create a string and then create the boolean from the string value ...
339         return create(getStringValueFactory().create(value));
340     }
341 
342     /**
343      * {@inheritDoc}
344      */
345     public Name create( InputStream stream,
346                         long approximateLength ) throws IoException {
347         // First attempt to create a string from the value, then a double from the string ...
348         return create(getStringValueFactory().create(stream, approximateLength));
349     }
350 
351     /**
352      * {@inheritDoc}
353      */
354     public Name create( Reader reader,
355                         long approximateLength ) throws IoException {
356         // First attempt to create a string from the value, then a double from the string ...
357         return create(getStringValueFactory().create(reader, approximateLength));
358     }
359 
360     /**
361      * <p>
362      * {@inheritDoc}
363      * </p>
364      * 
365      * @see org.modeshape.graph.property.NameFactory#getNamespaceRegistry()
366      */
367     public NamespaceRegistry getNamespaceRegistry() {
368         return namespaceRegistry;
369     }
370 
371     /**
372      * {@inheritDoc}
373      */
374     @Override
375     protected Name[] createEmptyArray( int length ) {
376         return new Name[length];
377     }
378 }