📄 historymanager.java
字号:
/* * HistoryManager.java * * Version: $Revision: 1.11 $ * * Date: $Date: 2005/04/20 14:23:44 $ * * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts * Institute of Technology. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of the Hewlett-Packard Company nor the name of the * Massachusetts Institute of Technology nor the names of their * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */package org.dspace.history;import java.io.BufferedReader;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.io.PrintWriter;import java.io.StringReader;import java.io.StringWriter;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Timestamp;import java.text.NumberFormat;import java.util.LinkedList;import java.util.List;import org.apache.log4j.Logger;import org.dspace.content.Bitstream;import org.dspace.content.Collection;import org.dspace.content.Community;import org.dspace.content.DCValue;import org.dspace.content.Item;import org.dspace.content.ItemIterator;import org.dspace.content.WorkspaceItem;import org.dspace.core.ConfigurationManager;import org.dspace.core.Context;import org.dspace.core.Utils;import org.dspace.eperson.EPerson;import org.dspace.storage.rdbms.DatabaseManager;import org.dspace.storage.rdbms.TableRow;import org.dspace.workflow.WorkflowItem;import com.hp.hpl.mesa.rdf.jena.mem.ModelMem;import com.hp.hpl.mesa.rdf.jena.model.Model;import com.hp.hpl.mesa.rdf.jena.model.Property;import com.hp.hpl.mesa.rdf.jena.model.RDFException;import com.hp.hpl.mesa.rdf.jena.model.Resource;/** * Records information about changes in DSpace. The information about changes is * written out in RDF format to one or more files in the directory given by the * configuration property <em>history.dir</em>. * * @author Peter Breton * @version $Revision: 1.11 $ */public class HistoryManager{ // Action constants public static final int NONE = 0; public static final int CREATE = 1; public static final int MODIFY = 2; public static final int REMOVE = 3; private static final String uriPrefixConfig = ConfigurationManager .getProperty("history.uri.prefix"); /** URI prefix */ private static final String uriPrefix = (uriPrefixConfig != null) ? uriPrefixConfig : "http://www.dspace.org"; /** Handle prefix */ private static String handlePrefix = ConfigurationManager .getProperty("handle.prefix"); /** log4j category */ private static Logger log = Logger.getLogger(HistoryManager.class); /** Directory for history serialization */ private static String historyDirectory = ConfigurationManager .getProperty("history.dir"); // These settings control the way an identifier is hashed into // directory and file names // FIXME: This is basically stolen from the bitstore code, and thus // could be factored out into a common location private static int digitsPerLevel = 2; private static int directoryLevels = 3; /** Identifier for the generator */ private static final String ID = new StringBuffer().append( HistoryManager.class.getName()).append(" ").append( "$Revision: 1.11 $").toString(); /** * Private Constructor */ private HistoryManager() { } /** * Save history information about this object. Errors are simply logged. * * @param context * The current DSpace context * @param obj * The object to record History information about * @param flag * One of CREATE, MODIFY or REMOVE. * @param user * The user who performed the action that is being recorded * @param tool * A description of the tool that was used to effect the action. */ public static void saveHistory(Context context, Object obj, int flag, EPerson user, String tool) { try { createHarmonyData(context, obj, flag, user, tool); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("Exception while saving history", e); } } } /** * Create Harmony data which describes the event. * * @param context * The current DSpace context * @param obj * The object to record History information about * @param flag * One of CREATE, MODIFY or REMOVE. * @param user * The user who performed the action that is being recorded * @param tool * A description of the tool that was used to effect the action. */ private static void createHarmonyData(Context context, Object historyObj, int flag, EPerson theUser, String theTool) throws SQLException, RDFException, IOException { String id = (flag == REMOVE) ? getUniqueId(historyObj) : doSerialize( context, historyObj); // Figure out the tool used if (theTool == null) { theTool = getTool(); } String eventId = getUniqueId(getShortName(historyObj), flag); // Previous state (as far as History is concerned). It's possible, // of course, that changes were made without telling History! String inputStateId = (flag == CREATE) ? null : findPreviousState(id); // Create a model Model model = new ModelMem(); // A table row and id for the new state Integer stateId = null; TableRow row = null; if (flag != REMOVE) { row = DatabaseManager.create(context, "HistoryState"); stateId = new Integer(row.getIntColumn("history_state_id")); } // This is the object that we're making statements about.... Resource obj = model.createResource(id); // This is the event Resource event = model.createResource(eventId); // States Resource outputState = (flag == REMOVE) ? null : model .createResource(stateId.toString()); Resource inputState = (flag == CREATE) ? null : model .createResource(inputStateId); // FIXME The action (also typed??) Resource action = model.createResource(getUniqueId("action", NONE)); // The user Resource user = (theUser != null) ? model .createResource(getUniqueId(theUser)) : null; // These verbs are essentially constant Property atTime = model.createProperty(getHarmonyId("atTime")); Property hasInput = model.createProperty(getHarmonyId("hasInput")); Property hasOutput = model.createProperty(getHarmonyId("hasOutput")); Property inState = model.createProperty(getHarmonyId("inState")); //Property contains = model.createProperty(getHarmonyId("contains")); Property hasAction = model.createProperty(getHarmonyId("hasAction")); Property usesTool = model.createProperty(getHarmonyId("usesTool")); Property hasAgent = model.createProperty(getHarmonyId("hasAgent")); Property operation = null; // Choose the correct operation if (flag == CREATE) { operation = model.createProperty(getHarmonyId("creates")); } else if (flag == REMOVE) { operation = model.createProperty(getHarmonyId("destroys")); } else if (flag == MODIFY) { operation = model.createProperty(getHarmonyId("transforms")); } else { throw new IllegalArgumentException("Unknown value for flag: " + flag); } // Creation events do not have input states, but everything // else does if (flag != CREATE) { model.add(event, hasInput, inputState); } // Removal events do not have output states, nor is the object // in a state upon completion if (flag != REMOVE) { model.add(event, hasOutput, outputState); model.add(obj, inState, outputState); //model.add(outputState, contains, obj); } // Time that this event occurred model.add(event, atTime, (new java.util.Date().toString())); model.add(action, operation, obj); model.add(event, hasAction, action); model.add(action, usesTool, theTool); if (theUser != null) { model.add(action, hasAgent, user); } else { model.add(action, hasAgent, model.createLiteral("Unknown User")); } // FIXME Strictly speaking, this is NOT a property of the // object itself, but of the resulting serialization! Property generatorId = model.createProperty(uriPrefix + "/generator"); model.add(event, generatorId, ID); List dbobjs = new LinkedList(); if (flag != REMOVE) { row.setColumn("history_state_id", stateId.intValue()); row.setColumn("object_id", id); DatabaseManager.update(context, row); } StringWriter swdata = new StringWriter(); model.write(swdata); swdata.close(); String data = swdata.toString(); TableRow h = DatabaseManager.create(context, "History"); int hid = h.getIntColumn("history_id"); File file = forId(hid, true); FileWriter fw = new FileWriter(file); fw.write(data); fw.close(); h.setColumn("creation_date", nowAsTimeStamp()); h.setColumn("checksum", Utils.getMD5(data)); DatabaseManager.update(context, h); } //////////////////////////////////////// // Unique ids //////////////////////////////////////// /** * Return a unique id for an object. * * @param obj * The object to return an id for * @return A unique id for the object. */ private static String getUniqueId(Object obj) { if (obj == null) { return null; } int id = -1; // FIXME This would be easier there were a ContentObject // interface/base class if (obj instanceof Community) { id = ((Community) obj).getID(); } else if (obj instanceof Collection) { id = ((Collection) obj).getID(); } else if (obj instanceof Item) { id = ((Item) obj).getID(); } else if (obj instanceof EPerson) { id = ((EPerson) obj).getID(); } else if (obj instanceof WorkspaceItem) { id = ((WorkspaceItem) obj).getID(); } else if (obj instanceof WorkflowItem) { id = ((WorkflowItem) obj).getID(); } return getUniqueIdInternal(uriPrefix, handlePrefix, getShortName(obj), Integer.toString(id)); } /** * Return a unique id corresponding to a Harmony object. * * @param name * The name of a Harmony object (action, event, etc) * @param flag * One of CREATE, MODIFY, REMOVE * @return A unique id */ private static String getUniqueId(String name, int flag) { String objname = new StringBuffer("harmony").append("/").append(name) .append((flag == CREATE) ? "create" : "").append(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -