KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dspace > history > HistoryManager


1 /*
2  * HistoryManager.java
3  *
4  * Version: $Revision: 1.11 $
5  *
6  * Date: $Date: 2005/04/20 14:23:44 $
7  *
8  * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
9  * Institute of Technology. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are
13  * met:
14  *
15  * - Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  *
18  * - Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution.
21  *
22  * - Neither the name of the Hewlett-Packard Company nor the name of the
23  * Massachusetts Institute of Technology nor the names of their
24  * contributors may be used to endorse or promote products derived from
25  * this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
34  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38  * DAMAGE.
39  */

40 package org.dspace.history;
41
42 import java.io.BufferedReader JavaDoc;
43 import java.io.File JavaDoc;
44 import java.io.FileWriter JavaDoc;
45 import java.io.IOException JavaDoc;
46 import java.io.PrintWriter JavaDoc;
47 import java.io.StringReader JavaDoc;
48 import java.io.StringWriter JavaDoc;
49 import java.sql.Connection JavaDoc;
50 import java.sql.PreparedStatement JavaDoc;
51 import java.sql.ResultSet JavaDoc;
52 import java.sql.SQLException JavaDoc;
53 import java.sql.Timestamp JavaDoc;
54 import java.text.NumberFormat JavaDoc;
55 import java.util.LinkedList JavaDoc;
56 import java.util.List JavaDoc;
57
58 import org.apache.log4j.Logger;
59 import org.dspace.content.Bitstream;
60 import org.dspace.content.Collection;
61 import org.dspace.content.Community;
62 import org.dspace.content.DCValue;
63 import org.dspace.content.Item;
64 import org.dspace.content.ItemIterator;
65 import org.dspace.content.WorkspaceItem;
66 import org.dspace.core.ConfigurationManager;
67 import org.dspace.core.Context;
68 import org.dspace.core.Utils;
69 import org.dspace.eperson.EPerson;
70 import org.dspace.storage.rdbms.DatabaseManager;
71 import org.dspace.storage.rdbms.TableRow;
72 import org.dspace.workflow.WorkflowItem;
73
74 import com.hp.hpl.mesa.rdf.jena.mem.ModelMem;
75 import com.hp.hpl.mesa.rdf.jena.model.Model;
76 import com.hp.hpl.mesa.rdf.jena.model.Property;
77 import com.hp.hpl.mesa.rdf.jena.model.RDFException;
78 import com.hp.hpl.mesa.rdf.jena.model.Resource;
79
80 /**
81  * Records information about changes in DSpace. The information about changes is
82  * written out in RDF format to one or more files in the directory given by the
83  * configuration property <em>history.dir</em>.
84  *
85  * @author Peter Breton
86  * @version $Revision: 1.11 $
87  */

88 public class HistoryManager
89 {
90     // Action constants
91
public static final int NONE = 0;
92
93     public static final int CREATE = 1;
94
95     public static final int MODIFY = 2;
96
97     public static final int REMOVE = 3;
98
99     private static final String JavaDoc uriPrefixConfig = ConfigurationManager
100             .getProperty("history.uri.prefix");
101
102     /** URI prefix */
103     private static final String JavaDoc uriPrefix = (uriPrefixConfig != null) ? uriPrefixConfig
104             : "http://www.dspace.org";
105
106     /** Handle prefix */
107     private static String JavaDoc handlePrefix = ConfigurationManager
108             .getProperty("handle.prefix");
109
110     /** log4j category */
111     private static Logger log = Logger.getLogger(HistoryManager.class);
112
113     /** Directory for history serialization */
114     private static String JavaDoc historyDirectory = ConfigurationManager
115             .getProperty("history.dir");
116
117     // These settings control the way an identifier is hashed into
118
// directory and file names
119
// FIXME: This is basically stolen from the bitstore code, and thus
120
// could be factored out into a common location
121
private static int digitsPerLevel = 2;
122
123     private static int directoryLevels = 3;
124
125     /** Identifier for the generator */
126     private static final String JavaDoc ID = new StringBuffer JavaDoc().append(
127             HistoryManager.class.getName()).append(" ").append(
128             "$Revision: 1.11 $").toString();
129
130     /**
131      * Private Constructor
132      */

133     private HistoryManager()
134     {
135     }
136
137     /**
138      * Save history information about this object. Errors are simply logged.
139      *
140      * @param context
141      * The current DSpace context
142      * @param obj
143      * The object to record History information about
144      * @param flag
145      * One of CREATE, MODIFY or REMOVE.
146      * @param user
147      * The user who performed the action that is being recorded
148      * @param tool
149      * A description of the tool that was used to effect the action.
150      */

151     public static void saveHistory(Context context, Object JavaDoc obj, int flag,
152             EPerson user, String JavaDoc tool)
153     {
154         try
155         {
156             createHarmonyData(context, obj, flag, user, tool);
157         }
158         catch (Exception JavaDoc e)
159         {
160             if (log.isDebugEnabled())
161             {
162                 log.debug("Exception while saving history", e);
163             }
164         }
165     }
166
167     /**
168      * Create Harmony data which describes the event.
169      *
170      * @param context
171      * The current DSpace context
172      * @param obj
173      * The object to record History information about
174      * @param flag
175      * One of CREATE, MODIFY or REMOVE.
176      * @param user
177      * The user who performed the action that is being recorded
178      * @param tool
179      * A description of the tool that was used to effect the action.
180      */

181     private static void createHarmonyData(Context context, Object JavaDoc historyObj,
182             int flag, EPerson theUser, String JavaDoc theTool) throws SQLException JavaDoc,
183             RDFException, IOException JavaDoc
184     {
185         String JavaDoc id = (flag == REMOVE) ? getUniqueId(historyObj) : doSerialize(
186                 context, historyObj);
187
188         // Figure out the tool used
189
if (theTool == null)
190         {
191             theTool = getTool();
192         }
193
194         String JavaDoc eventId = getUniqueId(getShortName(historyObj), flag);
195
196         // Previous state (as far as History is concerned). It's possible,
197
// of course, that changes were made without telling History!
198
String JavaDoc inputStateId = (flag == CREATE) ? null : findPreviousState(id);
199
200         // Create a model
201
Model model = new ModelMem();
202
203         // A table row and id for the new state
204
Integer JavaDoc stateId = null;
205         TableRow row = null;
206
207         if (flag != REMOVE)
208         {
209             row = DatabaseManager.create(context, "HistoryState");
210             stateId = new Integer JavaDoc(row.getIntColumn("history_state_id"));
211         }
212
213         // This is the object that we're making statements about....
214
Resource obj = model.createResource(id);
215
216         // This is the event
217
Resource event = model.createResource(eventId);
218
219         // States
220
Resource outputState = (flag == REMOVE) ? null : model
221                 .createResource(stateId.toString());
222         Resource inputState = (flag == CREATE) ? null : model
223                 .createResource(inputStateId);
224
225         // FIXME The action (also typed??)
226
Resource action = model.createResource(getUniqueId("action", NONE));
227
228         // The user
229
Resource user = (theUser != null) ? model
230                 .createResource(getUniqueId(theUser)) : null;
231
232         // These verbs are essentially constant
233
Property atTime = model.createProperty(getHarmonyId("atTime"));
234         Property hasInput = model.createProperty(getHarmonyId("hasInput"));
235         Property hasOutput = model.createProperty(getHarmonyId("hasOutput"));
236         Property inState = model.createProperty(getHarmonyId("inState"));
237
238         //Property contains = model.createProperty(getHarmonyId("contains"));
239
Property hasAction = model.createProperty(getHarmonyId("hasAction"));
240         Property usesTool = model.createProperty(getHarmonyId("usesTool"));
241         Property hasAgent = model.createProperty(getHarmonyId("hasAgent"));
242         Property operation = null;
243
244         // Choose the correct operation
245
if (flag == CREATE)
246         {
247             operation = model.createProperty(getHarmonyId("creates"));
248         }
249         else if (flag == REMOVE)
250         {
251             operation = model.createProperty(getHarmonyId("destroys"));
252         }
253         else if (flag == MODIFY)
254         {
255             operation = model.createProperty(getHarmonyId("transforms"));
256         }
257         else
258         {
259             throw new IllegalArgumentException JavaDoc("Unknown value for flag: "
260                     + flag);
261         }
262
263         // Creation events do not have input states, but everything
264
// else does
265
if (flag != CREATE)
266         {
267             model.add(event, hasInput, inputState);
268         }
269
270         // Removal events do not have output states, nor is the object
271
// in a state upon completion
272
if (flag != REMOVE)
273         {
274             model.add(event, hasOutput, outputState);
275             model.add(obj, inState, outputState);
276
277             //model.add(outputState, contains, obj);
278
}
279
280         // Time that this event occurred
281
model.add(event, atTime, (new java.util.Date JavaDoc().toString()));
282
283         model.add(action, operation, obj);
284         model.add(event, hasAction, action);
285         model.add(action, usesTool, theTool);
286
287         if (theUser != null)
288         {
289             model.add(action, hasAgent, user);
290         }
291         else
292         {
293             model.add(action, hasAgent, model.createLiteral("Unknown User"));
294         }
295
296         // FIXME Strictly speaking, this is NOT a property of the
297
// object itself, but of the resulting serialization!
298
Property generatorId = model.createProperty(uriPrefix + "/generator");
299
300         model.add(event, generatorId, ID);
301
302         List JavaDoc dbobjs = new LinkedList JavaDoc();
303
304         if (flag != REMOVE)
305         {
306             row.setColumn("history_state_id", stateId.intValue());
307             row.setColumn("object_id", id);
308             DatabaseManager.update(context, row);
309         }
310
311         StringWriter JavaDoc swdata = new StringWriter JavaDoc();
312
313         model.write(swdata);
314         swdata.close();
315
316         String JavaDoc data = swdata.toString();
317
318         TableRow h = DatabaseManager.create(context, "History");
319         int hid = h.getIntColumn("history_id");
320
321         File JavaDoc file = forId(hid, true);
322         FileWriter JavaDoc fw = new FileWriter JavaDoc(file);
323
324         fw.write(data);
325         fw.close();
326
327         h.setColumn("creation_date", nowAsTimeStamp());
328         h.setColumn("checksum", Utils.getMD5(data));
329         DatabaseManager.update(context, h);
330     }
331
332     ////////////////////////////////////////
333
// Unique ids
334
////////////////////////////////////////
335

336     /**
337      * Return a unique id for an object.
338      *
339      * @param obj
340      * The object to return an id for
341      * @return A unique id for the object.
342      */

343     private static String JavaDoc getUniqueId(Object JavaDoc obj)
344     {
345         if (obj == null)
346         {
347             return null;
348         }
349
350         int id = -1;
351
352         // FIXME This would be easier there were a ContentObject
353
// interface/base class
354
if (obj instanceof Community)
355         {
356             id = ((Community) obj).getID();
357         }
358         else if (obj instanceof Collection)
359         {
360             id = ((Collection) obj).getID();
361         }
362         else if (obj instanceof Item)
363         {
364             id = ((Item) obj).getID();
365         }
366         else if (obj instanceof EPerson)
367         {
368             id = ((EPerson) obj).getID();
369         }
370         else if (obj instanceof WorkspaceItem)
371         {
372             id = ((WorkspaceItem) obj).getID();
373         }
374         else if (obj instanceof WorkflowItem)
375         {
376             id = ((WorkflowItem) obj).getID();
377         }
378
379         return getUniqueIdInternal(uriPrefix, handlePrefix, getShortName(obj),
380                 Integer.toString(id));
381     }
382
383     /**
384      * Return a unique id corresponding to a Harmony object.
385      *
386      * @param name
387      * The name of a Harmony object (action, event, etc)
388      * @param flag
389      * One of CREATE, MODIFY, REMOVE
390      * @return A unique id
391      */

392     private static String JavaDoc getUniqueId(String JavaDoc name, int flag)
393     {
394         String JavaDoc objname = new StringBuffer JavaDoc("harmony").append("/").append(name)
395                 .append((flag == CREATE) ? "create" : "").append(
396                         (flag == MODIFY) ? "modify" : "").append(
397                         (flag == REMOVE) ? "remove" : "").toString();
398
399         return getUniqueIdInternal(uriPrefix, null, objname, Utils
400                 .generateHexKey());
401     }
402
403     /**
404      * Return an RDF property id.
405      *
406      * @param objname
407      * The name of an object
408      * @param property
409      * The name of a property of the objecty
410      * @return The id for the property
411      */

412     private static String JavaDoc getPropertyId(String JavaDoc objname, String JavaDoc property)
413     {
414         return getUniqueIdInternal(uriPrefix, null, objname, property);
415     }
416
417     /**
418      * Return an RDF property id for Harmony property.
419      *
420      * @param property
421      * The name of a Harmony property
422      * @return The id for the property
423      */

424     private static String JavaDoc getHarmonyId(String JavaDoc property)
425     {
426         return getUniqueIdInternal(uriPrefix, null, "harmony", property);
427     }
428
429     /**
430      * Internal method for id generation.
431      *
432      * @param uriPrefix
433      * A URI
434      * @param handlePrefix
435      * @param objname
436      * @param objid
437      * @return A unique id
438      */

439     private static String JavaDoc getUniqueIdInternal(String JavaDoc uriPrefix,
440             String JavaDoc handlePrefix, String JavaDoc objname, String JavaDoc objid)
441     {
442         final String JavaDoc SLASH = "/";
443
444         return new StringBuffer JavaDoc().append(uriPrefix).append(
445                 uriPrefix.endsWith(SLASH) ? "" : SLASH).append(objname).append(
446                 objname.endsWith(SLASH) ? "" : SLASH).append(
447                 (handlePrefix == null) ? "" : handlePrefix).append(
448                 ((handlePrefix == null) || (handlePrefix.endsWith(SLASH))) ? ""
449                         : SLASH).append(objid).toString();
450     }
451
452     ////////////////////////////////////////
453
// Serialize methods
454
////////////////////////////////////////
455

456     /**
457      * Return an RDF stream for this object.
458      *
459      * @param context
460      * Current DSpace context
461      * @param obj
462      * The object to serialize
463      * @return The serialization of the object
464      * @exception RDFException
465      * If an error occurs while constructing an RDF graph
466      * @exception SQLException
467      * If an error occurs while accessing the database
468      */

469     private static String JavaDoc serialize(Context context, Object JavaDoc obj)
470             throws RDFException, SQLException JavaDoc
471     {
472         if (obj == null)
473         {
474             return null;
475         }
476
477         Model model = new ModelMem();
478
479         // Add statements about this object
480
serializeInternal(context, obj, model);
481
482         StringWriter JavaDoc data = new StringWriter JavaDoc();
483
484         model.write(data);
485
486         // Since this is all in-memory, IOExceptions should never happen
487
try
488         {
489             data.close();
490         }
491         catch (IOException JavaDoc ioe)
492         {
493         }
494
495         return data.toString();
496     }
497
498     /**
499      * Add RDF statements about this object to the model.
500      *
501      * @param context
502      * Current DSpace context
503      * @param obj
504      * The object to make statements about
505      * @param model
506      * The RDF statement graph
507      * @exception RDFException
508      * If an error occurs while constructing an RDF graph
509      * @exception SQLException
510      * If an error occurs while accessing the database
511      */

512     private static void serializeInternal(Context context, Object JavaDoc obj,
513             Model model) throws RDFException, SQLException JavaDoc
514     {
515         if (obj == null)
516         {
517             return;
518         }
519
520         String JavaDoc id = getUniqueId(obj);
521         Resource res = model.createResource(id);
522
523         // FIXME Strictly speaking, this is NOT a property of the
524
// object itself, but of the resulting serialization!
525
Property generatorId = model.createProperty(uriPrefix + "/generator");
526
527         model.add(res, generatorId, ID);
528
529         if (obj instanceof Community)
530         {
531             addData(context, (Community) obj, res, model);
532         }
533         else if (obj instanceof Collection)
534         {
535             addData(context, (Collection) obj, res, model);
536         }
537         else if (obj instanceof Item)
538         {
539             addData(context, (Item) obj, res, model);
540         }
541         else if (obj instanceof WorkspaceItem)
542         {
543             addData(context, (WorkspaceItem) obj, res, model);
544         }
545         else if (obj instanceof WorkflowItem)
546         {
547             addData(context, (WorkflowItem) obj, res, model);
548         }
549         else if (obj instanceof EPerson)
550         {
551             addData(context, (EPerson) obj, res, model);
552         }
553     }
554
555     /**
556      * Serialize and store an object.
557      *
558      * @param context
559      * Current DSpace context.
560      * @param obj
561      * The object to serialize and store.
562      * @return A unique id for the object.
563      * @exception RDFException
564      * If an error occurs while constructing an RDF graph
565      * @exception IOException
566      * If an error occurs while storing the serialization
567      * @exception SQLException
568      * If an error occurs while accessing the database
569      */

570     private static String JavaDoc doSerialize(Context context, Object JavaDoc obj)
571             throws SQLException JavaDoc, IOException JavaDoc, RDFException
572     {
573         if (obj == null)
574         {
575             return null;
576         }
577
578         String JavaDoc id = getUniqueId(obj);
579         String JavaDoc serialization = serialize(context, obj);
580
581         store(context, serialization);
582
583         return id;
584     }
585
586     /**
587      * Store the serialization (unless it already exists).
588      *
589      * @param context
590      * Current DSpace context.
591      * @param serialization
592      * The serialization to store.
593      * @exception IOException
594      * If an error occurs while storing the serialization
595      * @exception SQLException
596      * If an error occurs while accessing the database
597      */

598     private static void store(Context context, String JavaDoc serialization)
599             throws SQLException JavaDoc, IOException JavaDoc
600     {
601         String JavaDoc checksum = Utils.getMD5(serialization);
602         TableRow row = DatabaseManager.findByUnique(context, "history",
603                 "checksum", checksum);
604
605         // Already stored
606
if (row != null)
607         {
608             return;
609         }
610
611         TableRow h = DatabaseManager.create(context, "History");
612         int hid = h.getIntColumn("history_id");
613
614         File JavaDoc file = forId(hid, true);
615         FileWriter JavaDoc fw = new FileWriter JavaDoc(file);
616
617         fw.write(serialization);
618         fw.close();
619
620         h.setColumn("checksum", checksum);
621         h.setColumn("creation_date", nowAsTimeStamp());
622         DatabaseManager.update(context, h);
623     }
624
625     /**
626      * Return the last state for the object with id, or null.
627      *
628      * @param id
629      * The object's history id
630      * @exception SQLException
631      * If an error occurs while accessing the database
632      */

633     private static String JavaDoc findPreviousState(String JavaDoc id) throws SQLException JavaDoc
634     {
635         Connection JavaDoc connection = null;
636         PreparedStatement JavaDoc statement = null;
637
638         try
639         {
640             String JavaDoc sql = "SELECT MAX(history_state_id) FROM HistoryState WHERE object_id = ?";
641
642             connection = DatabaseManager.getConnection();
643             statement = connection.prepareStatement(sql);
644             statement.setString(1, id);
645
646             ResultSet JavaDoc results = statement.executeQuery();
647
648             return results.next() ? results.getString(1) : null;
649         }
650         finally
651         {
652             if (statement != null)
653             {
654                 statement.close();
655             }
656
657             if (connection != null)
658             {
659                 connection.close();
660             }
661         }
662     }
663
664     ////////////////////////////////////////
665
// addData methods
666
////////////////////////////////////////
667

668     /**
669      * Add community-specific data to the model.
670      *
671      * @param context
672      * Current DSpace context.
673      * @param community
674      * The community
675      * @param res
676      * RDF resource for the community
677      * @param model
678      * The RDF graph
679      * @exception RDFException
680      * If an error occurs while constructing an RDF graph
681      * @exception SQLException
682      * If an error occurs while accessing the database
683      */

684     private static void addData(Context context, Community community,
685             Resource res, Model model) throws RDFException, SQLException JavaDoc
686     {
687         String JavaDoc shortname = getShortName(community);
688         model.add(res, model.createProperty(getPropertyId(shortname, "ID")),
689                 community.getID());
690
691         String JavaDoc[] metadata = new String JavaDoc[] { "name", "short_description",
692                 "introductory_text", "copyright_text", "side_bar_text" };
693
694         for (int i = 0; i < metadata.length; i++)
695         {
696             String JavaDoc meta = metadata[i];
697             addMetadata(model, res, shortname, meta, community
698                     .getMetadata(meta));
699         }
700
701         Property hasPart = model.createProperty(getHarmonyId("hasPart"));
702         Collection[] collections = community.getCollections();
703
704         for (int i = 0; i < collections.length; i++)
705         {
706             model.add(res, hasPart, getUniqueId(collections[i]));
707         }
708     }
709
710     /**
711      * Add collection-specific data to the model.
712      *
713      * @param context
714      * Current DSpace context.
715      * @param collection
716      * The collection
717      * @param res
718      * RDF resource for the collection
719      * @param model
720      * The RDF graph
721      * @exception RDFException
722      * If an error occurs while constructing an RDF graph
723      * @exception SQLException
724      * If an error occurs while accessing the database
725      */

726     private static void addData(Context context, Collection collection,
727             Resource res, Model model) throws SQLException JavaDoc, RDFException
728     {
729         String JavaDoc shortname = getShortName(collection);
730
731         model.add(res, model.createProperty(getPropertyId(shortname, "ID")),
732                 collection.getID());
733         model.add(res, model
734                 .createProperty(getPropertyId(shortname, "license")),
735                 collection.getLicense());
736
737         String JavaDoc[] metadata = new String JavaDoc[] { "name", "short_description",
738                 "introductory_text", "copyright_text", "side_bar_text",
739                 "provenance_description" };
740
741         for (int i = 0; i < metadata.length; i++)
742         {
743             String JavaDoc meta = metadata[i];
744             addMetadata(model, res, shortname, meta, collection
745                     .getMetadata(meta));
746         }
747
748         Property hasPart = model.createProperty(getHarmonyId("hasPart"));
749         ItemIterator items = collection.getItems();
750
751         while (items.hasNext())
752         {
753             Item item = items.next();
754
755             model.add(res, hasPart, getUniqueId(item));
756         }
757     }
758
759     /**
760      * Add item-specific data to the model.
761      *
762      * @param context
763      * Current DSpace context.
764      * @param item
765      * The item
766      * @param res
767      * RDF resource for the item
768      * @param model
769      * The RDF graph
770      * @exception RDFException
771      * If an error occurs while constructing an RDF graph
772      * @exception SQLException
773      * If an error occurs while accessing the database
774      */

775     private static void addData(Context context, Item item, Resource res,
776             Model model) throws RDFException, SQLException JavaDoc
777     {
778         DCValue[] dcfields = item.getDC(Item.ANY, Item.ANY, Item.ANY);
779
780         for (int i = 0; i < dcfields.length; i++)
781         {
782             DCValue dc = dcfields[i];
783             String JavaDoc element = dc.element;
784             String JavaDoc qualifier = dc.qualifier;
785
786             String JavaDoc type = new StringBuffer JavaDoc().append(element).append(
787                     (qualifier == null) ? "" : ".").append(
788                     (qualifier == null) ? "" : qualifier).toString();
789
790             Property p = model
791                     .createProperty(uriPrefix + "/dublincore/" + type);
792             model.add(res, p, dc.value);
793         }
794
795         // FIXME Ignoring Bundles for now, as they simply hold
796
// bitstreams in the Early Adopters release.
797
// When Bundles have their own metadata, they should be recorded
798
Property hasPart = model.createProperty(getHarmonyId("hasPart"));
799
800         // FIXME Not clear that we should ignore the internal bitstreams
801
Bitstream[] bitstreams = item.getNonInternalBitstreams();
802
803         for (int i = 0; i < bitstreams.length; i++)
804         {
805             Bitstream bitstream = bitstreams[i];
806
807             model.add(res, hasPart, getUniqueId(bitstream));
808
809             // Serialize the bitstream's metadata
810
serializeInternal(context, bitstream, model);
811         }
812     }
813
814     /**
815      * Add workspace-item-specific data to the model.
816      *
817      * @param context
818      * The current DSpace context
819      * @param wi
820      * The WorkspaceItem
821      * @param res
822      * The RDF Resource representing the WorkspaceItem
823      * @param model
824      * The RDF Model
825      * @exception SQLException
826      * If an error occurs reading data about the WorkspaceItem
827      * from the database
828      * @exception RDFException
829      * If an error occurs adding RDF statements to the model
830      */

831     private static void addData(Context context, WorkspaceItem wi,
832             Resource res, Model model) throws SQLException JavaDoc, RDFException
833     {
834         Item item = Item.find(context, wi.getItem().getID());
835
836         serializeInternal(context, item, model);
837     }
838
839     /**
840      * Add workflow-item-specific data to the model.
841      *
842      * @param context
843      * The current DSpace context
844      * @param wi
845      * The WorkflowItem
846      * @param res
847      * The RDF Resource representing the WorkflowItem
848      * @param model
849      * The RDF Model
850      * @exception SQLException
851      * If an error occurs reading data about the WorkflowItem
852      * from the database
853      * @exception RDFException
854      * If an error occurs adding RDF statements to the model
855      */

856     private static void addData(Context context, WorkflowItem wi, Resource res,
857             Model model) throws SQLException JavaDoc, RDFException
858     {
859         Item item = Item.find(context, wi.getItem().getID());
860
861         serializeInternal(context, item, model);
862     }
863
864     /**
865      * Add eperson-specific data to the model.
866      *
867      * @param context
868      * The current DSpace context
869      * @param eperson
870      * The EPerson
871      * @param res
872      * The RDF Resource representing the EPerson
873      * @param model
874      * The RDF Model
875      * @exception SQLException
876      * If an error occurs reading data about the EPerson from the
877      * database
878      * @exception RDFException
879      * If an error occurs adding RDF statements to the model
880      */

881     private static void addData(Context context, EPerson eperson, Resource res,
882             Model model) throws SQLException JavaDoc, RDFException
883     {
884         String JavaDoc shortname = getShortName(eperson);
885         model.add(res, model.createProperty(getPropertyId(shortname, "ID")),
886                 eperson.getID());
887         model.add(res, model.createProperty(getPropertyId(shortname, "email")),
888                 eperson.getEmail());
889         model.add(res, model.createProperty(getPropertyId(shortname,
890                 "firstname")), eperson.getFirstName());
891         model.add(res, model
892                 .createProperty(getPropertyId(shortname, "lastname")), eperson
893                 .getLastName());
894         model.add(res,
895                 model.createProperty(getPropertyId(shortname, "active")),
896                 eperson.canLogIn());
897         model.add(res, model.createProperty(getPropertyId(shortname,
898                 "require_certificate")), eperson.getRequireCertificate());
899
900         String JavaDoc[] metadata = new String JavaDoc[] { "phone" };
901
902         for (int i = 0; i < metadata.length; i++)
903         {
904             String JavaDoc meta = metadata[i];
905             addMetadata(model, res, shortname, meta, eperson.getMetadata(meta));
906         }
907     }
908
909     /**
910      * Convenience method to add a metadata statement to a model.
911      *
912      * @param model
913      * The RDF graph
914      * @param res
915      * RDF resource
916      * @param object
917      * The name of the object
918      * @param property
919      * The name of a property of the object
920      * @param value
921      * The value of the property
922      * @exception RDFException
923      * If an error occurs while constructing an RDF graph
924      */

925     private static void addMetadata(Model model, Resource res, String JavaDoc object,
926             String JavaDoc property, String JavaDoc value) throws RDFException
927     {
928         if (value == null)
929         {
930             return;
931         }
932
933         model.add(res, model.createProperty(getPropertyId(object, property)),
934                 value);
935     }
936
937     ////////////////////////////////////////
938
// File storage methods (stolen from BitstreamStorageManager)
939
////////////////////////////////////////
940

941     /**
942      * Return the File corresponding to id.
943      *
944      * @param id
945      * The id
946      * @param create
947      * If true, the file will be created if it does not exist.
948      * Otherwise, null will be returned.
949      * @return The File corresponding to id
950      * @exception IOException
951      * If a filesystem error occurs while determining the
952      * corresponding file.
953      */

954     private static File JavaDoc forId(int id, boolean create) throws IOException JavaDoc
955     {
956         File JavaDoc file = new File JavaDoc(id2Filename(id));
957
958         if (!file.exists())
959         {
960             if (!create)
961             {
962                 return null;
963             }
964
965             File JavaDoc parent = file.getParentFile();
966
967             if (!parent.exists())
968             {
969                 parent.mkdirs();
970             }
971
972             file.createNewFile();
973         }
974
975         return file;
976     }
977
978     /**
979      * Return the filename corresponding to id.
980      *
981      * @param id
982      * The id
983      * @return The filename corresponding to id
984      * @exception IOException
985      * If a filesystem error occurs while determining the name.
986      */

987     private static String JavaDoc id2Filename(int id) throws IOException JavaDoc
988     {
989         NumberFormat JavaDoc nf = NumberFormat.getInstance();
990
991         // Do not use commas to separate digits
992
nf.setGroupingUsed(false);
993
994         // Ensure numbers are at least 8 digits
995
nf.setMinimumIntegerDigits(8);
996
997         String JavaDoc ID = nf.format(new Integer JavaDoc(id));
998
999         // Start with the root directory
1000
StringBuffer JavaDoc result = new StringBuffer JavaDoc().append(historyDirectory);
1001
1002        // Split the id into groups
1003
for (int i = 0; i < directoryLevels; i++)
1004        {
1005            int digits = i * digitsPerLevel;
1006
1007            result.append(File.separator).append(
1008                    ID.substring(digits, digits + digitsPerLevel));
1009        }
1010
1011        // Lastly, add the id itself
1012
String JavaDoc theName = result.append(File.separator).append(id).toString();
1013
1014        if (log.isDebugEnabled())
1015        {
1016            log.debug("Filename for " + id + " is " + theName);
1017        }
1018
1019        return theName;
1020    }
1021
1022    ////////////////////////////////////////
1023
// Utility methods
1024
////////////////////////////////////////
1025

1026    /**
1027     * Return a basic idea of which tool was used to do something.
1028     *
1029     * @return A String indicating the tool used
1030     */

1031    private static String JavaDoc getTool()
1032    {
1033        String JavaDoc stacktrace = getStackTrace();
1034
1035        // Find the highest stack frame that contains org.dspace.
1036
try
1037        {
1038            BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new StringReader JavaDoc(
1039                    stacktrace));
1040            String JavaDoc line = null;
1041            String JavaDoc match = null;
1042
1043            while ((line = reader.readLine()) != null)
1044            {
1045                if (line.indexOf("org.dspace") != -1)
1046                {
1047                    match = line.trim();
1048                }
1049            }
1050
1051            // If nothing matched, maybe the stacktrace will give a clue
1052
return (match == null) ? stacktrace : match;
1053        }
1054        // Should never get here -- no real I/O
1055
catch (Exception JavaDoc e)
1056        {
1057            return stacktrace;
1058        }
1059    }
1060
1061    /**
1062     * Return a String containing the stack trace of the caller.
1063     *
1064     * @return A String containing the stack trace of the caller.
1065     */

1066    public static String JavaDoc getStackTrace()
1067    {
1068        StringWriter JavaDoc writer = new StringWriter JavaDoc();
1069
1070        new Throwable JavaDoc().printStackTrace(new PrintWriter JavaDoc(writer));
1071
1072        return writer.toString();
1073    }
1074
1075    /**
1076     * Return the unqualified classname for object.
1077     *
1078     * @param obj
1079     * The object to check
1080     * @return The object's unqualified classname
1081     */

1082    private static String JavaDoc getShortName(Object JavaDoc obj)
1083    {
1084        if (obj == null)
1085        {
1086            return null;
1087        }
1088
1089        String JavaDoc classname = obj.getClass().getName();
1090        int index = classname.lastIndexOf(".");
1091
1092        return (index == -1) ? classname : classname.substring(index + 1);
1093    }
1094
1095    /**
1096     * Return the current instant as an SQL timestamp.
1097     *
1098     * @return The current instant as an SQL timestamp.
1099     */

1100    private static Timestamp JavaDoc nowAsTimeStamp()
1101    {
1102        return new java.sql.Timestamp JavaDoc(new java.util.Date JavaDoc().getTime());
1103    }
1104
1105    ////////////////////////////////////////
1106
// Main
1107
////////////////////////////////////////
1108

1109    /**
1110     * Embedded test harness
1111     *
1112     * @param argv -
1113     * Command-line arguments
1114     */

1115    public static void main(String JavaDoc[] argv)
1116    {
1117        Context context = null;
1118
1119        try
1120        {
1121            context = new Context();
1122
1123            Community c = Community.find(context, 1);
1124
1125            if (c != null)
1126            {
1127                System.out.println("Got unique id " + getUniqueId(c));
1128
1129                saveHistory(context, c, CREATE, null, null);
1130            }
1131
1132            Collection collection = Collection.find(context, 3);
1133
1134            if (collection != null)
1135            {
1136                System.out.println("Got unique id " + getUniqueId(collection));
1137
1138                saveHistory(context, collection, CREATE, null, null);
1139            }
1140
1141            // New eperson
1142
String JavaDoc email = "historytestuser@HistoryManager";
1143            EPerson nep = EPerson.findByEmail(context, email);
1144
1145            if (nep == null)
1146            {
1147                nep = EPerson.create(context);
1148            }
1149
1150            nep.setFirstName("History");
1151            nep.setEmail(email);
1152            nep.update();
1153
1154            saveHistory(context, nep, CREATE, null, null);
1155
1156            // Change some things around
1157
nep.setFirstName("History Test");
1158            nep.setLastName("User");
1159            nep.update();
1160
1161            saveHistory(context, nep, MODIFY, null, null);
1162
1163            Item item = Item.find(context, 1);
1164
1165            if (item != null)
1166            {
1167                saveHistory(context, item, CREATE, null, null);
1168            }
1169
1170            System.exit(0);
1171        }
1172        catch (Exception JavaDoc e)
1173        {
1174            e.printStackTrace();
1175        }
1176        finally
1177        {
1178            if (context != null)
1179            {
1180                context.abort();
1181            }
1182        }
1183    }
1184}
1185
Popular Tags