001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.rdf.serialize;
031
032import java.io.IOException;
033import java.io.StringReader;
034import java.lang.reflect.Array;
035import java.lang.reflect.Field;
036import java.lang.reflect.InvocationTargetException;
037import java.lang.reflect.Method;
038import java.lang.reflect.Type;
039import java.net.MalformedURLException;
040import java.net.URISyntaxException;
041import java.net.URL;
042import java.util.ArrayList;
043import java.util.Arrays;
044import java.util.Collection;
045import java.util.HashMap;
046import java.util.HashSet;
047import java.util.List;
048
049import javassist.Modifier;
050
051import org.openimaj.util.pair.IndependentPair;
052import org.openrdf.model.Statement;
053import org.openrdf.model.URI;
054import org.openrdf.model.Value;
055import org.openrdf.model.impl.LiteralImpl;
056import org.openrdf.model.impl.StatementImpl;
057import org.openrdf.model.impl.URIImpl;
058import org.openrdf.model.impl.ValueFactoryImpl;
059import org.openrdf.model.vocabulary.RDF;
060import org.openrdf.query.BindingSet;
061import org.openrdf.query.BooleanQuery;
062import org.openrdf.query.MalformedQueryException;
063import org.openrdf.query.QueryEvaluationException;
064import org.openrdf.query.QueryLanguage;
065import org.openrdf.query.TupleQuery;
066import org.openrdf.query.TupleQueryResult;
067import org.openrdf.repository.Repository;
068import org.openrdf.repository.RepositoryConnection;
069import org.openrdf.repository.RepositoryException;
070import org.openrdf.repository.sail.SailRepository;
071import org.openrdf.rio.RDFFormat;
072import org.openrdf.rio.RDFParseException;
073import org.openrdf.sail.memory.MemoryStore;
074import org.springframework.core.GenericCollectionTypeResolver;
075
076/**
077 * The RDFSerializer is used to serialise an object to RDF. It will serialise
078 * the object deeply. This class itself does not output any specific RDF
079 * representation but generates triples which is gives to the method
080 * {@link #addTriple(Statement)}. This method must be overridden in a subclass
081 * to provide the actual representation output.
082 * <p>
083 * For example, to output to Turtle, you might use the OpenRDF TurtleWriter to
084 * form a representation of the RDF graph:
085 * <p>
086 * <code><pre>
087 *              StringWriter sw = new StringWriter();
088 *              final TurtleWriter tw = new TurtleWriter( sw );
089 *              RDFSerializer rs = new RDFSerializer()
090 *              {
091 *                      public void addTriple( Statement s )
092 *                      {
093 *                              tw.handleStatement( s );
094 *                      }
095 *              };
096 *              rs.serialize( myObject );
097 *              System.out.println( sw.toString() );
098 *      </pre></code>
099 * <p>
100 * By default the class will only produce triples for fields which have been
101 * annotated with the {@link Predicate} annotation. The annotation gives the URI
102 * used to link the object to its field in the triple. If you wish to attempt to
103 * serialise unannotated fields, then you should use the constructor that takes
104 * a boolean, passing true: {@link #RDFSerializer(boolean)}. This will then
105 * create predicates based on the field name, so field {@code member} will become
106 * predicate {@code hasMember}. Complex fields are serialised into subgraphs and those
107 * graphs have URIs automatically generated for them based on the URI of the object
108 * in which they exist and their name. For example:
109 * <code><pre>
110 *      http://example.com/MyObject
111 *              http://example.com/MyObject_hasMember
112 *              http://example.com/MyObject_member.
113 * </pre></code>
114 * <p>
115 * The {@link #serialize(Object, String)} method requires the URI of the object
116 * to be serialised. This must be decided by the caller and passed in. It is
117 * used to construct URIs for complex fields and predicates (if not given). So,
118 * an object with URI <code>http://example.com/object</code> and a complex field
119 * called <code>field</code> will end up with a triple that links the object to a
120 * subgraph representing the complex object as so: <code><pre>
121 *              http://example.com/object :hasField http://example.com/object_field
122 *      </pre></code>
123 * The name of the subgraph is based on the URI of the object and the name of
124 * the field. The predicate is also automatically generated from the name of the
125 * field. Note that this means you may need to be careful about the names
126 * of the fields. For example, if an object had a complex field
127 * <code>name_first</code> but also had a complex field <code>name</code> that
128 * itself had a complex field <code>first</code> it's possible the same URI may be
129 * generated for both subgraphs.
130 * <p>
131 * Primitive types will be typed with XSD datatypes. For example:
132 * <code><pre>
133 *      example:field example:hasNumber "20"^^xsd:integer
134 * </pre></code>
135 * <p>
136 * Lists and collections are output in one of two ways. By default they are
137 * output as separate triples in an unordered way:
138 * <code><pre>
139 *              @Predicate("http://example.com/hasString")
140 *              String[] strings = new String[] { "one", "two" };
141 * </pre></code>
142 * ...will be output, by default, as:
143 * <code><pre>
144 *      http://example.com/object
145 *                      http://example.com/hasString "one";
146 *                      http://example.com/hasString "two".
147 * </pre></code>
148 * <p>
149 * Alternatively, the {@link RDFCollection} annotation can be used.
150 * When this annotation is used, they are encoded using RDF sequences;
151 * that is as subgraphs where the items have the predicates
152 * <code>rdf:_1, rdf:_2..., rdf:_n</code> and the type <code>rdf:Seq</code>.
153 * This retains the same order for the collection as when serialised.
154 * So the above example would be output as:
155 * <code><pre>
156 *      http://example.com/object
157 *              http://example.com/hasString http://example.com/strings .
158 *      http://example.com/strings
159 *              rdf:type        rdf:Seq;
160 *              rdf:_1  "one";
161 *              rdf:_2  "two".
162 * </pre></code>
163 * <p>
164 * By default the serialisation will also output a triple that gives the class
165 * name of the object which is being serialised. If you do not want this, use
166 * the {@link #setOutputClassNames(boolean)} to turn it off, although this may
167 * cause the deserialization to stop working, if the original fields in the
168 * object are defined as non-concrete classes (e.g. List or Collection
169 * rather than an ArrayList). In this case, the deserialiser attempts to look
170 * for this triple to find the actual class that was serialised.
171 * <p>
172 * The {@link RelationList} annotation allows collections of independent pairs
173 * of URI and Object can be sent to the RDF graph directly without validation.
174 * This is not deserialisable as there's no way for the derserialiser to know
175 * which triples belong in this collection.
176 * <p>
177 * The {@link TripleList} annotation allows members that are collections of
178 * OpenRDF {@link Statement} objects to be sent to the RDF graph directly.
179 * Again, this is not deserialisable as there's no way for the derserialiser to know
180 * which triples belong in this collection.
181 * <p>
182 * This class also provides an unserialisation routine for converting an RDF
183 * graph back into an object graph. Given a string that is an RDF representation
184 * of a graph (serialised with the serialiser), it will return the object.
185 *
186 * @author David Dupplaw (dpd@ecs.soton.ac.uk)
187 * @created 11 Sep 2012
188 * @version $Author$, $Revision$, $Date$
189 */
190public class RDFSerializer
191{
192        /** URI used for temporary graph when loading into a store */
193        public static final String RDF_OPENIMAJ_TMP_GRAPH =
194                        "http://rdf.openimaj.org/tmp/";
195
196        /** Predicate for giving the class name */
197        public static final String RDF_OPENIMAJ_P_CLASSNAME
198                = "http://rdf.openimaj.org/hasClassName/";
199
200        /** Predicate for unnamed collections */
201        public static final String RDF_OPENIMAJ_P_COLLECTIONITEM
202                = "http://rdf.openimaj.org/hasCollectionItem/";
203
204        /** Whether to try to create predicates for unannotated fields */
205        protected boolean autoPredicate = false;
206
207        /** Whether to output class names */
208        protected boolean outputClassNames = true;
209
210        /**
211         * During a serialization, this field contains all the graphs which have
212         * already been written, avoiding duplicate entries in the output as well as
213         * avoiding infinite loops when cycles occur
214         */
215        private HashSet<URI> knownGraphs = null;
216
217        /**
218         * Default constructor
219         */
220        public RDFSerializer()
221        {
222                this( false );
223        }
224
225        /**
226         * Constructor that determines whether to create predicates automatically
227         * when the {@link Predicate} annotation does not exist.
228         *
229         * @param autoPredicate Whether to automatically create predicates
230         */
231        public RDFSerializer( final boolean autoPredicate )
232        {
233                this.autoPredicate = autoPredicate;
234        }
235
236        /**
237         * Serialize the given object as RDF.
238         *
239         * @param objectToSerialize The object to serialize.
240         * @param uri The URI of the object to serialize.
241         * @return Returns the URI of the object (this may be different to the one
242         *         that's passed in)
243         */
244        public URI serialize( final Object objectToSerialize, final String uri )
245        {
246                this.knownGraphs = new HashSet<URI>();
247                final URI i = this.serializeAux( objectToSerialize, uri );
248                return i;
249        }
250
251        /**
252         * Serialize the given object as RDF.
253         *
254         * @param objectToSerialize The object to serialize.
255         * @param uri The URI of the object to serialize.
256         * @return Returns the URI of the object (this may be different to the one
257         *         that's passed in)
258         */
259        public URI serializeAux( final Object objectToSerialize, final String uri )
260        {
261                return this.serializeAux( objectToSerialize, uri, true );
262        }
263
264        /**
265         * Serialize the given object as RDF. This is specifically designed for
266         * calling by the process outputting collections.
267         *
268         * @param objectToSerialize The object to serialize.
269         * @param uri The URI of the object to serialize.
270         * @param outputCollectionObjects Whether to output items in a collection
271         * @return Returns the URI of the object (this may be different to the one
272         *         that's passed in)
273         */
274        public URI serializeAux( final Object objectToSerialize, final String uri,
275                        final boolean outputCollectionObjects )
276        {
277                // The subject (the object to serialize) won't change, so
278                // we'll just create the URI node once.
279                URIImpl subject = new URIImpl( uri );
280
281                // Find the object URI
282                subject = this.getObjectURI( objectToSerialize, subject );
283
284                // Check whether we've already serialized this object. If we have
285                // we just return, otherwise we add it to our memory of serialized
286                // objects so that we won't try again.
287                if( this.knownGraphs.contains( subject ) )
288                        return subject;
289
290                this.knownGraphs.add( subject );
291
292                // Output the class name of the object to serialise
293                if( this.outputClassNames )
294                        this.addTriple( new StatementImpl( subject, new URIImpl(
295                                        RDFSerializer.RDF_OPENIMAJ_P_CLASSNAME ), this
296                                        .checkPrimitive( objectToSerialize.getClass().getName() ) ) );
297
298                // Check whether there's a semantic type for this object
299                final RDFType typeAnnotation = objectToSerialize.getClass()
300                                .getAnnotation( RDFType.class );
301
302                // If there is a type anotation, add it as a triple in the graph.
303                if( typeAnnotation != null )
304                        this.addTriple( new StatementImpl( subject, RDF.TYPE, new URIImpl(
305                                        typeAnnotation.value() ) ) );
306
307                // If this top-level object is a collection, we obviously
308                // have no predicate for all the items in the collection,
309                // so we will output them all linked to the subject URI by
310                // way of the OpenIMAJ hasCollectionItem predicate. This functionality
311                // can be disabled by passing in outputCollectionObjects as false,
312                // which the processCollection() method does when serializing collections.
313                // It does this because it will have already output the list items for
314                // a collection object, but will have recursed here to allow the other
315                // fields in the collection object to be serialized.
316                if( objectToSerialize instanceof Collection && outputCollectionObjects )
317                {
318                        this.processCollection( subject, new URIImpl(RDFSerializer.RDF_OPENIMAJ_P_COLLECTIONITEM),
319                                        subject, "", objectToSerialize, false );
320
321                        // We will still carry on and serialize the other parts
322                        // of this object...
323                }
324
325                // Get all the fields
326                final List<Field> fields = this.getAllFields( objectToSerialize );
327
328                // Loop through the fields and output them one at a time
329                for( final Field field : fields )
330                {
331                        // We won't output static members
332                        if( Modifier.isStatic( field.getModifiers() ) )
333                                continue;
334
335                        // System.out.println( "====== Field "+field+" ============");
336
337                        try
338                        {
339                                // Get the value of the field
340                                field.setAccessible( true );
341                                final Object oo = field.get( objectToSerialize );
342
343                                // Special fields have annotations which mean they will be
344                                // output in some other way, as defined in the outputSpecial()
345                                // method. If this field is not one of those, we'll output
346                                // in the normal way.
347                                if( !this.outputSpecial( oo, field, subject ) )
348                                {
349                                        // Get the predicate name (may be null if if cannot be
350                                        // created either due to a lack of the @Predicate
351                                        // annotation or because autoPredicate is false
352                                        final URIImpl predicate = this.getPredicateName( field, uri );
353
354                                        // If the predicate is null, we can't output this object.
355                                        // Otherwise, we'll go ahead and output it.
356                                        if( predicate != null )
357                                                this.processObject( subject, predicate, field.getName(), oo,
358                                                        field.getAnnotation( RDFCollection.class ) != null );
359                                }
360                        }
361                        catch( final Exception e )
362                        {
363                                System.out.println( "Error reflecting " + field );
364                                e.printStackTrace();
365                        }
366                }
367
368                return subject;
369        }
370
371        /**
372         *      Serialises a single object into the graph using the given
373         *      subject and predicate in the triple.
374         *
375         *      @param subject The URI of the subject being serialised
376         *      @param predicate The URI of the predicate for this member
377         *      @param field The name of the field being serialised
378         *      @param oo The object being serialised
379         *      @param asCollection Whether the field should be output as
380         *              an {@link RDFCollection}
381         */
382        private void processObject( final URIImpl subject, final URIImpl predicate,
383                        final String fieldName, final Object oo, final boolean asCollection )
384        {
385                // Get the URI of the subject (the object we're serialising)
386                final String uri = subject.stringValue();
387
388                // If the value of the object to output is not null, we go ahead
389                // and serialise the object.
390                if( oo != null && predicate != null )
391                {
392                        // This will be the value of the object we're outputting.
393                        // It'll be a URI for complex objects.
394                        Value object;
395
396                        // This value will give whether we're outputting a collection object.
397                        // That also includes Arrays.
398                        boolean isCollective = false;
399
400                        // Check if we should output a primitive value. If so, we're done.
401                        // Otherwise, we'll need to do some more complex analysis...
402                        if( (object = this.checkPrimitive( oo )) == null )
403                        {
404                                // Get a URI for this object
405                                final URIImpl objectURI = this.getObjectURI(
406                                                oo, new URIImpl(
407                                                        subject.stringValue() + "_" + fieldName ) );
408
409                                // If oo is an array, we'll call the processArray() method
410                                // to output it. The object becomes a URI to the array subgraph.
411                                if( oo.getClass().isArray() )
412                                {
413                                        isCollective = true;
414                                        object = this.processArray( subject, predicate, objectURI,
415                                                        fieldName, oo, asCollection );
416                                }
417                                else
418                                // If we have a collection of things, we'll output
419                                // them as an RDF linked-list. The object becomes a URI
420                                // to the collection's subgraph.
421                                if( oo instanceof Collection<?> )
422                                {
423                                        isCollective = true;
424                                        object = this.processCollection( subject, predicate, objectURI,
425                                                        fieldName, oo, asCollection );
426                                }
427                                // Not a primitive, array or collection?  Must be a
428                                // regular object, so we'll recurse this process with
429                                // the value of the field.
430                                else
431                                {
432                                        // The URI is the uri of the subject concatenated
433                                        // with the name of the field from which this value
434                                        // was taken.
435                                        object = new URIImpl( uri + "_"
436                                                        + fieldName );
437
438                                        // Here's the recursive call to the process
439                                        object = this.serializeAux( oo, object.stringValue() );
440                                }
441                        }
442
443                        // We don't need to add this triple if the triples are a
444                        // are collection that's been output separately
445                        if( !isCollective || (isCollective && asCollection) )
446                        {
447                                // Create a triple and send it to the serializer
448                                final Statement t = new StatementImpl( subject,
449                                                predicate, object );
450                                this.addTriple( t );
451                        }
452                }
453        }
454
455        /**
456         *      Processes an array object outputting triples for the entire array.
457         *      Returns the Value linking to this array.
458         *
459         *      @param subject The URI of the object to serialise
460         *      @param predicate The predicate between the subject and this array
461         *      @param collectionURI The URI of the collection subgraph
462         *      @param field The field in the object that's the array
463         *      @param arrayObject The array object
464         *      @param asCollection Whether to output as an RDF Collection
465         *      @return The object linking to this array
466         */
467        private Value processArray( final URIImpl subject, final URIImpl predicate,
468                        final URIImpl collectionURI, final String fieldName,
469                        final Object arrayObject, final boolean asCollection )
470        {
471                // Loop through all the array elements and output them separately.
472                for( int count = 0; count < Array.getLength( arrayObject ); )
473                {
474                        // Get the array element value..
475                        final Object o = Array.get( arrayObject, count );
476
477                        // Call the processListitemObject to output the actual value.
478                        // We call this method rather than the serializeAux() method because
479                        // we need to deal with the various methods for outputting collections
480                        // in one single place (e.g. as a collection, or an RDF sequence, etc.)
481                        count = this.processListItemObject( subject, predicate, collectionURI,
482                                        count, o, asCollection );
483                }
484
485                return collectionURI;
486        }
487
488        /**
489         *      Processes a collection object.
490         *
491         *      @param subject The URI of the object we're serializing
492         *      @param predicate The predicate for this collection
493         *      @param collectionURI The URI of the collection subgraph
494         *      @param field The field in the object that is the collection
495         *      @param collectionObject The collection object
496         *      @param asCollection Whether to output as an RDF collection
497         *      @return The object created for this collection
498         */
499        private Value processCollection( final URIImpl subject, final URIImpl predicate,
500                        final URIImpl collectionURI, final String fieldName,
501                        final Object collectionObject, final boolean asCollection )
502        {
503                // Loop through all the collection items outputting them one at a time.
504                int count = 1;
505                for( final Object o : (Collection<?>) collectionObject )
506                {
507                        // We call this method rather than the serializeAux() method because
508                        // we need to deal with the various methods for outputting collections
509                        // in one single place (e.g. as a collection, or an RDF sequence, etc.)
510                        count = this.processListItemObject( subject, predicate, collectionURI,
511                                        count, o, asCollection );
512                }
513
514                // We also need to serialize the object itself because if
515                // The collection is actually a subclass that contains
516                // @Predicate annotations we need to go ahead and
517                // serialise those too; so we recurse here.
518                final Value object = this.serializeAux( collectionObject,
519                                collectionURI.stringValue(), false );
520
521                return object;
522        }
523
524        /**
525         * A method that's called during the processing of a list of items to write
526         * a single item.
527         *
528         * @param subject The URI of the object in which this collection exists
529         * @param predicate The predicate of the collection in the original graph
530         * @param collectionURI The URI of the collection in the graph
531         * @param listCounter The current counter in the list (1-based index)
532         * @param listItemObject The object to be serialised
533         * @param asSequence Whether to output as an RDF Sequence
534         *                      or as individual triples
535         * @return the next counter in the list
536         */
537        private int processListItemObject(
538                        URIImpl subject, URIImpl predicate,
539                        final URIImpl collectionURI,
540                        final int listCounter, final Object listItemObject,
541                        final boolean asSequence )
542        {
543                // If we're outputting as a sequence, then we must
544                // alter the predicate and therefore the subject
545                if( asSequence )
546                {
547                        // If we're outputting as an RDF sequence the predicate
548                        // becomes the rdf:_n counter predicate and the subject
549                        // will be the URI of the collection
550                        predicate = new URIImpl( RDF.NAMESPACE + "_" + listCounter );
551                        subject = collectionURI;
552                }
553
554                // Check whether the list item is a primitive. If it is, its
555                // value will be output directly into the collection, otherwise
556                // we need to output a subgraph URI instead.
557                Value oo = null;
558                oo = this.checkPrimitive( listItemObject );
559
560                // If list item isn't a primitive, get a URI for it.
561                if( oo == null )
562                {
563                        // Get the URI for the list item object.
564                        oo = this.getObjectURI( listItemObject,
565                                new URIImpl( collectionURI.stringValue()
566                                                + "_listItem"+listCounter ) );
567
568                        // We're here because the list item is not a primitive - it's a
569                        // complex object or a collection; in which case we must
570                        // link to a subgraph and output that subgraph.
571                        this.addTriple( new StatementImpl( subject, predicate, oo ) );
572
573                        // Now we serialize the object into the graph
574                        this.serializeAux( listItemObject, oo.stringValue() );
575                }
576                // Output the primitive triple
577                else
578                {
579                        this.addTriple( new StatementImpl( subject, predicate, oo ) );
580                }
581
582                return listCounter + 1;
583        }
584
585        /**
586         * Returns a predicate name for the given field.
587         *
588         * @param field The field
589         * @param uri The URI of the object
590         * @return A predicate URI, either generated from the @Predicate annotation
591         *         or from the field name
592         */
593        private URIImpl getPredicateName( final Field field, final String uri )
594        {
595                // Get the predicate annotation, if there is one
596                final Predicate predicateAnnotation = field
597                                .getAnnotation( Predicate.class );
598
599                URIImpl predicate = null;
600                if( predicateAnnotation != null )
601                {
602                        // Create a predicate URI for this predicate
603                        predicate = new URIImpl( predicateAnnotation.value() );
604                }
605                // Null predicate annotation?
606                else
607                {
608                        // Try to create a predicate for the unannotated field
609                        if( this.autoPredicate )
610                                predicate = new URIImpl( uri + "_has"
611                                                + field.getName().substring( 0, 1 ).toUpperCase()
612                                                + field.getName().substring( 1 ) );
613                }
614
615                return predicate;
616        }
617
618        /**
619         * Checks whether the given object is a primitive type and, if so, will
620         * return a Node that encodes it. Otherwise NULL is returned.
621         *
622         * @param o The object to check
623         * @return a Node or NULL
624         */
625        private Value checkPrimitive( final Object o )
626        {
627                if( o instanceof String ) return new LiteralImpl( o.toString() );
628
629                if( o instanceof Integer )
630                        return new ValueFactoryImpl().createLiteral( (Integer) o );
631
632                if( o instanceof Float )
633                        return new ValueFactoryImpl().createLiteral( (Float) o );
634
635                if( o instanceof Double )
636                        return new ValueFactoryImpl().createLiteral( (Double) o );
637
638                if( o instanceof URI || o instanceof URL || o instanceof java.net.URI )
639                        return new URIImpl( o.toString() );
640
641                return null;
642        }
643
644        /**
645         * Returns a list of declared fields from the whole object tree.
646         *
647         * @param o The object
648         * @return A list of fields
649         */
650        private List<Field> getAllFields( final Object o )
651        {
652                final ArrayList<Field> fields = new ArrayList<Field>();
653                Class<?> objectToGetFieldsFrom = o.getClass();
654                do
655                {
656                        fields.addAll( Arrays.asList( objectToGetFieldsFrom
657                                        .getDeclaredFields() ) );
658                        objectToGetFieldsFrom = objectToGetFieldsFrom.getSuperclass();
659                }
660                while( !objectToGetFieldsFrom.getSimpleName().equals( "Object" ) );
661
662                return fields;
663        }
664
665        /**
666         * Set whether to output class names as triples.
667         *
668         * @param tf TRUE to output class name triples.
669         */
670        public void setOutputClassNames( final boolean tf )
671        {
672                this.outputClassNames = tf;
673        }
674
675        /**
676         * Set whether to attempt to output all fields from the objects, not just
677         * those annotated with {@link Predicate}.
678         *
679         * @param tf TRUE to attempt to find predicates for all members.
680         */
681        public void setAutoPredicate( final boolean tf )
682        {
683                this.autoPredicate = tf;
684        }
685
686        /**
687         * Unserializes an object from the given RDF string (with the given format)
688         * into the given object.
689         *
690         * @param <T> Type of object being unserialised
691         *
692         * @param objectToUnserialize The object to populate
693         * @param objectRootURI The URI that gives the root of the object graph
694         * @param rdf The RDF string
695         * @param rdfFormat The format of the RDF in the string
696         * @return The populated object or NULL if an error occurs
697         */
698        public <T> T unserialize( final T objectToUnserialize,
699                        final String objectRootURI, final String rdf,
700                        final RDFFormat rdfFormat )
701        {
702                try
703                {
704                        // We'll read the RDF into a memory store. So create that store
705                        // here.
706                        final Repository repo = new SailRepository( new MemoryStore() );
707                        repo.initialize();
708
709                        // Read the RDF into the store
710                        final RepositoryConnection connection = repo.getConnection();
711                        final StringReader sr = new StringReader( rdf );
712                        final String graphURI = RDFSerializer.RDF_OPENIMAJ_TMP_GRAPH;
713                        connection.add( sr, graphURI, rdfFormat );
714
715                        // Now unserialize the object
716                        return this.unserialize( objectToUnserialize, objectRootURI, repo );
717                }
718                catch( final RepositoryException e )
719                {
720                        e.printStackTrace();
721                        return null;
722                }
723                catch( final RDFParseException e )
724                {
725                        e.printStackTrace();
726                        return null;
727                }
728                catch( final IOException e )
729                {
730                        e.printStackTrace();
731                        return null;
732                }
733        }
734
735        /**
736         * Unserializes an object from an RDF graph that is rooted at the given URI.
737         *
738         * @param <T> Type of object being unserialised
739         *
740         * @param objectToUnserialize The object to populate
741         * @param objectRootURI The URI that gives the root of the object graph
742         * @param repo The repository storing the RDF graph
743         * @return The populated object or NULL if an error occurs
744         */
745        public <T> T unserialize( final T objectToUnserialize,
746                        final String objectRootURI, final Repository repo )
747        {
748                // Can't do anything if the object is null
749                if( objectToUnserialize == null )
750                {
751                        System.err.println( "Unserialize error: given object is null" );
752                        return null;
753                }
754
755                // If our starting object is a collection, then there will be no
756                // predicate for us to work with. So we'll get the items from the
757                // collection using the statically defined predicate
758                // RDF_OPENIMAJ_P_COLLECTIONITEM. We will still need to deserialise
759                // the object after this, in case the collection has any
760                // predicated members that need to be deserialised.
761                if( objectToUnserialize instanceof Collection<?> )
762                        this.extractCollectionDirect( (Collection<?>)objectToUnserialize,
763                                        objectRootURI, repo );
764
765                try
766                {
767                        final RepositoryConnection connection = repo.getConnection();
768
769                        // Get the fields of the object's class
770                        final Field[] fields = objectToUnserialize.getClass().getFields();
771
772                        // Loop through the fields
773                        for( final Field field : fields )
774                        {
775//                              System.out.println( "=========== Field "+field.getName()+" ============= ");
776
777                                try
778                                {
779                                        // Get the name of the predicate for this field
780                                        final URIImpl predicateName = this.getPredicateName( field,
781                                                        objectRootURI );
782
783                                        // If we can't determine a predicate, we don't unserialize it
784                                        if( predicateName != null )
785                                        {
786                                                // If it's a collection, we'll do something special
787                                                if( Collection.class.isAssignableFrom( field.getType() ) )
788                                                {
789                                                        this.unserializeCollection( field, objectToUnserialize,
790                                                                        objectRootURI, repo, predicateName );
791                                                }
792                                                else
793                                                // Same goes for if it's an array.
794                                                if( ((Class<?>) field.getType()).isArray() )
795                                                {
796                                                        this.unserializeArray( objectToUnserialize,
797                                                                        objectRootURI, repo, field, predicateName );
798                                                }
799                                                // If we don't know what it is, we'll treat it as
800                                                // an unknown (RDF) serializable object and recurse
801                                                else
802                                                {
803                                                        // Query the RDF graph for the triples that represent
804                                                        // this field in the graph. If there are more
805                                                        // than one, the first will be used.
806                                                        try
807                                                        {
808                                                                final String queryString = "SELECT ?o WHERE {<"
809                                                                                + objectRootURI + "> <" + predicateName
810                                                                                + "> ?o.}";
811                                                                final TupleQuery tupleQuery = connection
812                                                                                .prepareTupleQuery( QueryLanguage.SPARQL,
813                                                                                                queryString );
814                                                                final TupleQueryResult result = tupleQuery
815                                                                                .evaluate();
816
817                                                                // We only want the first result because we know
818                                                                // it's not a collection
819                                                                if( result.hasNext() )
820                                                                {
821                                                                        try
822                                                                        {
823                                                                                final BindingSet bindingSet = result.next();
824                                                                                final Value objectValue = bindingSet
825                                                                                                .getValue( "o" );
826
827                                                                                // We have a value for the field. Now what
828                                                                                // we do with it depends on the field itself.
829                                                                                field.setAccessible( true );
830                                                                                field.set( objectToUnserialize,
831                                                                                        this.getFieldValue(
832                                                                                                field.getGenericType(),
833                                                                                                objectValue, repo,
834                                                                                                field.getName(),
835                                                                                                objectRootURI ) );
836                                                                        }
837                                                                        catch( final IllegalArgumentException e )
838                                                                        {
839                                                                                e.printStackTrace();
840                                                                        }
841                                                                        catch( final IllegalAccessException e )
842                                                                        {
843                                                                                e.printStackTrace();
844                                                                        }
845                                                                }
846                                                                else
847                                                                {
848                                                                        // RDF Graph did not have a value for the field
849                                                                }
850                                                        }
851                                                        catch( final MalformedQueryException e )
852                                                        {
853                                                                e.printStackTrace();
854                                                        }
855                                                        catch( final QueryEvaluationException e )
856                                                        {
857                                                                e.printStackTrace();
858                                                        }
859                                                }
860                                        }
861                                }
862                                catch( final IllegalArgumentException e )
863                                {
864                                        e.printStackTrace();
865                                }
866                                catch( final IllegalAccessException e )
867                                {
868                                        e.printStackTrace();
869                                }
870                        }
871
872                        connection.close();
873                }
874                catch( final RepositoryException e )
875                {
876                        e.printStackTrace();
877                }
878                catch( final SecurityException e )
879                {
880                        e.printStackTrace();
881                }
882
883                return objectToUnserialize;
884        }
885
886        /**
887         *      @param objectToUnserialize
888         *      @param objectRootURI
889         *      @param repo
890         */
891        @SuppressWarnings( "unchecked" )
892        private <T extends Collection<?>> void extractCollectionDirect(
893                        final T objectToUnserialize,
894                        final String objectRootURI, final Repository repo )
895        {
896                final Class<?> collectionType =
897                                GenericCollectionTypeResolver.getCollectionType(
898                                                objectToUnserialize.getClass() );
899
900                // TODO: This needs to be sorted out. We can't pass null.
901                // Unserialize the collection items.
902                final Object[] seq = this.extractCollectionObjects(
903                                objectRootURI, repo, collectionType,
904                                "", objectRootURI,
905                                RDFSerializer.RDF_OPENIMAJ_P_COLLECTIONITEM );
906
907                ((Collection<Object>)objectToUnserialize).clear();
908                for( int i = 0; i < seq.length; i++ )
909                        ((Collection<Object>)objectToUnserialize).add( seq[i] );
910        }
911
912        /**
913         *      Unserializes an array object from the graph.
914         *
915         *      @param objectToUnserialize The object in which there is an array field
916         *      @param objectRootURI The URI of the object in which there is an array field
917         *      @param repo The repository containing the RDF graph
918         *      @param field The field that is the array
919         *      @param predicateName The name of the predicate for the array items
920         *      @throws IllegalAccessException If the field cannot be set
921         */
922        private <T> void unserializeArray( final T objectToUnserialize,
923                        final String objectRootURI, final Repository repo, final Field field,
924                        final URIImpl predicateName ) throws IllegalAccessException
925        {
926                final Class<?> componentType = field.getType().getComponentType();
927
928                // Go get all the array objects
929                @SuppressWarnings( "unchecked" )
930                final T[] seq = (T[])this
931                                .extractCollectionObjects( objectRootURI, repo,
932                                                componentType, field.getName(),
933                                                objectRootURI, predicateName
934                                                                .stringValue() );
935
936                // Set the field up
937                field.setAccessible( true );
938                field.set( objectToUnserialize, seq );
939        }
940
941        /**
942         *      Unserializes a collection object from the graph. This method is mainly
943         *      dealing with setting up the appropriate collection instance before calling
944         *      {@link #extractCollectionObjects(String, Repository, Class, Field, String, String)}
945         *      to actually get the objects.
946         *
947         *      @param field The field which is the collection
948         *      @param objectToUnserialize The object in which the field exists
949         *      @param objectRootURI The URI of the object in which the field exists
950         *      @param repo The repository containing the RDF graph
951         *      @param predicateURI The name of the predicate for the collection items.
952         */
953        private void unserializeCollection( final Field field,
954                        final Object objectToUnserialize, final String objectRootURI,
955                        final Repository repo, final URIImpl predicateURI )
956        {
957                // If we have a collection object, then we can do something
958                // a bit different here. We know it's a collection, so we
959                // simply iterate through the sequence getting each item in
960                // turn and deserialize it.
961                if( Collection.class.isAssignableFrom( field.getType() ) )
962                {
963                        try
964                        {
965                                // We get the class from the object that we're populating
966                                Class<?> cls = field.getType();
967
968                                // Attempt to instantiate the new object.
969                                // This may fail if the object does not have a
970                                // default or accessible constructor. In which case
971                                // we'll ignore the object here.
972                                Object newInstance;
973                                try
974                                {
975                                        newInstance = cls.newInstance();
976                                }
977                                catch( final InstantiationException e )
978                                {
979                                        cls = (Class<?>)this.getObjectClass(
980                                                objectRootURI+"_"+field.getName(), repo );
981
982                                        // If we can't get a class to instantiate,
983                                        // we cannot do anything. Probably the field was null.
984                                        if( cls == null ) return;
985
986                                        newInstance = cls.newInstance();
987                                }
988
989                                // Cast to a collection
990                                @SuppressWarnings( "unchecked" )
991                                final Collection<Object> collection =
992                                                (Collection<Object>) newInstance;
993
994                                // We must clear the collection here. We will populate
995                                // it will everything that was in it when it was created,
996                                // and if the constructor adds stuff to the collection,
997                                // this will end up with a collection that is not the same
998                                // as the original.
999                                collection.clear();
1000
1001                                // Get the collection of the type
1002                                Class<?> collectionType = null;
1003                                collectionType = GenericCollectionTypeResolver
1004                                                .getCollectionFieldType( field );
1005
1006                                // Now unserialise the collection.
1007                                final Object[] seq = this.extractCollectionObjects(
1008                                                objectRootURI, repo, collectionType,
1009                                                field.getName(), objectRootURI, predicateURI.stringValue() );
1010
1011                                // If we have some stuff, then put it into the field.
1012                                if( seq != null )
1013                                {
1014                                        // Add all the extracted objects into the collection
1015                                        for( int i = 0; i < seq.length; i++ )
1016                                                collection.add( seq[i] );
1017
1018                                        // Set the field value to the new collection
1019                                        field.setAccessible( true );
1020                                        field.set( objectToUnserialize, collection );
1021                                }
1022                        }
1023                        catch( final SecurityException e )
1024                        {
1025                                e.printStackTrace();
1026                        }
1027                        catch( final IllegalArgumentException e )
1028                        {
1029                                e.printStackTrace();
1030                        }
1031                        catch( final InstantiationException e1 )
1032                        {
1033                                e1.printStackTrace();
1034                        }
1035                        catch( final IllegalAccessException e )
1036                        {
1037                                e.printStackTrace();
1038                        }
1039                }
1040                else
1041                {
1042                        System.out.println( "WARNING: Unserialize collection called for" +
1043                                        " something that's not a collection.");
1044                }
1045        }
1046
1047        /**
1048         * Returns an object extracted from the OpenRDF {@link Value} for this field.
1049         * If it's a primitive type, the object will be that primitive type.
1050         * Otherwise, the object will be deserialised and its reference passed back.
1051         *
1052         * @param type The type of the field
1053         * @param value The RDF value object for the field.
1054         * @param repo The RDF Graph repository in use.
1055         * @param fieldName The field name
1056         * @param subjectURI The URI of the object
1057         * @return The deserialised object.
1058         */
1059        private Object getFieldValue( final Type type, final Value value,
1060                        final Repository repo, final String fieldName,
1061                        final String subjectURI )
1062        {
1063                try
1064                {
1065                        // ---- String value ----
1066                        if( type.equals( String.class ) )
1067                        {
1068                                return value.stringValue();
1069                        }
1070                        // ---- URI or URL values ----
1071                        else if( type.equals( java.net.URI.class ) )
1072                        {
1073                                try
1074                                {
1075                                        return new java.net.URI( value.toString() );
1076                                }
1077                                catch( final URISyntaxException e )
1078                                {
1079                                        e.printStackTrace();
1080                                }
1081                        }
1082                        // ---- URI or URL values ----
1083                        else if( type.equals( URL.class ) )
1084                        {
1085                                try
1086                                {
1087                                        return new URL( value.toString() );
1088                                }
1089                                catch( final MalformedURLException e )
1090                                {
1091                                        e.printStackTrace();
1092                                }
1093                        }
1094                        // ---- Integer values ----
1095                        else if( type.equals( Integer.class )
1096                                        || type.equals( int.class ) )
1097                        {
1098                                return Integer.parseInt( value.stringValue() );
1099                        }
1100                        // ---- Double values ----
1101                        else if( type.equals( Double.class )
1102                                        || type.equals( double.class ) )
1103                        {
1104                                return Double.parseDouble( value.stringValue() );
1105                        }
1106                        // ---- Float values ----
1107                        else if( type.equals( Float.class )
1108                                        || type.equals( float.class ) )
1109                        {
1110                                return Float.parseFloat( value.stringValue() );
1111                        }
1112                        // ---- Other complex objects ----
1113                        else
1114                        {
1115                                // The object is not a default type that we understand.
1116                                // So what we must do is try to instantiate the object,
1117                                // then attempt to deserialize that object, then set the field
1118                                // in this object.
1119                                try
1120                                {
1121                                        if( value instanceof URI )
1122                                        {
1123                                                String objectURI = value.stringValue();
1124
1125                                                // Try and look up the className predicate of the
1126                                                // object.
1127                                                Type type2 = this.getObjectClass( objectURI, repo );
1128                                                if( type2 == null )
1129                                                        type2 = this.getObjectClass( objectURI = subjectURI
1130                                                                        + "_" + fieldName, repo );
1131
1132                                                // Attempt to instantiate the new object.
1133                                                // This may fail if the object does not have a
1134                                                // default or accessible constructor.
1135                                                final Object newInstance = ((Class<?>) type2)
1136                                                                .newInstance();
1137
1138                                                // Now recurse the unserialization down the object tree,
1139                                                // by attempting to unserialize the given object.
1140                                                return this.unserialize( newInstance, objectURI, repo );
1141                                        }
1142                                        else
1143                                        {
1144                                                System.out
1145                                                                .println( "WARNING: I don't know what to do with "
1146                                                                                + value );
1147                                        }
1148                                }
1149                                catch( final InstantiationException e )
1150                                {
1151                                        e.printStackTrace();
1152                                }
1153                        }
1154                }
1155                catch( final IllegalArgumentException e )
1156                {
1157                        e.printStackTrace();
1158                }
1159                catch( final IllegalAccessException e )
1160                {
1161                        e.printStackTrace();
1162                }
1163
1164                return null;
1165        }
1166
1167        /**
1168         *      Returns whether the collection given by collectionURI is an RDF sequence
1169         *      or not. It does this by asking the SPARQL store whether the URI has the
1170         *      type rdf:Seq.
1171         *
1172         *      @param repo The repository containing the graph
1173         *      @param collectionURI The URI of the collection to check
1174         *      @return TRUE if the collection is of type rdf:Seq; FALSE otherwise or
1175         *              if an error occurs.
1176         */
1177        private boolean isRDFSequence( final Repository repo, final String collectionURI )
1178        {
1179                // Before we retrieve the objects from the sequence, we'll first
1180                // double check that it really is a sequence. If it's not (it's a
1181                // collection of unordered triples), then we'll treat it differently.
1182                try
1183                {
1184                        final RepositoryConnection c = repo.getConnection();
1185                        final String queryString = "ASK {<" + collectionURI + "> <"
1186                                        + RDF.TYPE + "> <" + RDF.SEQ + ">}";
1187                        final BooleanQuery query = c.prepareBooleanQuery(
1188                                        QueryLanguage.SPARQL, queryString );
1189                        return query.evaluate();
1190                }
1191                catch( final RepositoryException e1 )
1192                {
1193                        e1.printStackTrace();
1194                }
1195                catch( final MalformedQueryException e1 )
1196                {
1197                        e1.printStackTrace();
1198                }
1199                catch( final QueryEvaluationException e1 )
1200                {
1201                        e1.printStackTrace();
1202                }
1203
1204                return false;
1205        }
1206
1207        /**
1208         *      Returns a list of objects that have been deserialised from an unordered
1209         *      collection or an rdf:Seq in the graph. A test is made to determine which
1210         *      type the collection is, and it will be dealt with in the appropriate way.
1211         *      The method, if it succeeds, always returns an array of objects.
1212         *
1213         *      @param collectionURI The URI of the collection from which to get items
1214         *      @param repo The repository containing the RDF graph
1215         *      @param componentType The Java type of each component in the graph
1216         *      @param field The collection field to be set
1217         *      @param subject The URI of the object in which the collection is a member
1218         *      @param predicate The predicate that maps the collection to the object
1219         *      @return An array of deserialised objects
1220         */
1221        @SuppressWarnings( "unchecked" )
1222        private <T> T[] extractCollectionObjects( final String collectionURI,
1223                        final Repository repo, final Class<T> componentType,
1224                        final String fieldName, final String subject, final String predicate )
1225        {
1226                // This will be the output of the method - an array of
1227                // all the objects in order. May contain nulls.
1228                T[] sequence = null;
1229
1230                // Check whether the collection is a sequence. If it is, then we
1231                // can get the collection of objects and put them into an appropriate
1232                // array
1233                if( this.isRDFSequence( repo, collectionURI ) )
1234                {
1235                        // We'll get all the results into this map to start with.
1236                        // It maps an index (in the sequence) to the binding set from the query
1237                        final HashMap<Integer, BindingSet> tmpMap =
1238                                        new HashMap<Integer, BindingSet>();
1239
1240                        try
1241                        {
1242                                // Extract the objects from the RDF sequence
1243                                final int max = this.extractRDFSequenceObjects(
1244                                                collectionURI, repo, tmpMap );
1245
1246                                // If there was no sequence object, we'll return
1247                                if( max < 0 )
1248                                        return null;
1249
1250                                // So we've processed and stored all the results. Now we need to
1251                                // make sure our output array is big enough for all the results.
1252                                sequence = (T[]) Array.newInstance( componentType, max );
1253
1254                                // Now loop through all the values and poke them into the array.
1255                                // Note that we convert the indices to 0-based (RDF.Seq are
1256                                // 1-based indices).
1257                                for( final int i : tmpMap.keySet() )
1258                                        sequence[i-1] = (T)this.getFieldValue(
1259                                                        componentType,
1260                                                        tmpMap.get( i ).getValue( "o" ),
1261                                                        repo, fieldName,
1262                                                        collectionURI );
1263                        }
1264                        catch( final RepositoryException e )
1265                        {
1266                                e.printStackTrace();
1267                        }
1268                        catch( final MalformedQueryException e )
1269                        {
1270                                e.printStackTrace();
1271                        }
1272                        catch( final QueryEvaluationException e )
1273                        {
1274                                e.printStackTrace();
1275                        }
1276                }
1277                else
1278                {
1279                        sequence = this.getUnorderedObjects(
1280                                        collectionURI, repo, componentType,
1281                                        fieldName, subject, predicate );
1282                }
1283
1284                return sequence;
1285        }
1286
1287        /**
1288         *      Extracts a set of objects from an RDF sequence and returns a map
1289         *      containing the objects mapped to their index.
1290         *
1291         *      @param collectionURI The URI of the collection to extract
1292         *      @param repo The repository containing the RDF graph
1293         *      @param objectMap The map of the sequence objects
1294         *      @return The maximum index of a sequence object extracted
1295         *      @throws RepositoryException
1296         *      @throws MalformedQueryException
1297         *      @throws QueryEvaluationException
1298         */
1299        private int extractRDFSequenceObjects( final String collectionURI,
1300                final Repository repo, final HashMap<Integer, BindingSet> objectMap )
1301                        throws RepositoryException, MalformedQueryException,
1302                        QueryEvaluationException
1303        {
1304                int max = -1;
1305
1306                // First we select all the links from the collectionURI
1307                // out using the SPARQL query:
1308                //              SELECT <collectionURI> ?p ?o
1309                // ordered by the predicate name, as we're expecting those
1310                // to be rdf:_1, rdf:_2, etc. etc.
1311                final RepositoryConnection c = repo.getConnection();
1312                final String queryString = "SELECT ?p ?o WHERE {<" + collectionURI
1313                                + "> ?p ?o} ORDER BY DESC(?p)";
1314                final TupleQuery tupleQuery = c.prepareTupleQuery(
1315                                QueryLanguage.SPARQL, queryString );
1316
1317                // This actually does the query to the store...
1318                final TupleQueryResult result = tupleQuery.evaluate();
1319
1320                // Loop through the results...
1321                while( result.hasNext() )
1322                {
1323                        try
1324                        {
1325                                final BindingSet bs = result.next();
1326
1327                                // If the predicate is a sequence number (starts with rdf:_)
1328                                // then we parse the integer into the index variable.
1329                                // If it's not a NumberFormatException is thrown
1330                                // (and caught and ignored because it's clearly not an
1331                                // RDF sequence URI)
1332                                final int index = Integer.parseInt(
1333                                        bs.getValue( "p" ).stringValue()
1334                                        .substring("http://www.w3.org/1999/02/22-rdf-syntax-ns#_"
1335                                                        .length() ) );
1336
1337                                // Just be sure we're doing something sensible.
1338                                if( index >= 0 )
1339                                {
1340                                        // Stick it in the map.
1341                                        objectMap.put( index, bs );
1342
1343                                        // Store the maximum index
1344                                        max = Math.max( index, max );
1345                                }
1346                        }
1347                        catch( final NumberFormatException e )
1348                        {
1349                                // If we get a NFE then it's probably not a sequence number.
1350                        }
1351                        catch( final StringIndexOutOfBoundsException e )
1352                        {
1353                                // If we get a SOOBE then it's probably because the
1354                                // predicate
1355                                // is not a sequence number.
1356                        }
1357                }
1358                return max;
1359        }
1360
1361        /**
1362         * Returns a list of unserialised objects that were unserialised from an
1363         * unordered list of triples in RDF
1364         *
1365         * @param sequenceURI The URI of the triples
1366         * @param repo The repository
1367         * @param fieldType The field type
1368         * @param field The field
1369         * @return An array of objects, in an arbitrary order.
1370         */
1371        @SuppressWarnings( "unchecked" )
1372        private <T> T[] getUnorderedObjects( final String sequenceURI,
1373                        final Repository repo, final Class<T> fieldType,
1374                        final String fieldName,
1375                        final String subjectURI, final String predicate )
1376        {
1377                try
1378                {
1379                        // First select all the objects that link the main object
1380                        // with the collection objects via the collection predicate.
1381                        // We use the SPARQL query:
1382                        //              SELECT ?o WHERE { <subjectURI> <predicate> ?o . }
1383                        // The results are in any order.
1384                        final RepositoryConnection c = repo.getConnection();
1385                        final String queryString = "SELECT ?o WHERE {<" + subjectURI
1386                                        + "> <" + predicate + "> ?o}";
1387                        final TupleQuery tupleQuery = c.prepareTupleQuery(
1388                                        QueryLanguage.SPARQL, queryString );
1389
1390                        // Evaluate the query, to get the results.
1391                        final TupleQueryResult result = tupleQuery.evaluate();
1392
1393                        // We'll aggregate all the objects into this general list.
1394                        final ArrayList<T> objs = new ArrayList<T>();
1395                        int n = 0;
1396                        while( result.hasNext() )
1397                        {
1398                                final BindingSet bs = result.next();
1399                                final Value oo = bs.getBinding( "o" ).getValue();
1400
1401                                // Get the value of the field if it's a primitive, or
1402                                // it's URI if it's a complex object and add it to
1403                                // the list.
1404                                objs.add( (T)this.getFieldValue( fieldType,
1405                                                oo, repo, fieldName, sequenceURI ) );
1406                                n++;
1407                        }
1408
1409                        // Copy the values into an array
1410                        final T[] arr = (T[])Array.newInstance( fieldType, n );
1411                        for( int i = 0; i < arr.length; i++ )
1412                                arr[i] = objs.get(i);
1413
1414                        return arr;
1415                }
1416                catch( final RepositoryException e )
1417                {
1418                        e.printStackTrace();
1419                }
1420                catch( final MalformedQueryException e )
1421                {
1422                        e.printStackTrace();
1423                }
1424                catch( final QueryEvaluationException e )
1425                {
1426                        e.printStackTrace();
1427                }
1428
1429                return null;
1430        }
1431
1432        /**
1433         * Attempts to find the correct class for the object URI given. If a class
1434         * name cannot be found in the repository, then the field is used to attempt
1435         * to instantiate a class.
1436         *
1437         * @param objectURI The URI of the object in the repo
1438         * @param repo The RDF repository
1439         * @return A class object.
1440         */
1441        private Type getObjectClass( final String objectURI, final Repository repo )
1442        {
1443                String queryString = null;
1444                try
1445                {
1446                        final RepositoryConnection c = repo.getConnection();
1447
1448                        queryString = "SELECT ?o WHERE {<" + objectURI + "> <"
1449                                        + RDFSerializer.RDF_OPENIMAJ_P_CLASSNAME + "> ?o.}";
1450                        final TupleQuery tupleQuery = c.prepareTupleQuery(
1451                                        QueryLanguage.SPARQL, queryString );
1452                        final TupleQueryResult result = tupleQuery.evaluate();
1453
1454//                      System.out.println( queryString );
1455
1456                        // We'll look at all the results until we find a class we can
1457                        // instantiate. Of course, we expect there to be only one in
1458                        // reality.
1459                        Class<?> clazz = null;
1460                        boolean found = false;
1461                        while( !found && result.hasNext() )
1462                        {
1463                                final Value value = result.next().getValue( "o" );
1464
1465                                try
1466                                {
1467                                        // Try to find the class with the given name
1468                                        clazz = Class.forName( value.stringValue() );
1469
1470                                        // If the above succeeds, then we are done
1471                                        found = true;
1472                                }
1473                                catch( final ClassNotFoundException e )
1474                                {
1475                                        e.printStackTrace();
1476                                }
1477                        }
1478
1479                        // Close the repo connection.
1480                        c.close();
1481
1482                        // Return the class if we have one.
1483                        if( clazz != null )
1484                        {
1485//                              System.out.println( clazz );
1486                                return clazz;
1487                        }
1488
1489                }
1490                catch( final RepositoryException e )
1491                {
1492                        System.out.println( "Processing: " + queryString );
1493                        e.printStackTrace();
1494                }
1495                catch( final MalformedQueryException e )
1496                {
1497                        System.out.println( "Processing: " + queryString );
1498                        e.printStackTrace();
1499                }
1500                catch( final QueryEvaluationException e )
1501                {
1502                        System.out.println( "Processing: " + queryString );
1503                        e.printStackTrace();
1504                }
1505
1506                // Can't determine a class from the repository? Then we'll fall back
1507                // to the field's type.
1508                return null;
1509        }
1510
1511        /**
1512         * Returns a URI for the given object. If it cannot determine one, it will
1513         * return the default URI. It attempts to determine the object's URI
1514         * by looking for a getURI() method in the object. If it has one, it invokes
1515         * it and uses the return value as the object's URI, otherwise it will use
1516         * the default URI passed in via the method parameters.
1517         *
1518         * @param obj The object
1519         * @param defaultURI A default value for the URI
1520         * @return A URI for the object
1521         */
1522        public URIImpl getObjectURI( final Object obj, final URIImpl defaultURI )
1523        {
1524                // Check whether the object has a getURI() method. If so, then
1525                // what we'll do is this: we'll call the getURI() method to retrieve the
1526                // URI of the object and use that as the subject URI instead of the
1527                // uri that's passed in via the method parameters.
1528                try
1529                {
1530                        final Method method = obj.getClass().getMethod( "getURI" );
1531
1532                        // We'll call the method and use the toString() method to
1533                        // get the URI as a string. We'll instantiate a new URIImpl with it.
1534                        final URIImpl subject = new URIImpl( method.invoke( obj,
1535                                        (Object[]) null ).toString() );
1536
1537                        return subject;
1538                }
1539                catch( final NoSuchMethodException e1 )
1540                {
1541                }
1542                catch( final SecurityException e1 )
1543                {
1544                        e1.printStackTrace();
1545                }
1546                catch( final IllegalAccessException e )
1547                {
1548                        e.printStackTrace();
1549                }
1550                catch( final IllegalArgumentException e )
1551                {
1552                        e.printStackTrace();
1553                }
1554                catch( final InvocationTargetException e )
1555                {
1556                        e.printStackTrace();
1557                }
1558
1559                return defaultURI;
1560        }
1561
1562        /**
1563         * Checks whether the field value is a special field. If so, it will output
1564         * it using a separate device than the main serialization loop. Otherwise
1565         * the method returns FALSE and the main loop continues.
1566         * <p>
1567         * A special field is one which has some annotation that requires the
1568         * output be performed in a separate way. One example of this is the
1569         * {@link TripleList} annotation which forces the outputs of triples
1570         * directly from the value of the object. Similarly for the
1571         * {@link RelationList} which forces the output of triples from the
1572         * pairs stored in the object's value.
1573         *
1574         * @param fieldValue the value of the field
1575         * @param field The field definition
1576         * @return
1577         */
1578        private boolean outputSpecial( final Object fieldValue, final Field field,
1579                        final URIImpl subjectURI )
1580        {
1581                // Check whether this field is a triple list. If it is, we'll take
1582                // the triples from the field (assuming it's the right type) and
1583                // bang them into the triple store.
1584                if( field.getAnnotation( TripleList.class ) != null )
1585                {
1586                        if( fieldValue instanceof Collection )
1587                        {
1588                                for( final Object o : (Collection<?>) fieldValue )
1589                                {
1590                                        if( o instanceof Statement )
1591                                                this.addTriple( (Statement) o );
1592                                }
1593                        }
1594                        return true; // stop the main loop processing this field
1595                }
1596                else
1597                // If the field is a relation list, process each in turn
1598                if( field.getAnnotation( RelationList.class ) != null )
1599                {
1600                        if( fieldValue instanceof Collection )
1601                        {
1602                                int count = 0;
1603                                for( final Object o : (Collection<?>) fieldValue )
1604                                {
1605                                        if( o instanceof IndependentPair<?, ?> )
1606                                        {
1607                                                final IndependentPair<?, ?> ip = (IndependentPair<?, ?>) o;
1608
1609                                                Value ooo;
1610                                                if( (ooo = this.checkPrimitive( ip.getSecondObject() )) != null )
1611                                                        this.addTriple( new StatementImpl(
1612                                                                        subjectURI,
1613                                                                        new URIImpl( ip.getFirstObject().toString() ),
1614                                                                        ooo ) );
1615                                                else
1616                                                {
1617                                                        final URI subjU = this.serializeAux(
1618                                                                        ip.getSecondObject(), subjectURI + "_"
1619                                                                                        + field.getName() + "_" + count++ );
1620                                                        this.addTriple( new StatementImpl(
1621                                                                        subjectURI,
1622                                                                        new URIImpl( ip.getFirstObject().toString() ),
1623                                                                        subjU ) );
1624                                                }
1625                                        }
1626                                        else
1627                                                this.serializeAux( o,
1628                                                                subjectURI + "_" + field.getName() + "_"
1629                                                                                + count++ );
1630                                }
1631                        }
1632                        return true; // stop the main loop processing this field
1633                }
1634
1635                return false; // continue on the main loop
1636        }
1637
1638        /**
1639         * Adds a single triple to some RDF serializer.
1640         *
1641         * @param t The triple to add
1642         */
1643        public void addTriple( final Statement t )
1644        {
1645                // Default implementation does nothing. Subclasses should override
1646                // this method and do something useful with created triples.
1647                // This method is not abstract just so users can create this object
1648                // for unserialization.
1649        }
1650}