/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at * * http://www.dspace.org/license/ */ package org.dspace.rdf; import com.hp.hpl.jena.rdf.model.Model; import java.sql.SQLException; import java.util.logging.Level; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeManager; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.Site; import org.dspace.core.Constants; import org.dspace.core.Context; /** * * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de) */ public class RDFUtil { private static final Logger log = Logger.getLogger(RDFUtil.class); /** * Loads converted data of a DSpaceObject identified by the URI provided * as {@code identifier}. This method uses the RDFStorage configurated in * the DSpace configuration. Close the model * ({@link com.hp.hpl.jena.rdf.model.Model#close() Model.close()}) as soon * as possible to free system resources. * @param identifier A URI representing the object you want to load data about. * @return A model containing the RDF data to the specified identifier or * null if no data could be found. */ public static Model loadModel(String identifier) { return RDFConfiguration.getRDFStorage().load(identifier); } /** * Generates a URI identifying the provided DSpaceObject. This method * automatically loads and instantiates the URIGenerator configured in * DSpace configuration. * Please note that URIs can be generated for DSpaceObjects of the * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf * doesn't support Bundles or Bitstreams as independent entity. * @param context DSpace Context. * @param dso DSpace Object you want to get an identifier for. * @return URI to identify the DSO or null if no URI could be generated. * This can happen f.e. if you use a URIGenerator that uses * persistent identifier like DOIs or Handles but there is no such * identifier assigned to the provided DSO. */ public static String generateIdentifier(Context context, DSpaceObject dso) throws SQLException { return RDFConfiguration.getURIGenerator().generateIdentifier(context, dso); } /** * Generates a URI identifying the provided DSpaceObject. This method * automatically loads and instantiates the URIGenerator configured in * DSpace configuration. * Please note that URIs can be generated for DSpaceObjects of the * type SITE, COMMUNITY, COLLECTION or ITEM only. Currently dspace-rdf * doesn't support Bundles or Bitstreams as independent entity. * @param context DSpace Context. * @param type Type of the DSpaceObject you want to generate a URI for (g.e. * {@link org.dspace.core.Constants#ITEM Constants.ITEM}. * @param id ID of the DSpaceObject you want to generate a URI for. * @param handle Handle of the DSpaceObject you want to generate a URI for. * @return URI to identify the DSO or null if no URI could be generated. * This can happen f.e. if you use a URIGenerator that uses * persistent identifier like DOIs or Handles but there is no such * identifier assigned to the provided DSO. */ public static String generateIdentifier(Context context, int type, int id, String handle, String[] identifier) throws SQLException { return RDFConfiguration.getURIGenerator().generateIdentifier(context, type, id, handle, identifier); } /** * Converts the the provided DSpaceObject into RDF and returns the model. * Please note that dspace-rdf doesn't support Bundles or Bitstreams as * independent entity. You can convert DSpaceObjects of type SITE, * COMMUNITY, COLLECTION or ITEM. * @param context Consider that the converted data will be stored in a * triple store, that is outside the range of the DSpace * authorization mechanism. Unless you are really sure what * you are doing, you should provide the context of an * anonymous user here, as the triple store probably provides * a public SPARQL endpoint. * @param dso DSpaceObject to convert. * @return The converted data or null if the conversion result is empty. * Remember to close the model as soon as you don't need it anymore. * @throws RDFMissingIdentifierException If no identifier could be generated. * @throws java.sql.SQLException * @throws ItemNotArchivedException If you want to convert an Item that is * not archived. * @throws ItemWithdrawnException If you want to convert an Item that is * withdrawn. * @throws ItemNotDiscoverableException If you want to convert an Item that * is not discoverable. * @throws AuthorizeException If the DSpaceObject does not have READ * permissions with the provided context. * @throws IllegalArgumentException If the DSpaceObject is not of type SITE, * COMMUNITY, COLLECTION or ITEM. */ public static Model convert(Context context, DSpaceObject dso) throws RDFMissingIdentifierException, SQLException, ItemNotArchivedException, ItemWithdrawnException, ItemNotDiscoverableException, AuthorizeException, IllegalArgumentException { if (dso.getType() != Constants.SITE && dso.getType() != Constants.COMMUNITY && dso.getType() != Constants.COLLECTION && dso.getType() != Constants.ITEM) { throw new IllegalArgumentException(dso.getTypeText() + " is currently not supported as independent entity."); } if (!RDFConfiguration.isConvertType(dso.getTypeText())) { return null; } isPublic(context, dso); return RDFConfiguration.getRDFConverter().convert(context, dso); } /** * Converts a DSpaceObject into RDF data and stores them using the configured * {@link org.dspace.rdf.storage.RDFStorage RDFStorage}. * Please note that dspace-rdf doesn't support Bundles or Bitstreams as * independent entity. You can convert DSpaceObjects of type SITE, * COMMUNITY, COLLECTION or ITEM. * @param context Consider that the converted data will be stored in a * triple store, that is outside the range of the DSpace * authorization mechanism. Unless you are really sure what * you are doing, you should provide the context of an * anonymous user here, as the triple store probably provides * a public SPARQL endpoint. * @param dso DSpaceObject to convert. * @return The converted data or null if the conversion result is empty. * Remember to close the model as soon as you don't need it anymore. * @throws RDFMissingIdentifierException If no identifier could be generated. * @throws java.sql.SQLException * @throws ItemNotArchivedException If you want to convert an Item that is * not archived. * @throws ItemWithdrawnException If you want to convert an Item that is * withdrawn. * @throws ItemNotDiscoverableException If you want to convert an Item that * is not discoverable. * @throws AuthorizeException If the DSpaceObject does not have READ * permissions with the provided context. * @throws IllegalArgumentException If the DSpaceObject is not of type SITE, * COMMUNITY, COLLECTION or ITEM. */ public static Model convertAndStore(Context context, DSpaceObject dso) throws RDFMissingIdentifierException, SQLException, ItemNotArchivedException, ItemWithdrawnException, ItemNotDiscoverableException, AuthorizeException, IllegalArgumentException { Model convertedData = convert(context, dso); String identifier = generateIdentifier(context, dso); if (StringUtils.isEmpty(identifier)) { log.error("Cannot generate identifier for dso from type " + dso.getTypeText() + " (id: " + dso.getID() + ")."); if (convertedData != null) convertedData.close(); throw new RDFMissingIdentifierException(dso.getType(), dso.getID()); } if (convertedData == null) { // if data about this dso is stored in the triplestore already, we // should remove it as a conversion currently result in no data RDFConfiguration.getRDFStorage().delete(identifier); return null; } RDFConfiguration.getRDFStorage().store(identifier, convertedData); return convertedData; } /** * Checks whether the provided DSpaceObject is readable within the provided * context and if the DSO is an Item whether it is archived, discoverable * and not withdrawn. * * @param context Consider that the converted data will be stored in a * triple store, that is outside the range of the DSpace * authorization mechanism. Unless you are really sure what * you are doing, you should provide the context of an * anonymous user here, as the triple store probably provides * a public SPARQL endpoint. * @param dso The DSpaceObjet to check. * @throws SQLException * @throws ItemNotArchivedException If {@code dso} is an Item and is not * archived. * @throws ItemWithdrawnException If {@code dso} is an Item and is withdrawn. * @throws ItemNotDiscoverableException If {@code dso} is an Item and is not * discoverable. * @throws AuthorizeException If {@code context} does not grant {@code READ} * permissions for {@code dso}. */ public static void isPublic(Context context, DSpaceObject dso) throws SQLException, ItemNotArchivedException, ItemWithdrawnException, ItemNotDiscoverableException, AuthorizeException { // as there is no way to set site permissions in XMLUI or JSPUI, we // ignore the permissions of the repository root (DSpaceObject of type // Site). if (dso instanceof Site) { return; } AuthorizeManager.authorizeAction(context, dso, Constants.READ); if (dso instanceof Item) { Item item = (Item) dso; if (!item.isArchived()) throw new ItemNotArchivedException(); if (!item.isDiscoverable()) throw new ItemNotDiscoverableException(); if (item.isWithdrawn()) throw new ItemWithdrawnException(); } } /** * Does the same as {@link #isPublic(Context, DSpaceObject) * isPublic(Context, DSpaceObject)} but returns a boolean instead of throwing * exceptions. For those who don't want to deal with catching exceptions. * @param context Consider that the converted data will be stored in a * triple store, that is outside the range of the DSpace * authorization mechanism. Unless you are really sure what * you are doing, you should provide the context of an * anonymous user here, as the triple store probably provides * a public SPARQL endpoint. * @param dso The DSpaceObjet to check. * @return true if {@link #isPublic(Context, DSpaceObject) * isPublic(Context, DSpaceObject)} doesn't throw an exception, false if it * did. * @throws SQLException */ public static boolean isPublicBoolean(Context context, DSpaceObject dso) throws SQLException { try { RDFUtil.isPublic(context, dso); } catch (ItemNotArchivedException | ItemWithdrawnException | ItemNotDiscoverableException | AuthorizeException ex) { return false; } return true; } /** * Deletes the data identified by the URI from the triple store. * @param uri URI to identify the named graph to delete. */ public static void delete(String uri) { RDFConfiguration.getRDFStorage().delete(uri); } /** * This is a shortcut to generate an RDF identifier for a DSpaceObject and * to delete the identified data from the named graph. * @param ctx * @param type DSpaceObject type (g.e. {@link Constants#ITEM Constants.ITEM}). * @param id Id of the DspaceObject. * @param handle Handle of the DSpaceObject. * @throws SQLException * @throws RDFMissingIdentifierException In case that no Identifier could be generated. */ public static void delete(Context ctx, int type, int id, String handle, String[] identifiers) throws SQLException, RDFMissingIdentifierException { String uri = RDFConfiguration.getURIGenerator().generateIdentifier(ctx, type, id, handle, identifiers); if (uri != null) { RDFConfiguration.getRDFStorage().delete(uri); } else { throw new RDFMissingIdentifierException(type, id); } } }