/**
* 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.conversion;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.util.FileManager;
import com.hp.hpl.jena.util.FileUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.LinkedList;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.app.util.Util;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.content.Site;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.rdf.RDFConfiguration;
import org.dspace.rdf.RDFUtil;
import org.dspace.services.ConfigurationService;
import org.dspace.utils.DSpace;
/**
*
* @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de)
*/
public class SimpleDSORelationsConverterPlugin
implements ConverterPlugin
{
public static final String SIMPLE_RELATIONS_PREFIXES_KEY = "rdf.simplerelations.prefixes";
public static final String SIMPLE_RELATIONS_SITE2COMMUNITY_KEY = "rdf.simplerelations.site2community";
public static final String SIMPLE_RELATIONS_COMMUNITY2SITE_KEY = "rdf.simplerelations.community2site";
public static final String SIMPLE_RELATIONS_COMMUNITY2SUBCOMMUNITY_KEY= "rdf.simplerelations.community2subcommunity";
public static final String SIMPLE_RELATIONS_SUBCOMMUNITY2COMMUNITY_KEY= "rdf.simplerelations.subcommunity2community";
public static final String SIMPLE_RELATIONS_COMMUNITY2COLLECTION_KEY = "rdf.simplerelations.community2collection";
public static final String SIMPLE_RELATIONS_COLLECTION2COMMUNITY_KEY = "rdf.simplerelations.collection2community";
public static final String SIMPLE_RELATIONS_COLLECTION2ITEM_KEY = "rdf.simplerelations.collection2item";
public static final String SIMPLE_RELATIONS_ITEM2COLLECTION_KEY = "rdf.simplerelations.item2collection";
public static final String SIMPLE_RELATIONS_ITEM2BITSTREAM_KEY = "rdf.simplerelations.item2bitstream";
private static final Logger log = Logger.getLogger(SimpleDSORelationsConverterPlugin.class);
protected ConfigurationService configurationService;
protected String[] site2community;
protected String[] community2site;
protected String[] community2subcommunity;
protected String[] subcommunity2community;
protected String[] community2collection;
protected String[] collection2community;
protected String[] collection2item;
protected String[] item2collection;
protected String[] item2bitstream;
public SimpleDSORelationsConverterPlugin()
{
site2community = RDFConfiguration.loadConfigurationArray(SIMPLE_RELATIONS_SITE2COMMUNITY_KEY);
community2site = RDFConfiguration.loadConfigurationArray(SIMPLE_RELATIONS_COMMUNITY2SITE_KEY);
community2subcommunity = RDFConfiguration.loadConfigurationArray(SIMPLE_RELATIONS_COMMUNITY2SUBCOMMUNITY_KEY);
subcommunity2community = RDFConfiguration.loadConfigurationArray(SIMPLE_RELATIONS_SUBCOMMUNITY2COMMUNITY_KEY);
community2collection = RDFConfiguration.loadConfigurationArray(SIMPLE_RELATIONS_COMMUNITY2COLLECTION_KEY);
collection2community = RDFConfiguration.loadConfigurationArray(SIMPLE_RELATIONS_COLLECTION2COMMUNITY_KEY);
collection2item = RDFConfiguration.loadConfigurationArray(SIMPLE_RELATIONS_COLLECTION2ITEM_KEY);
item2collection = RDFConfiguration.loadConfigurationArray(SIMPLE_RELATIONS_ITEM2COLLECTION_KEY);
item2bitstream = RDFConfiguration.loadConfigurationArray(SIMPLE_RELATIONS_ITEM2BITSTREAM_KEY);
if (site2community == null)
{
log.warn("SimpleDSORelationsConverterPlugin was unable to load "
+ "configuration to convert relation between the repository "
+ "the repository (SITE) and the top communities.");
}
if (community2site == null)
{
log.warn("SimpleDSORelationsConverterPlugin was unable to load "
+ "configuration to convert relation between "
+ "the top communities and the repository (SITE).");
}
if (community2subcommunity == null)
{
log.warn("SimpleDSORelationsConverterPlugin was unable to load "
+ "configuration to convert relation between "
+ "communities and subcommunities.");
}
if (subcommunity2community == null)
{
log.warn("SimpleDSORelationsConverterPlugin was unable to load "
+ "configuration to convert relation between "
+ "subcommunities and communities.");
}
if (community2collection == null)
{
log.warn("SimpleDSORelationsConverterPlugin was unable to load "
+ "configuration to convert relation between "
+ "communities and collections.");
}
if (collection2community == null)
{
log.warn("SimpleDSORelationsConverterPlugin was unable to load "
+ "configuration to convert relation between "
+ "collections and communities.");
}
if (collection2item == null)
{
log.warn("SimpleDSORelationsConverterPlugin was unable to load "
+ "configuration to convert relation between "
+ "collections and items");
}
if (item2collection == null)
{
log.warn("SimpleDSORelationsConverterPlugin was unable to load "
+ "configuration to convert relation between "
+ "items and collections");
}
if (item2bitstream == null)
{
log.warn("SimpleDSORelationsConverterPlugin was unable to load "
+ "configuration to convert relation between "
+ "items and bitstreams.");
}
}
/**
* Loads the prefixes that should be used by the
* SimpleDSORelationsConverterPlugin. Please remember to close the model
* returned by this method.
* @return A model containing the content of the file used to configure the
* RDF-Prefixes that should be used by this plugin.
*/
protected Model getPrefixes()
{
Model m = ModelFactory.createDefaultModel();
String prefixesPath = configurationService
.getProperty(SIMPLE_RELATIONS_PREFIXES_KEY);
if (!StringUtils.isEmpty(prefixesPath))
{
InputStream is = FileManager.get().open(prefixesPath);
if (is == null)
{
log.warn("Cannot find file '" + prefixesPath + "', ignoring...");
} else {
m.read(is, null, FileUtils.guessLang(prefixesPath));
try {
is.close();
}
catch (IOException ex)
{
// nothing to do here.
}
}
} else {
log.warn("Configuration does not contain path to prefixes file for "
+ "SimpleDSORelationsConverterPlugin. Will proceed without "
+ "prefixes.");
}
return m;
}
@Override
public void setConfigurationService(ConfigurationService configurationService)
{
this.configurationService = configurationService;
}
@Override
public Model convert(Context context, DSpaceObject dso)
throws SQLException
{
switch(dso.getType())
{
case (Constants.SITE) :
{
return convertSite(context, (Site) dso);
}
case (Constants.COMMUNITY) :
{
return convertCommunity(context, (Community) dso);
}
case (Constants.COLLECTION) :
{
return convertCollection(context, (Collection) dso);
}
case (Constants.ITEM) :
{
return convertItem(context, (Item) dso);
}
}
return null;
}
public Model convertSite(Context context, Site site)
throws SQLException
{
if (site2community == null)
{
log.info("Either there was a problem loading the configuration or "
+ "linking from the repository (SITE) to the top level "
+ "communities is disabled. Won't link from the repostitory "
+ "(SITE) to the top level communities.");
return null;
}
Model m = ModelFactory.createDefaultModel();
Model prefixes = this.getPrefixes();
m.setNsPrefixes(prefixes);
prefixes.close();
String myId = RDFUtil.generateIdentifier(context, site);
if (myId == null)
{
return null;
}
Community[] topLevelCommies = Community.findAllTop(context);
for (Community community : topLevelCommies)
{
if (!RDFUtil.isPublicBoolean(context, community))
{
continue;
}
String id = RDFUtil.generateIdentifier(context, community);
if (id == null)
{
continue;
}
for (String link : site2community)
{
m.add(m.createResource(myId),
m.createProperty(link),
m.createResource(id));
}
}
if (m.isEmpty())
{
log.info("There were no public sub communities we could link to.");
m.close();
return null;
}
return m;
}
public Model convertCommunity(Context context, Community community)
throws SQLException
{
if (community2site == null)
{
log.info("Either there was a problem loading the configuration or "
+ "linking from the top level communities to the repository "
+ "(SITE) is disabled. Won't link from the top level "
+ "communities to the repository (SITE).");
}
if (community2subcommunity == null)
{
log.info("Either there was a problem loading the configuration or "
+ "linking from communities to subcommunities was disabled. "
+ "Won't link from communities to subcommunities.");
}
if (subcommunity2community == null)
{
log.info("Either there was a problem loading the configuration or "
+ "linking from subcommunities to communities was disabled. "
+ "Won't link from subcommunities to communities.");
}
if (community2collection == null)
{
log.info("Either there was a problem loading the configuration or "
+ "linking from communities to collections was disabled. "
+ "Won't link from collections to subcommunities.");
}
if (community2site == null && community2subcommunity == null
&& subcommunity2community == null && community2collection == null)
{
return null;
}
Model m = ModelFactory.createDefaultModel();
Model prefixes = this.getPrefixes();
m.setNsPrefixes(prefixes);
prefixes.close();
String myId = RDFUtil.generateIdentifier(context, community);
if (myId == null)
{
return null;
}
// add all parents
DSpaceObject[] parents = community.getAllParents();
// check whether this is a top level community
if (parents.length == 0)
{
parents = new DSpaceObject[] {Site.find(context, Site.SITE_ID)};
}
for (DSpaceObject parent : parents)
{
if (!RDFUtil.isPublicBoolean(context, parent))
{
continue;
}
String id = RDFUtil.generateIdentifier(context, parent);
if (id != null)
{
if (parent instanceof Site)
{
for (String link : community2site)
{
m.add(m.createResource(myId),
m.createProperty(link),
m.createResource(id));
}
}
else if (parent instanceof Community)
{
for (String link : subcommunity2community)
{
m.add(m.createResource(myId),
m.createProperty(link),
m.createResource(id));
}
}
}
}
// add all subcommunities
for (Community sub : community.getSubcommunities())
{
if (!RDFUtil.isPublicBoolean(context, sub))
{
continue;
}
String id = RDFUtil.generateIdentifier(context, sub);
if (id == null)
{
continue;
}
for (String link : community2subcommunity)
{
m.add(m.createResource(myId),
m.createProperty(link),
m.createResource(id));
}
}
// add all collections.
for (Collection col : community.getAllCollections())
{
if (!RDFUtil.isPublicBoolean(context, col))
{
continue;
}
String id = RDFUtil.generateIdentifier(context, col);
if (id == null)
{
continue;
}
for (String link : community2collection)
{
m.add(m.createResource(myId),
m.createProperty(link),
m.createResource(id));
}
}
if (m.isEmpty())
{
m.close();
return null;
}
return m;
}
public Model convertCollection(Context context, Collection collection)
throws SQLException
{
if (collection2community == null)
{
log.info("Either there was a problem loading the configuration or "
+ "linking from collections to communities was disabled. "
+ "Won't link from collections to communities.");
}
if (collection2item == null)
{
log.info("Either there was a problem loading the configuration or "
+ "linking from collections to items was disabled. "
+ "Won't link from collections to items.");
}
if (collection2community == null && collection2item == null)
{
return null;
}
Model m = ModelFactory.createDefaultModel();
Model prefixes = this.getPrefixes();
m.setNsPrefixes(prefixes);
prefixes.close();
String myId = RDFUtil.generateIdentifier(context, collection);
if (myId == null)
{
return null;
}
// add all parents
DSpaceObject[] parents = collection.getCommunities();
for (DSpaceObject parent : parents)
{
if (!RDFUtil.isPublicBoolean(context, parent))
{
continue;
}
String id = RDFUtil.generateIdentifier(context, parent);
if (id != null)
{
for (String link : collection2community)
{
m.add(m.createResource(myId),
m.createProperty(link),
m.createResource(id));
}
}
}
// add all items
ItemIterator items = collection.getAllItems();
while (items.hasNext())
{
String id = RDFUtil.generateIdentifier(context, items.next());
if (id != null)
{
for (String link : collection2item)
{
m.add(m.createResource(myId),
m.createProperty(link),
m.createResource(id));
}
}
}
if (m.isEmpty())
{
m.close();
return null;
}
return m;
}
public Model convertItem(Context context, Item item)
throws SQLException
{
if (item2collection == null)
{
log.info("Either there was a problem loading the configuration or "
+ "linking from items to collections was disabled. "
+ "Won't link from items to collections.");
}
if (item2bitstream == null)
{
log.info("Either there was a problem loading the configuration or "
+ "linking from items to bitstreams was disabled. "
+ "Won't link from items to bitstreams.");
}
if (item2collection == null && item2bitstream == null)
{
return null;
}
Model m = ModelFactory.createDefaultModel();
Model prefixes = this.getPrefixes();
m.setNsPrefixes(prefixes);
prefixes.close();
String myId = RDFUtil.generateIdentifier(context, item);
if (myId == null)
{
return null;
}
// add all parents
Collection[] collections = item.getCollections();
for (DSpaceObject parent : collections)
{
if (!RDFUtil.isPublicBoolean(context, parent))
{
continue;
}
String id = RDFUtil.generateIdentifier(context, parent);
if (id != null)
{
for (String link : item2collection)
{
m.add(m.createResource(myId),
m.createProperty(link),
m.createResource(id));
}
}
}
// add all items
for(Bundle bundle : item.getBundles())
{
// currently link only the original files
// TODO: Discuss if LICENSEs, THUMBNAILs and/or extracted TEXTs
// should be linked/exported as well (and if sutch a feature should
// be configurable).
if (bundle.getName().equals("ORIGINAL"))
{
for (Bitstream bs : bundle.getBitstreams())
{
if (RDFUtil.isPublicBoolean(context, bs))
{
String url = bitstreamURI(bs);
if (url != null)
{
for (String link : item2bitstream)
{
m.add(m.createResource(myId),
m.createProperty(link),
m.createResource(url));
}
}
}
}
}
}
if (m.isEmpty())
{
m.close();
return null;
}
return m;
}
/**
* This methods generataes a link to the provieded Bitstream.
* As bitstreams currently don't get Persistent Identifier in DSpace, we have
* to link them using a link to the repository. This link should work with
* JSPUI and XMLUI (at least it does in DSpace 4.x).
* @param bitstream Bitstream for which a URL should be generated.
* @return The link to the URL or null if the Bistream is is a Community or
* Collection logo.
* @throws SQLException
*/
public String bitstreamURI(Bitstream bitstream)
throws SQLException
{
DSpaceObject parent = bitstream.getParentObject();
if (!(parent instanceof Item))
{
// Bitstream is a community or collection logo.
// we currently ignore those
return null;
}
String dspaceURL = configurationService.getProperty("dspace.url");
String link = "";
try
{
// this currently (DSpace 4.1) works with xmlui and jspui.
link = dspaceURL + "/bitstream/" + parent.getHandle() + "/"
+ bitstream.getSequenceID() + "/"
+ Util.encodeBitstreamName(bitstream.getName(), Constants.DEFAULT_ENCODING);
}
catch (UnsupportedEncodingException ex)
{
throw new RuntimeException("DSpace's default encoding is not supported.", ex);
}
return link;
}
@Override
public boolean supports(int type)
{
switch (type)
{
case (Constants.COLLECTION) :
return true;
case (Constants.COMMUNITY) :
return true;
case (Constants.ITEM) :
return true;
case (Constants.SITE) :
return true;
default :
return false;
}
}
}