public RDFizer() { this.stdout = false; this.verbose = false; this.dryrun = false; this.lang = "TURTLE"; this.processed = new CopyOnWriteArraySet<UUID>(); this.context = new Context(Context.READ_ONLY); this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); this.contentServiceFactory = ContentServiceFactory.getInstance(); this.communityService = contentServiceFactory.getCommunityService(); this.itemService = contentServiceFactory.getItemService(); this.handleService = HandleServiceFactory.getInstance().getHandleService(); this.storage = RDFFactory.getInstance().getRDFStorage(); }
/* * This class retrieves items by a constructed metadata query evaluated against a set of Item Filters. * * @author Terry Brady, Georgetown University */ @Path("/filtered-items") public class FilteredItemsResource extends Resource { protected ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected SiteService siteService = ContentServiceFactory.getInstance().getSiteService(); protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); private static Logger log = Logger.getLogger(FilteredItemsResource.class); /** * Return instance of collection with passed id. You can add more properties through expand * parameter. * * @param expand String in which is what you want to add to returned instance of collection. * Options are: "all", "parentCommunityList", "parentCommunity", "items", "license" and * "logo". If you want to use multiple options, it must be separated by commas. * @param limit Limit value for items in list in collection. Default value is 100. * @param offset Offset of start index in list of items of collection. Default value is 0. * @param filters Comma separated list of Item Filters to use to evaluate against the items in a * collection * @param query_field List of metadata fields to evaluate in a metadata query. Each list value is * used in conjunction with a query_op and query_field. * @param query_op List of metadata operators to use in a metadata query. Each list value is used * in conjunction with a query_field and query_field. * @param query_val List of metadata values to evaluate in a metadata query. Each list value is * used in conjunction with a query_value and query_op. * @param collSel List of collections to query. * @param headers If you want to access to collection under logged user into context. In headers * must be set header "rest-dspace-token" with passed token from login method. * @return Return instance of collection. It can also return status code NOT_FOUND(404) if id of * collection is incorrect or status code UNATHORIZED(401) if user has no permission to read * collection. * @throws WebApplicationException It is thrown when was problem with database reading * (SQLException) or problem with creating context(ContextException). It is thrown by * NOT_FOUND and UNATHORIZED status codes, too. */ @GET @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) public org.dspace.rest.common.ItemFilter getItemQuery( @QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor, @QueryParam("filters") @DefaultValue("is_item,all_filters") String filters, @QueryParam("query_field[]") @DefaultValue("dc.title") List<String> query_field, @QueryParam("query_op[]") @DefaultValue("exists") List<String> query_op, @QueryParam("query_val[]") @DefaultValue("") List<String> query_val, @QueryParam("collSel[]") @DefaultValue("") List<String> collSel, @Context HttpHeaders headers, @Context HttpServletRequest request) { org.dspace.core.Context context = null; ItemFilterSet itemFilterSet = new ItemFilterSet(filters, true); ItemFilter result = itemFilterSet.getAllFiltersFilter(); try { context = createContext(getUser(headers)); if (!configurationService.getBooleanProperty("rest.reporting-authenticate", true)) { context.turnOffAuthorisationSystem(); } int index = Math.min(query_field.size(), Math.min(query_op.size(), query_val.size())); List<ItemFilterQuery> itemFilterQueries = new ArrayList<ItemFilterQuery>(); for (int i = 0; i < index; i++) { itemFilterQueries.add( new ItemFilterQuery(query_field.get(i), query_op.get(i), query_val.get(i))); } String regexClause = configurationService.getProperty("rest.regex-clause"); if (regexClause == null) { regexClause = ""; } List<UUID> uuids = getUuidsFromStrings(collSel); List<List<MetadataField>> listFieldList = getMetadataFieldsList(context, query_field); Iterator<org.dspace.content.Item> childItems = itemService.findByMetadataQuery( context, listFieldList, query_op, query_val, uuids, regexClause, offset, limit); int count = itemFilterSet.processSaveItems(context, childItems, true, expand); writeStats( siteService.findSite(context), UsageEvent.Action.VIEW, user_ip, user_agent, xforwarderfor, headers, request, context); result.annotateQuery(query_field, query_op, query_val); result.setUnfilteredItemCount(count); context.complete(); } catch (IOException e) { processException(e.getMessage(), context); } catch (SQLException e) { processException(e.getMessage(), context); } catch (AuthorizeException e) { processException(e.getMessage(), context); } catch (ContextException e) { processException("Unauthorized filtered item query. " + e.getMessage(), context); } finally { processFinally(context); } return result; } private List<List<MetadataField>> getMetadataFieldsList( org.dspace.core.Context context, List<String> query_field) throws SQLException { List<List<MetadataField>> listFieldList = new ArrayList<List<MetadataField>>(); for (String s : query_field) { ArrayList<MetadataField> fields = new ArrayList<MetadataField>(); listFieldList.add(fields); if (s.equals("*")) { continue; } String schema = ""; String element = ""; String qualifier = null; String[] parts = s.split("\\."); if (parts.length > 0) { schema = parts[0]; } if (parts.length > 1) { element = parts[1]; } if (parts.length > 2) { qualifier = parts[2]; } if (Item.ANY.equals(qualifier)) { for (MetadataField mf : metadataFieldService.findFieldsByElementNameUnqualified(context, schema, element)) { fields.add(mf); } } else { MetadataField mf = metadataFieldService.findByElement(context, schema, element, qualifier); if (mf != null) { fields.add(mf); } } } return listFieldList; } private List<UUID> getUuidsFromStrings(List<String> collSel) { List<UUID> uuids = new ArrayList<UUID>(); for (String s : collSel) { try { uuids.add(UUID.fromString(s)); } catch (IllegalArgumentException e) { log.warn("Invalid collection UUID: " + s); } } return uuids; } }
protected void logWorkflowEvent( Context c, String workflowId, String previousStepId, String previousActionConfigId, XmlWorkflowItem wfi, EPerson actor, Step newStep, WorkflowActionConfig newActionConfig) throws SQLException { try { // Fire an event so we can log our action ! Item item = wfi.getItem(); Collection myCollection = wfi.getCollection(); String workflowStepString = null; List<EPerson> currentEpersonOwners = new ArrayList<EPerson>(); List<Group> currentGroupOwners = new ArrayList<Group>(); // These are only null if our item is sent back to the submission if (newStep != null && newActionConfig != null) { workflowStepString = workflowId + "." + newStep.getId() + "." + newActionConfig.getId(); // Retrieve the current owners of the task List<ClaimedTask> claimedTasks = claimedTaskService.find(c, wfi, newStep.getId()); List<PoolTask> pooledTasks = poolTaskService.find(c, wfi); for (PoolTask poolTask : pooledTasks) { if (poolTask.getEperson() != null) { currentEpersonOwners.add(poolTask.getEperson()); } else { currentGroupOwners.add(poolTask.getGroup()); } } for (ClaimedTask claimedTask : claimedTasks) { currentEpersonOwners.add(claimedTask.getOwner()); } } String previousWorkflowStepString = null; if (previousStepId != null && previousActionConfigId != null) { previousWorkflowStepString = workflowId + "." + previousStepId + "." + previousActionConfigId; } // Fire our usage event ! UsageWorkflowEvent usageWorkflowEvent = new UsageWorkflowEvent( c, item, wfi, workflowStepString, previousWorkflowStepString, myCollection, actor); usageWorkflowEvent.setEpersonOwners( currentEpersonOwners.toArray(new EPerson[currentEpersonOwners.size()])); usageWorkflowEvent.setGroupOwners( currentGroupOwners.toArray(new Group[currentGroupOwners.size()])); DSpaceServicesFactory.getInstance().getEventService().fireEvent(usageWorkflowEvent); } catch (Exception e) { // Catch all errors we do not want our workflow to crash because the logging threw an // exception log.error( LogManager.getHeader( c, "Error while logging workflow event", "Workflow Item: " + wfi.getID()), e); } }
public static void main(String[] argv) throws IOException { InputStream propStream; Properties sys = System.getProperties(); // DSpace version System.out.printf("DSpace version: %s\n", Util.getSourceVersion()); // SCM revision Properties scm = new Properties(); propStream = Version.class.getResourceAsStream("/scm.properties"); if (null != propStream) { scm.load(propStream); } System.out.printf(" SCM revision: %s\n", scm.get("revision")); System.out.printf(" SCM branch: %s\n", scm.get("branch")); // OS version System.out.printf( " OS: %s(%s) version %s\n", sys.get("os.name"), sys.get("os.arch"), sys.get("os.version")); // UIs used List<WebApp> apps = UtilServiceFactory.getInstance().getWebAppService().getApps(); System.out.println(" Applications:"); for (WebApp app : apps) { System.out.printf(" %s at %s\n", app.getAppName(), app.getUrl()); } // Is Discovery available? ConfigurationService config = DSpaceServicesFactory.getInstance().getConfigurationService(); String[] consumers = config.getArrayProperty("event.dispatcher.default.consumers"); String discoveryStatus = "not enabled."; for (String consumer : consumers) { if (consumer.equals("discovery")) { discoveryStatus = "enabled."; break; } } System.out.println(" Discovery: " + discoveryStatus); // Java version System.out.printf( " JRE: %s version %s\n", sys.get("java.vendor"), sys.get("java.version")); // ant version Properties ant = new Properties(); propStream = Version.class.getResourceAsStream("/ant.properties"); if (null != propStream) { ant.load(propStream); } System.out.printf(" Ant version: %s\n", ant.get("ant.version")); // maven version Properties maven = new Properties(); propStream = Version.class.getResourceAsStream("/maven.properties"); if (null != propStream) { maven.load(propStream); } System.out.printf(" Maven version: %s\n", maven.get("maven.version")); // DSpace directory path System.out.printf(" DSpace home: %s\n", config.getProperty("dspace.dir")); }
/** * Invoke ROME library to assemble a generic model of a syndication for the given list of Items and * scope. Consults configuration for the metadata bindings to feed elements. Uses ROME's output * drivers to return any of the implemented formats, e.g. RSS 1.0, RSS 2.0, ATOM 1.0. * * <p>The feed generator and OpenSearch call on this class so feed contents are uniform for both. * * @author Larry Stone */ public class SyndicationFeed { protected final Logger log = Logger.getLogger(SyndicationFeed.class); /** i18n key values */ public static final String MSG_UNTITLED = "notitle"; public static final String MSG_LOGO_TITLE = "logo.title"; public static final String MSG_FEED_TITLE = "feed.title"; public static final String MSG_FEED_DESCRIPTION = "general-feed.description"; public static final String MSG_METADATA = "metadata."; public static final String MSG_UITYPE = "ui.type"; // UI keywords public static final String UITYPE_XMLUI = "xmlui"; public static final String UITYPE_JSPUI = "jspui"; // default DC fields for entry protected String defaultTitleField = "dc.title"; protected String defaultAuthorField = "dc.contributor.author"; protected String defaultDateField = "dc.date.issued"; private static final String[] defaultDescriptionFields = new String[] { "dc.description.abstract", "dc.description", "dc.title.alternative", "dc.title" }; protected String defaultExternalMedia = "dc.source.uri"; private final ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); // metadata field for Item title in entry: protected String titleField = configurationService.getProperty("webui.feed.item.title", defaultTitleField); // metadata field for Item publication date in entry: protected String dateField = configurationService.getProperty("webui.feed.item.date", defaultDateField); // metadata field for Item description in entry: private static final String descriptionFields[] = DSpaceServicesFactory.getInstance() .getConfigurationService() .getArrayProperty("webui.feed.item.description", defaultDescriptionFields); protected String authorField = configurationService.getProperty("webui.feed.item.author", defaultAuthorField); // metadata field for Podcast external media source url protected String externalSourceField = configurationService.getProperty("webui.feed.podcast.sourceuri", defaultExternalMedia); // metadata field for Item dc:creator field in entry's DCModule (no default) protected String dcCreatorField = configurationService.getProperty("webui.feed.item.dc.creator"); // metadata field for Item dc:date field in entry's DCModule (no default) protected String dcDateField = configurationService.getProperty("webui.feed.item.dc.date"); // metadata field for Item dc:author field in entry's DCModule (no default) protected String dcDescriptionField = configurationService.getProperty("webui.feed.item.dc.description"); // List of available mimetypes that we'll add to podcast feed. Multiple values separated by commas protected String[] podcastableMIMETypes = configurationService.getArrayProperty( "webui.feed.podcast.mimetypes", new String[] {"audio/x-mpeg"}); // -------- Instance variables: // the feed object we are building protected SyndFeed feed = null; // memory of UI that called us, "xmlui" or "jspui" // affects Bitstream retrieval URL and I18N keys protected String uiType = null; protected HttpServletRequest request = null; protected CollectionService collectionService; protected CommunityService communityService; protected ItemService itemService; /** * Constructor. * * @param ui either "xmlui" or "jspui" */ public SyndicationFeed(String ui) { feed = new SyndFeedImpl(); uiType = ui; ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance(); itemService = contentServiceFactory.getItemService(); collectionService = contentServiceFactory.getCollectionService(); communityService = contentServiceFactory.getCommunityService(); } /** * Returns list of metadata selectors used to compose the description element * * @return selector list - format 'schema.element[.qualifier]' */ public static String[] getDescriptionSelectors() { return (String[]) ArrayUtils.clone(descriptionFields); } /** * Fills in the feed and entry-level metadata from DSpace objects. * * @param request request * @param context context * @param dso DSpaceObject * @param items array of objects * @param labels label map */ public void populate( HttpServletRequest request, Context context, DSpaceObject dso, List<? extends DSpaceObject> items, Map<String, String> labels) { String logoURL = null; String objectURL = null; String defaultTitle = null; boolean podcastFeed = false; this.request = request; // dso is null for the whole site, or a search without scope if (dso == null) { defaultTitle = ConfigurationManager.getProperty("dspace.name"); feed.setDescription(localize(labels, MSG_FEED_DESCRIPTION)); objectURL = resolveURL(request, null); logoURL = ConfigurationManager.getProperty("webui.feed.logo.url"); } else { Bitstream logo = null; if (dso.getType() == Constants.COLLECTION) { Collection col = (Collection) dso; defaultTitle = col.getName(); feed.setDescription(collectionService.getMetadata(col, "short_description")); logo = col.getLogo(); String cols = ConfigurationManager.getProperty("webui.feed.podcast.collections"); if (cols != null && cols.length() > 1 && cols.contains(col.getHandle())) { podcastFeed = true; } } else if (dso.getType() == Constants.COMMUNITY) { Community comm = (Community) dso; defaultTitle = comm.getName(); feed.setDescription(communityService.getMetadata(comm, "short_description")); logo = comm.getLogo(); String comms = ConfigurationManager.getProperty("webui.feed.podcast.communities"); if (comms != null && comms.length() > 1 && comms.contains(comm.getHandle())) { podcastFeed = true; } } objectURL = resolveURL(request, dso); if (logo != null) { logoURL = urlOfBitstream(request, logo); } } feed.setTitle( labels.containsKey(MSG_FEED_TITLE) ? localize(labels, MSG_FEED_TITLE) : defaultTitle); feed.setLink(objectURL); feed.setPublishedDate(new Date()); feed.setUri(objectURL); // add logo if we found one: if (logoURL != null) { // we use the path to the logo for this, the logo itself cannot // be contained in the rdf. Not all RSS-viewers show this logo. SyndImage image = new SyndImageImpl(); image.setLink(objectURL); if (StringUtils.isNotBlank(feed.getTitle())) { image.setTitle(feed.getTitle()); } else { image.setTitle(localize(labels, MSG_LOGO_TITLE)); } image.setUrl(logoURL); feed.setImage(image); } // add entries for items if (items != null) { List<SyndEntry> entries = new ArrayList<SyndEntry>(); for (DSpaceObject itemDSO : items) { if (itemDSO.getType() != Constants.ITEM) { continue; } Item item = (Item) itemDSO; boolean hasDate = false; SyndEntry entry = new SyndEntryImpl(); entries.add(entry); String entryURL = resolveURL(request, item); entry.setLink(entryURL); entry.setUri(entryURL); String title = getOneDC(item, titleField); entry.setTitle(title == null ? localize(labels, MSG_UNTITLED) : title); // "published" date -- should be dc.date.issued String pubDate = getOneDC(item, dateField); if (pubDate != null) { entry.setPublishedDate((new DCDate(pubDate)).toDate()); hasDate = true; } // date of last change to Item entry.setUpdatedDate(item.getLastModified()); StringBuffer db = new StringBuffer(); for (String df : descriptionFields) { // Special Case: "(date)" in field name means render as date boolean isDate = df.indexOf("(date)") > 0; if (isDate) { df = df.replaceAll("\\(date\\)", ""); } List<MetadataValue> dcv = itemService.getMetadataByMetadataString(item, df); if (dcv.size() > 0) { String fieldLabel = labels.get(MSG_METADATA + df); if (fieldLabel != null && fieldLabel.length() > 0) { db.append(fieldLabel).append(": "); } boolean first = true; for (MetadataValue v : dcv) { if (first) { first = false; } else { db.append("; "); } db.append(isDate ? new DCDate(v.getValue()).toString() : v.getValue()); } db.append("\n"); } } if (db.length() > 0) { SyndContent desc = new SyndContentImpl(); desc.setType("text/plain"); desc.setValue(db.toString()); entry.setDescription(desc); } // This gets the authors into an ATOM feed List<MetadataValue> authors = itemService.getMetadataByMetadataString(item, authorField); if (authors.size() > 0) { List<SyndPerson> creators = new ArrayList<SyndPerson>(); for (MetadataValue author : authors) { SyndPerson sp = new SyndPersonImpl(); sp.setName(author.getValue()); creators.add(sp); } entry.setAuthors(creators); } // only add DC module if any DC fields are configured if (dcCreatorField != null || dcDateField != null || dcDescriptionField != null) { DCModule dc = new DCModuleImpl(); if (dcCreatorField != null) { List<MetadataValue> dcAuthors = itemService.getMetadataByMetadataString(item, dcCreatorField); if (dcAuthors.size() > 0) { List<String> creators = new ArrayList<String>(); for (MetadataValue author : dcAuthors) { creators.add(author.getValue()); } dc.setCreators(creators); } } if (dcDateField != null && !hasDate) { List<MetadataValue> v = itemService.getMetadataByMetadataString(item, dcDateField); if (v.size() > 0) { dc.setDate((new DCDate(v.get(0).getValue())).toDate()); } } if (dcDescriptionField != null) { List<MetadataValue> v = itemService.getMetadataByMetadataString(item, dcDescriptionField); if (v.size() > 0) { StringBuffer descs = new StringBuffer(); for (MetadataValue d : v) { if (descs.length() > 0) { descs.append("\n\n"); } descs.append(d.getValue()); } dc.setDescription(descs.toString()); } } entry.getModules().add(dc); } // iTunes Podcast Support - START if (podcastFeed) { // Add enclosure(s) List<SyndEnclosure> enclosures = new ArrayList(); try { List<Bundle> bunds = itemService.getBundles(item, "ORIGINAL"); if (bunds.get(0) != null) { List<Bitstream> bits = bunds.get(0).getBitstreams(); for (Bitstream bit : bits) { String mime = bit.getFormat(context).getMIMEType(); if (ArrayUtils.contains(podcastableMIMETypes, mime)) { SyndEnclosure enc = new SyndEnclosureImpl(); enc.setType(bit.getFormat(context).getMIMEType()); enc.setLength(bit.getSize()); enc.setUrl(urlOfBitstream(request, bit)); enclosures.add(enc); } else { continue; } } } // Also try to add an external value from dc.identifier.other // We are assuming that if this is set, then it is a media file List<MetadataValue> externalMedia = itemService.getMetadataByMetadataString(item, externalSourceField); if (externalMedia.size() > 0) { for (MetadataValue anExternalMedia : externalMedia) { SyndEnclosure enc = new SyndEnclosureImpl(); enc.setType( "audio/x-mpeg"); // We can't determine MIME of external file, so just picking // one. enc.setLength(1); enc.setUrl(anExternalMedia.getValue()); enclosures.add(enc); } } } catch (Exception e) { System.out.println(e.getMessage()); } entry.setEnclosures(enclosures); // Get iTunes specific fields: author, subtitle, summary, duration, keywords EntryInformation itunes = new EntryInformationImpl(); String author = getOneDC(item, authorField); if (author != null && author.length() > 0) { itunes.setAuthor(author); // <itunes:author> } itunes.setSubtitle( title == null ? localize(labels, MSG_UNTITLED) : title); // <itunes:subtitle> if (db.length() > 0) { itunes.setSummary(db.toString()); // <itunes:summary> } String extent = getOneDC( item, "dc.format.extent"); // assumed that user will enter this field with length of // song in seconds if (extent != null && extent.length() > 0) { extent = extent.split(" ")[0]; Integer duration = Integer.parseInt(extent); itunes.setDuration(new Duration(duration)); // <itunes:duration> } String subject = getOneDC(item, "dc.subject"); if (subject != null && subject.length() > 0) { String[] subjects = new String[1]; subjects[0] = subject; itunes.setKeywords(subjects); // <itunes:keywords> } entry.getModules().add(itunes); } } feed.setEntries(entries); } } /** * Sets the feed type for XML delivery, e.g. "rss_1.0", "atom_1.0" Must match one of ROME's * configured generators, see rome.properties (currently rss_1.0, rss_2.0, atom_1.0, atom_0.3) * * @param feedType feed type */ public void setType(String feedType) { feed.setFeedType(feedType); // XXX FIXME: workaround ROME 1.0 bug, it puts invalid image element in rss1.0 if ("rss_1.0".equals(feedType)) { feed.setImage(null); } } /** * @return the feed we built as DOM Document * @throws FeedException if feed error */ public Document outputW3CDom() throws FeedException { try { SyndFeedOutput feedWriter = new SyndFeedOutput(); return feedWriter.outputW3CDom(feed); } catch (FeedException e) { log.error(e); throw e; } } /** * @return the feed we built as serialized XML string * @throws FeedException if feed error */ public String outputString() throws FeedException { SyndFeedOutput feedWriter = new SyndFeedOutput(); return feedWriter.outputString(feed); } /** * send the output to designated Writer * * @param writer Writer * @throws FeedException if feed error * @throws IOException if IO error */ public void output(java.io.Writer writer) throws FeedException, IOException { SyndFeedOutput feedWriter = new SyndFeedOutput(); feedWriter.output(feed, writer); } /** * Add a ROME plugin module (e.g. for OpenSearch) at the feed level. * * @param m module */ public void addModule(Module m) { feed.getModules().add(m); } // utility to get config property with default value when not set. protected static String getDefaultedConfiguration(String key, String dfl) { String result = ConfigurationManager.getProperty(key); return (result == null) ? dfl : result; } // returns absolute URL to download content of bitstream (which might not belong to any Item) protected String urlOfBitstream(HttpServletRequest request, Bitstream logo) { String name = logo.getName(); return resolveURL(request, null) + (uiType.equalsIgnoreCase(UITYPE_XMLUI) ? "/bitstream/id/" : "/retrieve/") + logo.getID() + "/" + (name == null ? "" : name); } protected String baseURL = null; // cache the result for null /** * Return a url to the DSpace object, either use the official handle for the item or build a url * based upon the current server. * * <p>If the dspaceobject is null then a local url to the repository is generated. * * @param request current servlet request * @param dso The object to reference, null if to the repository. * @return URL */ protected String resolveURL(HttpServletRequest request, DSpaceObject dso) { // If no object given then just link to the whole repository, // since no offical handle exists so we have to use local resolution. if (dso == null) { if (baseURL == null) { if (request == null) { baseURL = ConfigurationManager.getProperty("dspace.url"); } else { baseURL = (request.isSecure()) ? "https://" : "http://"; baseURL += ConfigurationManager.getProperty("dspace.hostname"); baseURL += ":" + request.getServerPort(); baseURL += request.getContextPath(); } } return baseURL; } // return a link to handle in repository else if (ConfigurationManager.getBooleanProperty("webui.feed.localresolve")) { return resolveURL(request, null) + "/handle/" + dso.getHandle(); } // link to the Handle server or other persistent URL source else { return HandleServiceFactory.getInstance() .getHandleService() .getCanonicalForm(dso.getHandle()); } } // retrieve text for localization key, or mark untranslated protected String localize(Map<String, String> labels, String s) { return labels.containsKey(s) ? labels.get(s) : ("Untranslated:" + s); } // spoonful of syntactic sugar when we only need first value protected String getOneDC(Item item, String field) { List<MetadataValue> dcv = itemService.getMetadataByMetadataString(item, field); return (dcv.size() > 0) ? dcv.get(0).getValue() : null; } }