Example #1
0
  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"));
  }
Example #2
0
/**
 * 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;
  }
}