]> sjero.net Git - linphone/blob - p2pproxy/dependencies-src/jxse-src-2.5/api/src/net/jxta/document/StructuredDocumentFactory.java
74154edd354728cf63ca73aee06a8a4146b97228
[linphone] / p2pproxy / dependencies-src / jxse-src-2.5 / api / src / net / jxta / document / StructuredDocumentFactory.java
1 /*
2  * Copyright (c) 2001-2007 Sun Microsystems, Inc.  All rights reserved.
3  *  
4  *  The Sun Project JXTA(TM) Software License
5  *  
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions are met:
8  *  
9  *  1. Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *  
12  *  2. Redistributions in binary form must reproduce the above copyright notice, 
13  *     this list of conditions and the following disclaimer in the documentation 
14  *     and/or other materials provided with the distribution.
15  *  
16  *  3. The end-user documentation included with the redistribution, if any, must 
17  *     include the following acknowledgment: "This product includes software 
18  *     developed by Sun Microsystems, Inc. for JXTA(TM) technology." 
19  *     Alternately, this acknowledgment may appear in the software itself, if 
20  *     and wherever such third-party acknowledgments normally appear.
21  *  
22  *  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must 
23  *     not be used to endorse or promote products derived from this software 
24  *     without prior written permission. For written permission, please contact 
25  *     Project JXTA at http://www.jxta.org.
26  *  
27  *  5. Products derived from this software may not be called "JXTA", nor may 
28  *     "JXTA" appear in their name, without prior written permission of Sun.
29  *  
30  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
32  *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN 
33  *  MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
34  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
35  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
36  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
37  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
38  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
39  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *  
41  *  JXTA is a registered trademark of Sun Microsystems, Inc. in the United 
42  *  States and other countries.
43  *  
44  *  Please see the license information page at :
45  *  <http://www.jxta.org/project/www/license.html> for instructions on use of 
46  *  the license in source files.
47  *  
48  *  ====================================================================
49  *  
50  *  This software consists of voluntary contributions made by many individuals 
51  *  on behalf of Project JXTA. For more information on Project JXTA, please see 
52  *  http://www.jxta.org.
53  *  
54  *  This license is based on the BSD license adopted by the Apache Foundation. 
55  */
56
57 package net.jxta.document;
58
59
60 import java.io.InputStream;
61 import java.io.Reader;
62 import java.util.HashMap;
63 import java.util.Hashtable;
64 import java.util.Map;
65
66 import java.io.IOException;
67 import java.util.MissingResourceException;
68
69 import java.util.logging.Logger;
70 import java.util.logging.Level;
71 import net.jxta.logging.Logging;
72
73 import net.jxta.util.ClassFactory;
74 import net.jxta.endpoint.MessageElement;
75 import net.jxta.endpoint.TextMessageElement;
76
77
78 /**
79  * A factory for constructing instances of {@link StructuredDocument}.
80  * Behind the scenes, it also provides for the registration of the mime-types
81  * and constructors needed to accomplish the construction. All supported
82  * mime-types will need to register their implementation in this factory.
83  *
84  * @see         net.jxta.document.Document
85  * @see         net.jxta.document.StructuredTextDocument
86  * @see         net.jxta.document.StructuredDocument
87  * @see         net.jxta.document.MimeMediaType
88  */
89 public final class StructuredDocumentFactory extends ClassFactory<MimeMediaType, StructuredDocumentFactory.Instantiator> {
90     
91     /**
92      * Log4J Logger
93      */
94     private static final Logger LOG = Logger.getLogger(StructuredDocumentFactory.class.getName());
95     
96     /**
97      * Interface for instantiators of StructuredDocuments
98      */
99     public interface Instantiator {
100         
101         /**
102          *  For mapping between extensions and MIME types.
103          */
104         class ExtensionMapping extends Object {
105
106             /**
107              * The extension
108              */
109             private final String extension;
110             
111             /**
112              * MIME type it maps to
113              */
114             private final MimeMediaType mimetype;
115             
116             /**
117              *  default constructor
118              */
119             public ExtensionMapping(String extension, MimeMediaType mimetype) {
120                 this.extension = extension;
121                 this.mimetype = (null != mimetype) ? mimetype.intern() : null;
122             }
123             
124             /**
125              * {@inheritDoc}
126              */
127             @Override
128             public boolean equals(Object target) {
129                 if (this == target) {
130                     return true;
131                 }
132                 
133                 if (target instanceof ExtensionMapping) {
134                     ExtensionMapping likeMe = (ExtensionMapping) target;
135
136                     if (!extension.equals(likeMe.extension)) {
137                         return false;
138                     }
139                     
140                     if ((null == mimetype) && (null == likeMe.mimetype)) {
141                         return true;
142                     }
143                     
144                     if ((null == mimetype) || (null == likeMe.mimetype)) {
145                         return false;
146                     }
147                     
148                     return mimetype.equals(likeMe.mimetype);
149                 } else {
150                     return false;
151                 }
152             }
153             
154             /**
155              * {@inheritDoc}
156              */
157             @Override
158             public int hashCode() {
159                 int hash = extension.hashCode();
160                 
161                 if (null != mimetype) {
162                     hash ^= mimetype.hashCode();
163                 }
164                 
165                 return hash;
166             }
167             
168             /**
169              * {@inheritDoc}
170              */
171             @Override
172             public String toString() {
173                 return extension + " -> " + ((null != mimetype) ? mimetype.toString() : "<null>");
174             }
175             
176             /**
177              * Returns the extension which is part of this mapping.
178              *
179              * @return the extension which is part of this mapping.
180              */
181             public String getExtension() {
182                 return extension;
183             }
184             
185             /**
186              * Returns the MIME Media Type which is part of this mapping.
187              *
188              * @return the MIME Media Type which is part of this mapping.
189              */
190             public MimeMediaType getMimeMediaType() {
191                 return mimetype;
192             }
193         }
194         
195         /**
196          * Returns the MIME Media types supported by this this Document per
197          * {@link <a href="http://www.ietf.org/rfc/rfc2046.txt">IETF RFC 2046 <i>MIME : Media Types</i></a>}.
198          *
199          * <p/>JXTA does not currently support the 'Multipart' or 'Message'
200          * media types.
201          *
202          * @return An array of MimeMediaType objects containing the MIME Media Type
203          *  for this Document.
204          */
205         MimeMediaType[] getSupportedMimeTypes();
206         
207         /**
208          * Returns the mapping of file extension and mime-types for this type
209          * of document. The default extension is mapped to the 'null' mime-type
210          * and should only be used if no other mapping matches.
211          *
212          * @return An array of objects containing file extensions
213          */
214         ExtensionMapping[] getSupportedFileExtensions();
215         
216         /**
217          * Create a new structured document of the type specified by doctype.
218          *
219          *  @param mimeType The MIME type to be associated with this instance.
220          *  the base type must be one of the types returned by
221          *  <tt>getSupportedMimeTypes</tt>. Some implementations may accept
222          *  parameters in the params section of the MIME type.
223          *  @param doctype Type for the base node of the document.
224          *  @return StructuredDocument instance.
225          */
226         StructuredDocument newInstance(MimeMediaType mimeType, String doctype);
227         
228         /**
229          * Create a new structured document of the type specified by doctype.
230          *
231          *  @param mimeType The MIME type to be associated with this instance.
232          *  The base type must be one of the types returned by
233          *  <tt>getSupportedMimeTypes</tt>. Some implementations may accept
234          *  parameters in the params section of the MIME type.
235          *  @param doctype Type for the base node of the document.
236          *  @param value Value for the base node of the document.
237          *  @return {@link StructuredDocument} instance.
238          */
239         StructuredDocument newInstance(MimeMediaType mimeType, String doctype, String value);
240         
241         /**
242          *  Create a structured document from a stream containing an appropriately serialized
243          *  instance of the same document.
244          *
245          *  @param mimeType The MIME type to be associated with this instance.
246          *  The base type must be one of the types returned by
247          *  <tt>getSupportedMimeTypes</tt>. Some implementations may accept
248          *  parameters in the params section of the MIME type.
249          *  @param source The {@code Inputstream} from which to read the
250          *  document.
251          *  @return {@link StructuredDocument} instance.
252          *  @throws IOException Thrown for problems reading from the source.
253          */
254         StructuredDocument newInstance(MimeMediaType mimeType, InputStream source) throws IOException;
255     }
256     
257
258     /**
259      *  Interface for instantiators of StructuredTextDocuments
260      */
261     public interface TextInstantiator extends Instantiator {
262         
263         /**
264          *  Create a structured document from a Reader containing an appropriately serialized
265          *  instance of the same document.
266          *
267          *  @param mimeType The MIME type to be associated with this instance.
268          *  The base type must be one of the types returned by
269          *  <tt>getSupportedMimeTypes</tt>. Some implementations may accept
270          *  parameters in the params section of the MIME type.
271          *  @param source {@code Reader} from which to read the instance.
272          *  @return {@link StructuredDocument} instance.
273          *  @throws IOException Thrown for problems reading from the source.
274          */
275         StructuredDocument newInstance(MimeMediaType mimeType, Reader source) throws IOException;
276     }
277     
278     /**
279      *  This class is a singleton. This is the instance that backs the
280      *  static methods.
281      */
282     private static final StructuredDocumentFactory factory = new StructuredDocumentFactory();
283     
284     /**
285      *  This is the map of mime-types and instantiators used by
286      *  <CODE>newStructuredDocument</CODE>.
287      */
288     private final Map<MimeMediaType, Instantiator> encodings = new HashMap<MimeMediaType, Instantiator>();
289     
290     /**
291      *  This is the map of extensions to mime-types used by
292      *  {@link #getMimeTypeForFileExtension(String) }
293      */
294     private final Map<String, MimeMediaType>  extToMime = new HashMap<String, MimeMediaType>();
295     
296     /**
297      *  This is the map of mime-types to extensions used by
298      *  {@link #getFileExtensionForMimeType(MimeMediaType mimetype) }
299      */
300     private final Map<MimeMediaType, String>  mimeToExt = new HashMap<MimeMediaType, String>();
301     
302     /**
303      *  If true then the pre-defined set of StructuredDocument sub-classes has
304      *  been registered from the property containing them.
305      */
306     private boolean loadedProperty = false;
307     
308     /**
309      *  Private constructor. This class is not meant to be instantiated except
310      *  by itself.
311      *
312      */
313     private StructuredDocumentFactory() {}
314     
315     /**
316      *  Registers the pre-defined set of StructuredDocument sub-classes so that
317      *  this factory can construct them.
318      *
319      *  @return true if at least one of the StructuredDocument sub-classes could
320      *  be registered otherwise false.
321      */
322     private synchronized boolean loadProviders() {
323         if (factory.loadedProperty) {
324             return true;
325         }
326
327         factory.loadedProperty = registerProviders(StructuredDocument.class.getName());
328         
329         return factory.loadedProperty;
330     }
331     
332     /**
333      *  {@inheritDoc}
334      */
335     @Override
336     protected Map<MimeMediaType, Instantiator> getAssocTable() {
337         return encodings;
338     }
339     
340     /**
341      *  {@inheritDoc}
342      */
343     @Override
344     protected Class<MimeMediaType> getClassForKey() {
345         return MimeMediaType.class;
346     }
347     
348     /**
349      *  {@inheritDoc}
350      */
351     @Override
352     protected Class<Instantiator> getClassOfInstantiators() {
353         // our key is the doctype names.
354         return Instantiator.class;
355     }
356     
357     /**
358      *  {@inheritDoc}
359      *
360      *  <p/>We override the standard implementation to get the MIME type from
361      *  the class and use that as the key to register the class with the factory.
362      *
363      *  @param className The class name which will be registered.
364      *  @return boolean true if the class was registered otherwise false.
365      */
366     @Override
367     protected boolean registerAssoc(String className) {
368         boolean registeredSomething = false;
369         
370         LOG.finer("Registering : " + className);
371         
372         try {
373             Class docClass = Class.forName(className);
374             
375             Instantiator instantiator = (Instantiator) docClass.getField("INSTANTIATOR").get(null);
376             
377             MimeMediaType[] mimeTypes = instantiator.getSupportedMimeTypes();
378             
379             for (int eachType = 0; eachType < mimeTypes.length; eachType++) {
380                 LOG.finer("   Registering Type : " + mimeTypes[eachType].getMimeMediaType());
381                 registeredSomething |= registerInstantiator(mimeTypes[eachType], instantiator);
382             }
383         } catch (Exception all) {
384             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
385                 LOG.log(Level.WARNING, "Failed to register \'" + className + "\'", all);
386             }
387         }
388         
389         return registeredSomething;
390     }
391     
392     /**
393      *  Returns the preferred extension for a given mime-type. If there is no
394      *  mapping or no preferred extension for this MIME type then <tt>null</tt> is
395      *  returned.
396      *
397      *  @param mimetype the MimeMediaType we wish to know the file extension for.
398      *  @return String containing the extension or null for mime-types with no
399      *  known association.
400      */
401     public static String getFileExtensionForMimeType(MimeMediaType mimetype) {
402         factory.loadProviders();
403         
404         return factory.mimeToExt.get(mimetype.getBaseMimeMediaType());
405     }
406     
407     /**
408      *  Returns the preferred mime-type for a given file extension. If there is
409      *  no mapping then <tt>null</tt> is returned.
410      *
411      *  @param extension The extension we wish to know the mime-type for.
412      *  @return MimeMediaType associated with this file extension.
413      */
414     public static MimeMediaType getMimeTypeForFileExtension(String extension) {
415         factory.loadProviders();
416         
417         MimeMediaType result = factory.extToMime.get(extension);
418         
419         return result;
420     }
421     
422     /**
423      * Register an instantiator object a mime-type of documents to be
424      * constructed.
425      *
426      * @param mimetype   the mime-type associated.
427      * @param instantiator the instantiator that wants to be registered..
428      * @return boolean true   if the instantiator for this mime-type is now
429      * registered. If there was already an instantiator this mime-type then
430      * false will be returned.
431      * @throws SecurityException   there were permission problems registering
432      *  the instantiator.
433      */
434     public static boolean registerInstantiator(MimeMediaType mimetype, Instantiator instantiator) {
435         boolean registered = factory.registerAssoc(mimetype.getBaseMimeMediaType(), instantiator);
436         
437         if (registered) {
438             Instantiator.ExtensionMapping[] extensions = instantiator.getSupportedFileExtensions();
439             
440             for (int eachExt = 0; eachExt < extensions.length; eachExt++) {
441                 if (null != extensions[eachExt].getMimeMediaType()) {
442                     factory.extToMime.put(extensions[eachExt].getExtension(), extensions[eachExt].getMimeMediaType().intern());
443                     
444                     factory.mimeToExt.put(extensions[eachExt].getMimeMediaType(), extensions[eachExt].getExtension());
445                     
446                     // And the base version.
447                     factory.mimeToExt.put(extensions[eachExt].getMimeMediaType().getBaseMimeMediaType(), extensions[eachExt].getExtension());
448                 }
449             }
450         }
451         
452         return registered;
453     }
454     
455     /**
456      * Constructs an instance of {@link StructuredDocument} matching
457      * the mime-type specified by the <CODE>mimetype</CODE> parameter. The
458      * <CODE>doctype</CODE> parameter identifies the base type of the
459      * {@link StructuredDocument}.
460      *
461      * @param mimetype Specifies the mime media type to be associated with
462      *  the {@link StructuredDocument} to be created.
463      * @param doctype Specifies the root type of the {@link StructuredDocument}
464      *  to be created.
465      * @return StructuredDocument The instance of {@link StructuredDocument}
466      *  or null if it could not be created.
467      * @throws NoSuchElementException invalid mime-media-type
468      */
469     public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, String doctype) {
470         factory.loadProviders();
471         
472         Instantiator instantiator = factory.getInstantiator(mimetype.getBaseMimeMediaType());
473         
474         return instantiator.newInstance(mimetype, doctype);
475     }
476     
477     /**
478      * Constructs an instance of {@link StructuredDocument} matching
479      * the mime-type specified by the <CODE>mimetype</CODE> parameter. The
480      * <CODE>doctype</CODE> parameter identifies the base type of the
481      * {@link StructuredDocument}. Value supplies a value for the root
482      * element.
483      *
484      * @param mimetype Specifies the mime media type to be associated with
485      *  the {@link StructuredDocument} to be created.
486      * @param doctype Specifies the root type of the {@link StructuredDocument}
487      *  to be created.
488      * @param value Specifies a value for the root element.
489      * @return StructuredDocument The instance of {@link StructuredDocument}
490      *  or null if it could not be created.
491      * @throws NoSuchElementException if the mime-type has not been registered.
492      */
493     public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, String doctype, String value) {
494         factory.loadProviders();
495         
496         Instantiator instantiator = factory.getInstantiator(mimetype.getBaseMimeMediaType());
497         
498         return instantiator.newInstance(mimetype, doctype, value);
499     }
500     
501     /**
502      * Constructs an instance of {@link StructuredDocument} matching
503      * the mime-type specified by the <CODE>mimetype</CODE> parameter. The
504      * <CODE>doctype</CODE> parameter identifies the base type of the
505      * {@link StructuredDocument}.
506      *
507      * @param mimetype Specifies the mime media type to be associated with the
508      *  {@link StructuredDocument} to be created.
509      * @param stream Contains an InputStream from which the document will be
510      *  constructed.
511      * @return StructuredDocument The instance of {@link StructuredDocument}
512      *  or null if it could not be created.
513      * @throws IOException If there is a problem reading from the stream.
514      * @throws NoSuchElementException if the mime-type has not been registered.
515      */
516     public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, InputStream stream) throws IOException {
517         factory.loadProviders();
518         
519         Instantiator instantiator = factory.getInstantiator(mimetype.getBaseMimeMediaType());
520         
521         return instantiator.newInstance(mimetype, stream);
522     }
523     
524     /**
525      * Constructs an instance of {@link StructuredDocument} matching
526      * the mime-type specified by the <CODE>mimetype</CODE> parameter. The
527      * <CODE>doctype</CODE> parameter identifies the base type of the
528      * {@link StructuredDocument}.
529      *
530      * @param mimetype Specifies the mime media type to be associated with the
531      * {@link StructuredDocument} to be created.
532      * @param reader A Reader from which the document will be constructed.
533      * @return StructuredDocument The instance of {@link StructuredDocument}
534      * or {@code null} if it could not be created.
535      * @throws IOException If there is a problem reading from the stream.
536      * @throws NoSuchElementException if the mime-type has not been registered.
537      * @throws UnsupportedOperationException if the mime-type provided is not
538      * a text oriented MIME type.
539      */
540     public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, Reader reader) throws IOException {
541         factory.loadProviders();
542         
543         Instantiator instantiator = factory.getInstantiator(mimetype.getBaseMimeMediaType());
544         
545         if (!(instantiator instanceof TextInstantiator)) {
546             // XXX 20020502 bondolo@jxta.org we could probably do something
547             // really inefficient that would allow it to work, but better not to.
548             // if ReaderInputStream existed, it would be easy to do.
549             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
550                 LOG.warning( "Document Class \'" + instantiator.getClass().getName() + "\' associated with \'" + mimetype 
551                     + "\' is not a text oriented document");
552             }
553             
554             throw new UnsupportedOperationException( "Document Class '" + instantiator.getClass().getName() 
555                     + "' associated with '" + mimetype + "' is not a text oriented document");
556         }
557         
558         return ((TextInstantiator) instantiator).newInstance(mimetype, reader);
559     }
560     
561     /**
562      * Constructs an instance of {@link StructuredDocument} based upon the
563      * content of the provided message element.
564      *
565      * @param element The message element from which to create the document.
566      * @return StructuredDocument The instance of {@link StructuredDocument}
567      *  or null if it could not be created.
568      * @throws IOException If there is a problem reading from the stream.
569      * @throws NoSuchElementException if the mime-type has not been registered.
570      */
571     public static StructuredDocument newStructuredDocument(MessageElement element) throws IOException {
572         factory.loadProviders();
573         
574         Instantiator instantiator = factory.getInstantiator(element.getMimeType().getBaseMimeMediaType());
575         
576         if ((instantiator instanceof TextInstantiator) && (element instanceof TextMessageElement)) {
577             return ((TextInstantiator) instantiator).newInstance(element.getMimeType(), ((TextMessageElement) element).getReader());
578         } else {
579             return instantiator.newInstance(element.getMimeType(), element.getStream());
580         }
581     }
582 }