Compare commits

..

491 Commits

Author SHA1 Message Date
Tim Donohue
d1795b598a [maven-release-plugin] prepare release dspace-5.11 2022-07-28 11:04:16 -05:00
Kim Shepherd
6f75bb084a [DS-4453] Discovery autocomplete HTML escaping (JSPUI) 2022-07-27 09:12:22 +12:00
Kim Shepherd
d1dd7d2332 [DS-4132] JPSUI resumable upload dir validation 2022-07-26 16:33:34 +12:00
Kim Shepherd
c89e493e51 [DS-4453] Escape spellcheck, autocomplete HTML (JSPUI) 2022-07-26 16:33:25 +12:00
Kim Shepherd
28eb815821 [DS-4383] Request Item Servlet escape HTML 2022-07-26 16:33:17 +12:00
Kim Shepherd
56e7604918 [DS-4131] Better path handling in ItemImport zips 2022-07-26 16:18:05 +12:00
Tim Donohue
73cdff26fd Merge pull request #8420 from tdonohue/prep_for_5.11
[Prep for 5.11] Fix DSpace 5.x branch to make it releasable again.  Add Docker Compose for easier testing.
2022-07-25 12:14:38 -05:00
Tim Donohue
aee9386468 Fix missing license header errors and warnings 2022-07-25 11:37:39 -05:00
Tim Donohue
6b1a118f39 Bug fixes to Docker CLI containers. Ensure scripts run properly. 2022-07-25 11:37:39 -05:00
Tim Donohue
26f534e9ca Ensure bin scripts ALWAYS have correct line endings 2022-07-22 10:32:35 -05:00
Tim Donohue
ff0809a0cd Migrate docker-compose scripts for 5.x from https://github.com/DSpace-Labs/DSpace-Docker-Images/ . Some refactoring needed. 2022-07-22 10:32:35 -05:00
Tim Donohue
3f130fa308 Ensure scripts keep their necessary line endings 2022-07-22 10:32:35 -05:00
Tim Donohue
0428da8dab Download Ruby gems via different manner 2022-07-22 10:32:35 -05:00
Tim Donohue
059d6f6b17 Switch to new Sonatype settings for maven releases 2022-07-22 10:32:35 -05:00
Tim Donohue
349773a55c Update DuraSpace text/links to LYRASIS. Minor updates to POM to link to GitHub Issues and Google Groups 2022-07-20 14:19:16 -05:00
Tim Donohue
6220bcd9a4 Update LICENSE and NOTICE based on latest main (resync with main) 2022-07-19 17:12:16 -05:00
Kim Shepherd
5f72424a47 [DS-4133] Improve URL handling in Controlled Vocab JSPUI servlet 2022-01-14 13:12:46 +13:00
Hrafn Malmquist
3b0cdee734 Merge pull request #1701 from atmire/DS-2852
DS-2852 - Discovery label fix for authority display value
2021-07-19 23:54:37 +01:00
Hrafn Malmquist
6f781f2a2c Merge pull request #3274 from IordanisKostelidis/dspace-5_x
fixes restlet's blocked repository - dspace 5.x
2021-07-17 23:35:30 +01:00
Iordanis Kostelidis
3145c6abbf fixes DSpace#3247 2021-07-17 15:59:15 +03:00
Tim Donohue
d0434eb4ff Update build.yml to not limit by branch
Cherry-pick of #3072
2020-11-30 10:22:59 -06:00
Tim Donohue
09021ebe4a Merge pull request #3065 from tdonohue/github_ci_5x
Add CI to GitHub via Actions (based on Travis CI config) for 5.x
2020-11-25 15:05:29 -06:00
Tim Donohue
1d635c889d Remove .travis.yml 2020-11-25 13:26:39 -06:00
Tim Donohue
79246e9bb5 Change to only run for dspace-5_x branch 2020-11-25 13:26:05 -06:00
Tim Donohue
1ae611154a Initial GitHub CI based on Travis CI & backported from 6.x 2020-11-25 13:11:15 -06:00
Tim Donohue
690b614c25 Merge pull request #2245 from tdonohue/remove_unused_oai_dep
Remove unused jackson dependencies from DSpace 5.x OAI
2020-07-17 09:37:48 -05:00
kshepherd
c38e2527f0 Merge pull request #2605 from atmire/w2p-67450_Discovery-clean-index-fix
[DS-4393] Discovery clean index fix DSpace 5
2020-03-29 12:02:41 +13:00
kshepherd
0a2cb81e8f Merge pull request #2566 from 4Science/DS-3444
[DS-3444] JSPUI must keep shibboleth attributes on session renewal
2020-03-29 11:56:55 +13:00
Tim Donohue
f93f371b21 Update to LICENSE and NOTICE per LYRASIS merger 2020-03-27 12:19:41 -05:00
kshepherd
b71b453a2d Merge pull request #2565 from AndreaJenisSaroni/DS-4377
DS-4377 Fix Sherpa RoMEO layout
2020-02-19 23:53:54 +13:00
kshepherd
f478e5bfd5 Merge pull request #2679 from kshepherd/DS-3791_date_facets_5x
[DS-3791] XMLUI facet "yearDifference" fix (5.x port)
2020-02-19 00:49:36 +13:00
Jonas Van Goolen
d028ae3044 DS-3791 Make sure the "yearDifference" takes into account that a gap of 10 year contains 11 years 2020-02-19 00:39:56 +13:00
Kristof De Langhe
a8198257fb 67450: Discovery clean index fix 2019-11-27 11:33:54 +01:00
Pascal-Nicolas Becker
153b7f9dcf [DS-3444] JSPUI must keep shibboleth attributes on session renewal 2019-11-05 10:08:16 +01:00
Andrea Jenis Saroni
fc8fa661a0 DS-4377 Fix Sherpa RoMEO layout 2019-11-04 18:02:28 +01:00
Luigi Andrea Pascarelli
f2dfef10ce Merge pull request #2517 from atmire/DS-4342-5x
[DS-4342] improve the performance of the collections/collection_id/items REST endpoint
2019-10-28 18:42:41 +01:00
Terry Brady
5faf9adca7 Merge pull request #2518 from kshepherd/DS-4144_update_node_npm_mirage2_5x
[DS-4144] Update node and npm versions for mirage 2 (5.x)
2019-09-23 13:46:57 -07:00
kshepherd
ed014de4ca Merge pull request #2514 from 4Science/dspace-5_x
DS-4340 Duplicate Headers when bitstream has a comma in the title
2019-09-22 11:15:40 +12:00
Kim Shepherd
31600ffd3d [DS-4144] Update node and npm versions for mirage 2 dependencies 2019-09-17 14:28:42 +12:00
Philip Vissenaekens
c6c3299869 DS-4342 2019-09-16 11:36:26 +02:00
Andrea Bollini
fbe6dd6fbc DS-4340 Duplicate Headers when bitstream has a comma in the title (Chrome) - JSPUI Only 2019-09-09 09:38:28 +02:00
kshepherd
1aaf345fbb Merge pull request #2361 from Georgetown-University-Libraries/ds4167r5
[DS-4167] 5x Port: Migrate update-sequences.sql to `database` command
2019-09-07 11:59:34 +12:00
Terry Brady
e6ff477c6f Merge pull request #2512 from J4bbi/ds4336v5
[DS-4336] Point Ant to archived, stable URL
2019-09-06 12:26:10 -07:00
j4bbi
127bf2a43b Point Ant to archived, stable URL 2019-09-06 19:42:48 +01:00
Tim Donohue
c418e6f0a5 Merge pull request #2506 from Georgetown-University-Libraries/ds4336r5
[DS-4336] Update ant version in Docker Build (5x)
2019-09-06 18:06:08 +02:00
Terry Brady
12f4736808 update ant version 2019-09-05 10:51:23 -07:00
Tim Donohue
57bae82553 Merge pull request #2482 from mwoodiupui/2477-5_x
Travis CI: Continue to use Ubuntu Trusty 14.04
2019-08-06 23:16:24 +02:00
Mark H. Wood
75693d95ae Tell Travis to boot Trusty Tahr, not Xenial Xerus, so we get Java 8 not 11. 2019-08-06 16:29:35 -04:00
Bram Luyten
f7f61fd6c4 Merge pull request #1691 from samuelcambien/dspace-5_DS-3545
DS-3545 mirage2: custom sitemap.xmap is ignored
2019-07-05 14:39:33 +02:00
Terry Brady
ad94cd7196 fix seq sql 2019-03-09 17:36:45 -08:00
Terry Brady
7465ef67c5 fix typos 2019-03-09 17:03:16 -08:00
Terry Brady
961b958326 Initial port of PR 2348 2019-03-08 16:11:12 -08:00
Terry Brady
ef01ed688b Merge pull request #2345 from terrywbrady/ds4126d5
[DS-4126] 5x: Optimize docker builds
2019-02-20 13:16:46 -08:00
Terry Brady
8b56447d40 update comment 2019-02-07 07:42:07 -08:00
Terry Brady
d46ff561f2 comment typo 2019-02-07 07:41:16 -08:00
Terry Brady
46c7c2936c Update Dockerfile.jdk7-test 2019-02-06 16:18:50 -08:00
Terry Brady
1de03d0eea Update Dockerfile.jdk7 2019-02-06 16:18:16 -08:00
Terry Brady
d0f2a5744e resolve build clean issues 2019-02-06 15:21:50 -08:00
Mark H. Wood
36c5a94154 Merge pull request #2271 from AndrewBennet/dspace-5_x
[DS-4085] Update abdera-client dependency to 1.1.3
2019-02-06 16:05:53 -05:00
Terry Brady
ebfc93cf14 port pr2307 2019-02-06 12:18:23 -08:00
Terry Brady
25f0ff10d4 Merge pull request #2326 from J4bbi/ds4142_5x
[DS-4142] dspace-5x: update maven jdks for docker
2019-01-14 13:50:43 -08:00
kshepherd
caca40e45c Merge pull request #2330 from Georgetown-University-Libraries/dsMir2a
[DS-4115] Update bower version to fix Mirage2 build
2019-01-15 09:25:43 +13:00
Terry Brady
8399e8c768 Match bower version for 6x 2019-01-14 11:22:23 -08:00
Hrafn Malmquist
98c989210a update maven jdks for docker 2019-01-14 17:17:55 +00:00
kshepherd
99bfe8cf02 Merge pull request #2295 from DSpace/DS-4104-Avoid-crosswalk-of-incorrect-dates-for-google-scholar
DS-4104 Avoid crosswalking wrong dates for GS
2019-01-13 14:36:30 +13:00
kshepherd
c745b89fea Merge pull request #2316 from Georgetown-University-Libraries/ds4115
[DS-4115] Update SASS and Ruby ver
2019-01-04 10:23:27 +13:00
Terry Brady
3345c6b9a0 Note ruby ver in documentation. 2019-01-03 12:46:59 -08:00
Terry Brady
2d7aa1fbb4 Update SASS and Ruby ver 2019-01-03 11:12:41 -08:00
Bram Luyten
e8abd073fc DS-4104 Avoid crosswalking wrong dates for GS 2018-12-13 08:24:56 +01:00
Andrew Bennet
2f2a10e95e Update abdera-client dependency to 1.1.3 2018-11-22 16:12:08 +00:00
Tim Donohue
7c2e039c7b Remove unused, old dependencies 2018-10-19 21:48:12 +00:00
Tim Donohue
837b4f7882 Merge pull request #2233 from mwoodiupui/DS-4031
[DS-4031] Updated link to DRIVER guidelines.
2018-10-18 11:42:48 -05:00
Terry Brady
bc7707624a Merge pull request #2217 from terrywbrady/ds4012_5x
[DS-4012] port to 5x for Jdk7 and 8
2018-10-17 11:49:08 -07:00
Terry Brady
ca35e6086b pr comments 2018-10-10 08:34:55 -07:00
Mark H. Wood
8b7c2a872f [DS-4031] Updated link to DRIVER guidelines. 2018-10-05 14:15:54 -04:00
Terry Brady
3b40088c04 [maven-release-plugin] prepare for next development iteration 2018-10-04 13:48:07 -04:00
Terry Brady
eca7968be7 [maven-release-plugin] prepare release dspace-5.10 2018-10-04 13:47:58 -04:00
Terry Brady
d0d4708a08 Merge pull request #2230 from Georgetown-University-Libraries/license-5.10
5.10 Update License
2018-10-04 08:57:26 -07:00
Terry Brady
0a4c7c54dd Collapse additional entries 2018-10-04 08:42:03 -07:00
Terry Brady
9730d69c24 pull license merge rules from prod 2018-10-04 08:30:16 -07:00
Terry Brady
e2e6e17c23 add license 2018-10-04 08:02:43 -07:00
Tim Donohue
e1e7bf13ff Merge pull request #2221 from Georgetown-University-Libraries/ds-2948_5x
[DS-2948] Port to 5x
2018-10-03 10:11:51 -05:00
Terry Brady
52342f039d port from 6x, hide noise from snippets 2018-10-01 13:55:36 -07:00
Terry Brady
e06e7c99da tomcat ver sel 2018-10-01 10:29:58 -07:00
Terry Brady
f2d11ba1d1 Merge pull request #2220 from Georgetown-University-Libraries/ds4020
[DS-4020] fix statistics logging issue in DSpace 5.9
2018-10-01 08:29:27 -07:00
Terry Brady
0bfebb8366 fix config ref 2018-09-28 08:13:59 -07:00
Terry Brady
776e8976b6 comment update 2018-09-27 23:04:39 -07:00
Terry Brady
23eb3d4ef9 port to 5x for Jdk7 and 8 2018-09-27 16:35:37 -07:00
Tim Donohue
3017df42ba Merge pull request #2204 from AlexanderS/DS-3664-5_x
[DS-3664] ImageMagick: Only execute "identify" on first page
2018-09-17 09:41:56 -05:00
Alexander Sulfrian
4e8c7b578b ImageMagick: Only execute "identify" on first page
The Info object used to get the color format runs "identify" on the supplied
input file. If the file has many pages, this process might require some time.
"identify" supports the same syntax for the input file like the other
ImageMagick tools and we can simply restrict the pages by changing the input
file name.

This fixes DS-3664.
2018-09-17 15:05:28 +02:00
Terry Brady
aa2895a49e Merge pull request #2197 from atmire/DS-4000
DS-4000: REST API (v5.9) does not run
2018-09-04 08:17:29 -07:00
Philip Vissenaekens
556eaf826f DS-4000 2018-09-04 09:59:54 +02:00
Mark H. Wood
59d6fb7dcc Merge pull request #2104 from jmarton/DS-3938_5x
[DS-3938] Use JDK7-compatible PostgreSQL JDBC driver in DSpace 5.x
2018-08-22 15:57:43 -04:00
Tim Donohue
f355da6494 Merge pull request #2136 from terrywbradyC9/dockerDspace5x
[DS-3967] 5x - Migrate Dockerfile to DSpace/DSpace
2018-08-21 15:10:00 -05:00
Terry Brady
655b17a55c enable Mirage2 by default 2018-08-02 15:20:15 -07:00
Terry Brady
31d5e621b8 docker usage comment 2018-08-01 19:03:49 -07:00
Terry Brady
04ec8af4e5 move docker res 2018-08-01 16:02:52 -07:00
Terry Brady
841ba85cbb add usage link 2018-07-25 17:56:41 -07:00
Terry Brady
c3c339141a Migrate 5x Dockerfile 2018-07-25 17:16:45 -07:00
Jozsef Marton
c9a9337b1b [DS-3938] Use JDK7-compatible PostgreSQL JDBC driver 2018-06-29 15:53:20 +02:00
Tim Donohue
75ac9a882e [maven-release-plugin] prepare for next development iteration 2018-06-25 21:13:50 +00:00
Tim Donohue
be88702e4e [maven-release-plugin] prepare release dspace-5.9 2018-06-25 21:13:36 +00:00
Tim Donohue
b5e0777575 Merge pull request #2100 from kshepherd/DS-3936_bower_registry_needs_updated_5.x
DS-3936 bower registry needs updating (5.x port)
2018-06-25 13:48:50 -05:00
Tim Donohue
2b8a177c71 Merge pull request #2018 from the-library-code/DS-3886
DS-3886: Adopt tests to versioning and DOI-support
2018-06-25 10:40:31 -05:00
Kim Shepherd
ce6212bcfc fix typo in json bowerrc 2018-06-25 09:13:05 +00:00
Kim Shepherd
83f74f93a0 update bower registry to https://registry.bower.io as per official instructions 2018-06-25 09:12:57 +00:00
kshepherd
f002a3e885 Merge pull request #2062 from tdonohue/DS-3447-ORCID-v2-5.x-port
DS-3447: ORCID v2 integration (port to 5.x from PR#2039)
2018-06-25 12:01:13 +12:00
kshepherd
8b849559bc Merge pull request #2094 from tdonohue/DS-950-5.x
DS-950: OAI should respect metadata.hidden... config properties.
2018-06-23 13:41:24 +12:00
kshepherd
d00880481a Merge pull request #2020 from tdonohue/DS-3883-port-to-5.x
DS-3883: Speed up Item summary lists by being smarter about when we load Thumbnails/Bitstreams (port to 5.x)
2018-06-22 12:06:20 +12:00
Terry Brady
2a70460983 Merge pull request #1789 from helix84/DS-3245-dspace-5_x
DS-3245: CSV linebreaks not supported by Bulkedit - DSpace 5 backport
2018-06-21 18:04:50 -06:00
kshepherd
2bf85d9e8d Merge pull request #1968 from mwoodiupui/DS-3853
[DS-3202] PMH Responder returns 500 Internal Error if item is in no Community or no Collection
2018-06-22 10:21:07 +12:00
Tim Donohue
8ebdc626db DS-950: OAI should respect metadata.hidden... config properties. 2018-06-20 19:57:22 +00:00
Tim Donohue
f7509e95f0 Merge pull request #2092 from tdonohue/DS-3866-5.x
fixes for DS-3866 (for 5.x branch)
2018-06-19 15:51:48 -05:00
Tim Donohue
ac796e51ba Merge pull request #2090 from tdonohue/DS-3840-5.x
Fixes for DS-3480 (for 5.x branch)
2018-06-19 15:44:49 -05:00
Kim Shepherd
df2a6a59e5 fixes for DS-3866 2018-06-18 21:42:42 +00:00
Kim Shepherd
1008277c02 Fixes for DS-3480 2018-06-18 21:22:22 +00:00
Tim Donohue
1d91a47d23 DS-3447: ORCID v2 integration (port to 5.x from PR#2039) 2018-05-15 16:27:51 -05:00
Tim Donohue
b8e289ae73 Merge pull request #1855 from helix84/DS-3705-reference-fix-pagination-5_x
DS-3705 Recent Submissions in Reference theme completely covered up by navigation (5.x)
2018-05-02 10:45:04 -05:00
kshepherd
3fe47c95a2 Merge pull request #2011 from mwoodiupui/DS-3832-v5
[DS-3832] GeoIP-API(com.maxmind.geoip:geoip-api) needs to be replaced by GeoIP2 ( com.maxmind.geoip2:geoip2 )
2018-04-19 09:51:04 +12:00
Mark H. Wood
41ed0511ec [DS-3832] Fix cherry-pick mention of class renamed in v6. 2018-04-18 16:53:39 -04:00
Mark H. Wood
e0f8da6671 [DS-3832] Don't spew stack traces for simple exceptions. 2018-04-18 16:38:16 -04:00
kshepherd
0a89ba8834 Merge pull request #1806 from atmire/DS-3560
DS-3560 MathJax CDN provider change
2018-04-15 12:09:47 +12:00
Tim Donohue
8d81e825de DS-3883: If only including thumbnails, only load the main item thumbnail. 2018-04-12 16:15:44 +00:00
Tim Donohue
a0ea20bd18 DS-3883: Don't loop through original bitstreams if only displaying thumbnails 2018-04-12 15:37:13 +00:00
Pascal-Nicolas Becker
a392058032 DS-3886: Adopt tests to versioning and DOI-support 2018-04-12 13:59:17 +02:00
Tim Donohue
31a19e7084 Merge pull request #2005 from Georgetown-University-Libraries/ds3835r5
[DS-3835] Port PR 1951 to 5x
2018-04-02 10:10:54 -05:00
Mark H. Wood
4d2cde0bfb [DS-3832] DSpace 5 has fewer mocks, more classes using GeoIP. 2018-03-30 10:03:46 -04:00
Mark H. Wood
17b2d0a67e [DS-3832] Clean up more references to v1 database. 2018-03-30 09:29:11 -04:00
Mark H. Wood
9fc0ce0df7 [DS-3832] Fetch and use GeoLite v2 City database. 2018-03-30 09:27:42 -04:00
Mark H. Wood
a16168edbe [DS-3832] Resolve dependency convergence problems. 2018-03-30 09:24:04 -04:00
Mark H. Wood
b869a242d3 [DS-3832] Fix ElasticSearch too. 2018-03-30 09:17:41 -04:00
Mark H. Wood
246df7b265 [DS-3832] Recast test support classes. 2018-03-30 09:11:22 -04:00
Mark H. Wood
78e68f6cb7 [DS-3832] Upgrade to GeoIP2. 2018-03-30 09:10:49 -04:00
Terry W Brady
c01a12f3d8 port PR 1951 to 5x 2018-03-28 15:00:03 -07:00
Tim Donohue
88e7b322c0 Merge pull request #1970 from tdonohue/latest_postgres_jdbc_5x
DS-3854: Update to latest PostgreSQL JDBC driver
2018-03-21 13:49:14 -05:00
Tim Donohue
682b4b0043 Update to latest PostgreSQL JDBC driver 2018-02-26 20:37:07 +00:00
Tim Donohue
418fd92a4c Merge pull request #1965 from mwoodiupui/DS-3852
[DS-3852]OAI indexer message not helpful in locating problems
2018-02-26 09:31:01 -06:00
Mark H. Wood
4e30af2c0f [DS-3853] Detect null Collection and skip on. 2018-02-24 18:39:10 -05:00
Mark H. Wood
07b050cf7d [DS-3852] Give more information about the item just indexed, to help identify it in case of problems. 2018-02-24 16:52:33 -05:00
kshepherd
483d23ae82 Merge pull request #1962 from hardyoyo/DS-3839-revised-5_x
[DS-3839] moved the autoorient IM op to the top of the operations list
2018-02-20 16:05:09 +13:00
Hardy Pottinger
2d6fceed53 [DS-3839] moved the autoorient IM op to the top of the operations list, where it belongs 2018-02-19 17:45:03 -06:00
Tim Donohue
4a5649174f Merge pull request #1958 from hardyoyo/DS-3839-support-autoorient-for-imagemagick-thumbnails-dspace_5x
[DS-3839] backporting DSPR#1956 for dspace-5_x
2018-02-16 09:31:30 -06:00
Hardy Pottinger
75e100d97e [DS-3839] backporting DSPR#1956 for dspace-5_x 2018-02-16 08:15:11 -06:00
Hardy Pottinger
577f3e31fe [DS-3757] increase default clamav socket timeout to 6 minutes (#1886) 2017-11-27 10:27:40 -06:00
Lotte Hofstede
ff1f01224f DS-3560: update deprecated MathJax url 2017-11-21 11:05:14 +01:00
Ivan Masár
52ec272ee6 DS-3705 Recent Submissions in Reference theme completely covered up by navigation 2017-10-04 10:52:30 +02:00
Terry Brady
890b04689f [maven-release-plugin] prepare for next development iteration 2017-09-01 12:36:10 -04:00
Terry Brady
50eca14e9f [maven-release-plugin] prepare release dspace-5.8 2017-09-01 12:25:57 -04:00
Hardy Pottinger
51b74510b9 [DS-3674] copied over input-forms.xml to the test config folder 2017-08-15 14:46:12 -05:00
Terry Brady
f96185dcea Merge pull request #1817 from Georgetown-University-Libraries/ds3661
[DS-3661] ImageMagick PDF Processing Degraded with Changes in 5.7 release
2017-08-09 11:04:58 -07:00
Terry W Brady
98ac9ed3ce bypass color profile check if not configured 2017-08-07 12:22:45 -07:00
Tim Donohue
50ac3b6819 Pin versions of SASS and Compass that Travis uses 2017-07-13 16:59:57 +00:00
Tim Donohue
ec8e839ef5 [maven-release-plugin] prepare for next development iteration 2017-07-12 19:44:29 +00:00
Tim Donohue
3832acc63e [maven-release-plugin] prepare release dspace-5.7 2017-07-12 19:44:19 +00:00
Tim Donohue
12f978ecee Rollback LNI versions manually 2017-07-12 18:32:56 +00:00
Tim Donohue
9981dfcacd [maven-release-plugin] rollback the release of dspace-5.7 2017-07-12 18:21:52 +00:00
Tim Donohue
ec5056750f [maven-release-plugin] prepare for next development iteration 2017-07-12 18:03:12 +00:00
Tim Donohue
266d016653 [maven-release-plugin] prepare release dspace-5.7 2017-07-12 18:03:01 +00:00
Mark H. Wood
4f0e0aec5e Fix doc comments to evade error on finding 'Javascript' in them 2017-07-12 17:24:01 +00:00
Mark H. Wood
f673b8da37 Update copyright claim years for release 2017-07-12 17:23:20 +00:00
Tim Donohue
e55212c14f DS-3431 : Fix broken tests by adding missing H2 migration 2017-07-11 15:44:18 +00:00
Tim Donohue
9401d971f6 DS-3431 : Fix broken tests by removing nullifying of global eperson 2017-07-11 14:37:46 +00:00
Mark H. Wood
090b617c28 [DS-3431] Harden DSpace's BasicWorfklowService 2017-07-11 14:37:08 +00:00
Tim Donohue
504e2ae270 Merge pull request #1724 from atmire/DS-2359-5x
DS-2359 Error when depositing large files via browser (over 2Gb)
2017-07-08 05:58:05 +10:00
Tim Donohue
99683cb810 Merge pull request #1781 from atmire/DS-3595-5x
DS-3595: Language change causes "page not found" error in several forms on XMLUI
2017-07-06 07:22:34 +10:00
Tim Donohue
dab9bd40ed Merge pull request #1733 from samuelcambien/dspace-5-DS-3584
DS-3584 when editing an eperson, trying to change its email address is ignored if another user already has that email address
2017-07-06 07:08:01 +10:00
Tim Donohue
7bbeea2633 Merge pull request #1794 from atmire/DS-3563_Missing-index-metadatavalue-resource-type-id
DS-3563: Fix Oracle Flyway migration error
2017-07-06 01:33:45 +10:00
Tom Desair
0182392563 DS-3563: Fix Oracle Flyway migration error 2017-07-04 16:51:05 +02:00
Àlex Magaz Graça
1c3673b37d DS-3245: CSV linebreaks not supported by Bulkedit
When a multiline field contained empty lines, the importer stopped
reading the file. This reverts a change in 53d387fed to stop when the
end of the file has been reached instead.

Fixes https://jira.duraspace.org/browse/DS-3245
2017-06-30 10:11:43 +02:00
Lotte Hofstede
94faee2fd4 40648: fix for filters 2017-06-27 10:47:06 +02:00
Mark H. Wood
40d5f113a9 Merge pull request #1697 from tomdesair/DS-2748-5x_Improve-cocoon-page-not-found-page
DS-2748: Do not throw an exception in the PageNotFoundTransformer
2017-06-22 08:50:36 -04:00
Philip Vissenaekens
97b22916f4 DS-3595 2017-06-21 17:42:52 +02:00
Lotte Hofstede
98c38d38e1 Merge branch 'dspace-5_x' into DS-2852
Conflicts:
	dspace-xmlui-mirage2/src/main/webapp/templates/discovery_simple_filters.hbs
2017-06-14 11:53:07 +02:00
Pascal-Nicolas Becker
711b4e8a96 Merge pull request #1669 from alanorth/DS-3517
DS-3517 Allow improved handling of CMYK PDFs
2017-06-07 22:45:39 +02:00
kshepherd
778f9dfec0 Merge pull request #1700 from atmire/DS-3551-DB-connections-reduction
DS-3551 db connections reduction
2017-06-02 21:13:50 +12:00
Tim Donohue
15046de363 Merge pull request #1743 from arvoConsultores/DS-3281
DS-3281 - Submisisions made through REST API (POST/item method) use workflow
2017-05-31 13:52:30 -07:00
kshepherd
ed8b31721f Merge pull request #1706 from atmire/DS-3563_Missing-index-metadatavalue-resource-type-id
Ds 3563 missing index metadatavalue resource type id
2017-05-30 13:22:11 +12:00
aroman
9edd2cd218 DS-3281 - Submisisions made through REST API (POST/item method) don´t
get into workflow-approvals
2017-05-09 08:24:41 +02:00
Lotte Hofstede
4d28fa42cc 40648: DS-2852 - Nullpointer prevention 2017-05-04 11:44:49 +02:00
Jonas Van Goolen
a7bed3a293 DS-3551 Additional required mocking of method 2017-05-04 09:03:54 +02:00
Jonas Van Goolen
d917b3158d DS-3551 "ContextAwareDisseminationCrosswalk" + Javadoc expactations of DisseminationCrosswalk interface 2017-04-28 11:21:44 +02:00
Jonas Van Goolen
aef0f52a5b DS-3551 Javadoc update + Remove additional "null" param for getColumnNames method 2017-04-28 11:21:44 +02:00
Tom Desair
09713ea4a8 DS-3551 Added some deprecation warnings 2017-04-28 11:21:44 +02:00
Jonas Van Goolen
54f5cd87fc DS-3551: Reuse database connection when requesting item page or bitstream 2017-04-28 11:21:43 +02:00
Jonas Van Goolen
c8f62e6f49 DS-3583 Usage of correct Collection Array (#1731)
* DS-3583 Usage of correct Collection Array

* DS-3583 Reverting of import rearrangement
2017-04-26 12:16:25 -07:00
Tim Donohue
bdf665b07e Merge pull request #1738 from cjuergen/DS-3585-5_x
Fix for DS-3585
2017-04-26 11:08:05 -07:00
cjuergen
8a790dedd3 Fix for DS-3585 2017-04-26 14:44:11 +02:00
samuel
23aa21ae86 DS-3584 when editing an eperson, trying to change its email address is ignored if another user already has that email address 2017-04-26 11:37:22 +02:00
Tom Desair
9f531fb244 DS-3563: Conditional create index for Oracle 2017-04-24 11:05:53 +02:00
Mark H. Wood
5a1943cf22 Merge pull request #1718 from mwoodiupui/DS-3505-5x
[DS-3505] Bad redirection from logout action (ported to dspace-5_x)

We've seen several successful tests (see the Jira issue).  Merging.
2017-04-20 08:49:54 -04:00
Philip Vissenaekens
2a627d8bbd DS-2359 2017-04-20 14:19:46 +02:00
Terry Brady
632a55d894 Merge pull request #1709 from alanorth/DS-3516
DS-3516 ImageMagick PDF Thumbnail class should only process PDFs
2017-04-19 14:37:30 -07:00
Mark H. Wood
b434b999b7 [DS-3505] Bad redirection from logout action (ported to dspace-5_x) 2017-04-19 15:15:35 -04:00
Tim Donohue
3963d3929e Merge pull request #1712 from atmire/DS-3573-Filtername-in-XMLUI-Discovery-filter-labels
DS-3573: Filtername in XMLUI Discovery filter labels
2017-04-19 09:19:43 -07:00
Alan Orth
f81cdf5283 DS-3516 ImageMagick PDF Thumbnail class should only process PDFs
Input formats for ImageMagick mediafilter plugins should be defined
in dspace.cfg. Currently they implement SelfRegisteredInputFormats,
which causes the PDF filter to attempt to process other formats in
the ORIGINAL bitstream bundle.
2017-04-14 14:29:09 +03:00
Yana De Pauw
dd7502f758 DS-3573: Filtername in XMLUI Discovery filter labels 2017-04-14 13:03:01 +02:00
Tom Desair
d557c019f2 DS-3563 Added missing index on metadatavalue.resource_type_id 2017-04-11 16:41:05 +02:00
Lotte Hofstede
e010c2acff 40648: DS-2852 - Discovery label fix for authority display value 2017-04-06 16:10:11 +02:00
Tom Desair
7467741624 DS-2748: Do not throw an exception in the PageNotFoundTransformer but do return a 404 error code 2017-04-05 15:50:22 +02:00
Alan Orth
91a00e237c DS-3517 Allow improved handling of CMYK PDFs
Allow ImageMagick to generate thumbnails with more accurate colors
for PDFs using the CMYK color system. This adds two options to the
dspace.cfg where the user can optionally specify paths to CMYK and
RGB color profiles if they are available on their system (they are
provided by Ghostscript 9.x).

Uses im4java's Info class to determine the color system being used
by the PDF.

See: http://im4java.sourceforge.net/docs/dev-guide.html
2017-04-01 13:11:44 +03:00
samuel
274f41258c DS-3545 mirage2: custom sitemap.xmap is ignored
Conflicts:
	dspace/modules/xmlui-mirage2/pom.xml
2017-03-28 12:57:55 +02:00
Peter Dietz
f45252547d DS-3366 Fix handleresolver by removing out.close (#1560) 2017-03-08 12:24:10 -06:00
Tim Donohue
d2c123d8c9 Merge pull request #1528 from aschweer/DS-3336-sort-movedropdown-5_x
[DS-3336] Properly sort collections in move item drop-down
2017-03-08 11:46:30 -06:00
Tim Donohue
943619248a DS-3520 fix. Upgrade Commons Collections to 3.2.2 2017-03-06 15:14:36 +00:00
Bram Luyten
848aea9b27 Merge pull request #1667 from jonas-atmire/DS-3518-PasswordAuthentication-bugfix
DS-3518 5_X port of JIRA Ticket DS-2941
2017-03-04 08:08:39 +01:00
Jonas Van Goolen
b8e784f8c2 DS-3518 5_X port of JIRA Ticket DS-2941 2017-03-03 10:20:59 +01:00
Tim Donohue
0b9d05154c Workaround for travis-ci/travis-ci#4629 2017-02-27 21:44:57 +00:00
Tim Donohue
5a81ba0f3b Merge pull request #1616 from jonas-atmire/DS-3448-MultiSelect-in-Submission_5_x
DS-3448 Multi-select in submission for workflow and workspace items
2017-02-22 14:46:39 -06:00
Tim Donohue
63ab1f13f8 Merge pull request #1592 from samuelcambien/dspace-5-3425
DS 3425 outputstream gets closed in JSONDiscoverySearcher
2017-02-21 15:33:58 -06:00
Tim Donohue
19d8144faa Merge pull request #1591 from samuelcambien/dspace-5-3415
DS-3415 - administrative.js doEditCommunity wrong parameter name
2017-02-21 15:00:00 -06:00
Bram Luyten
7d53df0d6b DS-2840 changing log level to DEBUG sidebar facet
Changes INFO level sidebar facet transformer log entries to DEBUG
2017-02-18 14:21:31 +01:00
Luigi Andrea Pascarelli
2bd6c2e392 DS-3356 add turnoff authz system (#1552) 2017-02-15 16:13:36 -06:00
Terry Brady
b0e624d72c Port 6x changes by Tom D to 5x, make static method (#1645) 2017-02-09 11:26:27 -06:00
Tim Donohue
b37bd18c51 Merge pull request #1643 from Georgetown-University-Libraries/ds3458-5xA
[DS-3458]5x Allow Shard Process to Append to an existing repo
2017-02-09 08:41:59 -06:00
Terry Brady
51bb72da2a Attempt to force travis to rebuild 2017-02-08 14:31:19 -08:00
Terry W Brady
3c8ecb5d1f Re-apply ping fix 2017-02-08 11:24:28 -08:00
Tim Donohue
59302e9d6f Merge pull request #1640 from cjuergen/DS-3479-5_x
Fix for DS-3479 avoid adding empty metadata values during import
2017-02-08 10:16:41 -06:00
Terry Brady
567ec083c8 [DS-3456] 5x Clarify command line options for statisics import/export tools (#1623)
* Clarify command line options

* Allow overwrite flag for import and export

* Document -o behavior for overwrite option

* Allow export file overwrite during re-index

* Fix DS-3464 solr-reindex-statistics

* Allow safe import/export of multivalue fields

* force another commit

* Use UTC year to prevent Jan 01 stats creating prior year shard

* Remove overloading of the -o option

* Limit import files for -i statistics

* Add more context to warning messages

* whitespace
2017-02-08 09:45:09 -06:00
cjuergen
329f3b48a6 Fix for DS-3479 avoid adding empty metadata values during import 2017-02-07 11:58:41 +01:00
Tim Donohue
a52779c571 Merge pull request #1628 from Georgetown-University-Libraries/ds3468-5x
[DS-3468] 5x Ignore bin directory created by Eclipse
2017-02-01 14:40:19 -06:00
Terry Brady
9a0334da7f Ensure only top level exclusion of bin 2017-01-26 07:11:59 -08:00
Terry W Brady
8e4db1344e Ignore bin directory created by Eclipse 2017-01-25 11:26:32 -08:00
Jonas Van Goolen
a9b8cca20f DS-3448 Removal of unnecessary duplicate javascript file 2017-01-13 09:53:38 +01:00
Jonas Van Goolen
93f368ff6b DS-3448 Multi-select in submission for workflow and workspace items 2017-01-12 14:02:17 +01:00
Tim Donohue
fbc023019c Merge pull request #1609 from bram-atmire/DS-3289-5_x
DS-3289 Removing duplicate slashes
2017-01-09 09:16:48 -06:00
Bram Luyten
e00dc3d421 DS-3289 Removing duplicat slashes 2017-01-07 19:17:27 +01:00
Bram Luyten
77a4da32ec Merge pull request #1606 from 4Science/DS-3441-5x
DS-3441 READ permission on the Collection object not respected by the JSPUI (5_x)
2017-01-06 18:19:00 +01:00
Andrea Bollini
79014ed943 DS-3441 READ permssion on the Collection object not respected by the JSPUI 2017-01-06 14:11:02 +01:00
samuel
0dbaa81b54 DS 3425 outputstream gets closed in JSONDiscoverySearcher 2016-12-21 13:26:07 +01:00
samuel
c36e6f9f02 DS-3415 - administrative.js doEditCommunity wrong parameter name 2016-12-21 13:25:40 +01:00
Ivan Masár
f7b6c83e99 DS-3363 CSV import error says "row", means "column" 2016-11-14 18:28:35 +01:00
Luigi Andrea Pascarelli
2510609f68 [maven-release-plugin] prepare for next development iteration 2016-09-29 19:09:38 +02:00
Luigi Andrea Pascarelli
03724151be [maven-release-plugin] prepare release dspace-5.6 2016-09-29 19:09:29 +02:00
Luigi Andrea Pascarelli
52db795b72 Merge pull request #1541 from 4Science/DS-3347
DS-3347 manage empty configuration string for request a copy
2016-09-29 16:04:50 +02:00
Luigi Andrea Pascarelli
5f3f552078 DS-3347 manage empty configuration string for request a copy 2016-09-29 15:53:34 +02:00
Luigi Andrea Pascarelli
39f4db91da Merge pull request #1538 from 4Science/DS-3346-for-5
DS-3346 change deprecated setIgnoreAuthorization in favour of turnOff…
2016-09-28 23:23:15 +02:00
Luigi Andrea Pascarelli
04ba49ba56 DS-3346 change deprecated setIgnoreAuthorization in favour of turnOff/restore 2016-09-28 22:58:13 +02:00
Luigi Andrea Pascarelli
1aa92f8d00 Merge pull request #1531 from 4Science/DS-2623-porting
DS-2623 backport set description in the upload step files
2016-09-28 22:17:47 +02:00
Luigi Andrea Pascarelli
85f2195396 Reintroduce deprecated method referenced by dspace-lni for backward compatibility (related to DS-2604) 2016-09-26 19:44:44 +02:00
Luigi Andrea Pascarelli
c5cdedb0c6 Merge pull request #1522 from lap82/DS-2604-porting-cc_5
DS-2604 port - DSpace 5.x - from XMLUI to JSPUI the approach to queries Creative Commons service (via REST API)
2016-09-26 18:49:07 +02:00
Luigi Andrea Pascarelli
b805aaf1dd DS-2604 add some comment 2016-09-26 18:42:01 +02:00
Luigi Andrea Pascarelli
da315a4911 Merge pull request #1533 from 4Science/DS-3340
DS-3340 fix test
2016-09-26 17:45:15 +02:00
Luigi Andrea Pascarelli
ea4e3ee857 DS-3340 fix test 2016-09-26 17:29:55 +02:00
Luigi Andrea Pascarelli
1c4089c6b2 DS-2623 backport that fix the set description in the upload file and add the possibility to setdescription on multiple files 2016-09-26 14:58:27 +02:00
Andrea Schweer
e8a06006ae [DS-3336] Properly sort collections in move item drop-down 2016-09-26 11:58:49 +13:00
Luigi Andrea Pascarelli
9e0208fa96 DS-2604 manage double check for select_change and no_license option, fix no need to reach CC WS if select_change or no_license option selected 2016-09-23 00:14:41 +02:00
Luigi Andrea Pascarelli
76d6dec743 DS-2604 revert change to i18n key, manage selected option for select_change and no_license options 2016-09-23 00:13:26 +02:00
Luigi Andrea Pascarelli
427ba190a6 DS-2604 port from XMLUI to JSPUI the approach to reach the Creative Commons service (via REST API) 2016-09-22 15:28:15 +02:00
Luigi Andrea Pascarelli
bdd4eb20dc Merge pull request #1521 from lap82/DS-3248-porting-to-5
DS-3248 backport patch to enable expand parameter
2016-09-21 17:04:43 +02:00
Luigi Andrea Pascarelli
c7cbd44330 DS-3248 backport patch to enable expand parameter 2016-09-20 16:12:29 +02:00
Luigi Andrea Pascarelli
50a4f046d4 Merge pull request #1512 from 4Science/pdfbox-1.8.12
bump up to latest minor pdfbox version
2016-09-13 12:24:16 +02:00
Andrea Bollini
b5330b7815 bump up to latest minor pdfbox version 2016-09-13 11:29:31 +02:00
Mark H. Wood
4fed285c83 [DS-3097] Bitstreams of embargoed and/or withdrawn items can be accessed by anyone 2016-09-01 12:03:57 -04:00
Tim Donohue
9390016397 Merge pull request #1497 from wilee53/DS-3294-new
Fix DS-3294
2016-08-25 12:23:36 -05:00
Tim Donohue
b3c7f0a7f1 Merge pull request #1498 from abollini/DS-2895_5-x
Ds 2895 5 x
2016-08-24 10:44:46 -05:00
Bill Tantzen
8da8431869 remove unnecessary comments. 2016-08-22 09:41:05 -05:00
Andrea Bollini
2549e643f9 DS-28DS-2895 fix issue with the canEdit method
add unit test for the new isInProgressSubmission method
move the updateLastModified call after the actual change of the policies to avoid authorization exception on item and make the code more consistent
2016-08-20 11:19:25 +02:00
Andrea Bollini
ac0721767b DS-2895 add unit test to expose the wrong behaviour 2016-08-20 11:13:07 +02:00
Bill Tantzen
679c971ec3 replaced call to Boolean.getBoolean() (always returns false) with Boolean.valueOf() 2016-08-19 13:10:16 -05:00
Tim Donohue
b50d35d3f3 Merge pull request #1465 from tdonohue/DS-3266-and-DS-3140
Backporting of DS-3266 and DS-3140 for 5.x. Fix AIP Restore logic and add Integration Tests
2016-08-17 12:38:08 -05:00
Bruno Nocera Zanette
d6412e9af3 Fix: Bitstream's retrieval's response without filename
This adds bitstreams's filename to retrieval's response, and it fixes the bug that all bitstreams are downloaded using the same filename ("retrieve").
2016-08-15 14:59:00 +02:00
helix84
067c1b1a95 Merge pull request #1229 from cjuergen/DS-2968
DS-2968 5.x EPerson selection list sorting
2016-08-11 16:35:58 +02:00
oooriii
20026af124 DS-3206 Policy form merge field values when perform group search 2016-08-11 10:54:28 +02:00
Tim Donohue
b3f9ea0eaa AIP Integration Test stability improvements. Make sure tests use separate temp directories for AIPs, better NPE handling for AIP parsing. 2016-08-09 13:39:40 -05:00
Tim Donohue
987a16d23f Backport to 5.x: Fix ITDSpaceAIP to no longer re-use AIPs between tests. Ensure all tests are standalone. 2016-08-09 11:32:03 -05:00
Tim Donohue
43d44aa0cc Backport to 5.x: Fix AIP restoration of item with no policies attached. Add Integration Test to prove. 2016-08-09 11:20:54 -05:00
Tim Donohue
307d577b35 Backporting of DS-3266 and DS-3140 for 5.x. Also backports the integration tests to validate code is working 2016-07-18 13:01:50 -05:00
Hardy Pottinger
04c60ba939 [DS-3217] modified DCDateTest and InstallItemTest to use Calendar instead of Date for getting a date value for testing, explicitly set the timezone of the new calendar object to UTC, thanks to LuizClaudioSantos and Helix84 for the hints 2016-07-13 11:03:44 -05:00
Hardy Pottinger
462360ed4d [DS-3217] trying the suggestion from LuizClaudioSantos, use Calendar and not Date 2016-07-13 10:58:46 -05:00
Hardy Pottinger
c6fda557f7 [DS-3250] applying patch provided by Atmire 2016-07-06 16:16:38 -05:00
Tim Donohue
e73f83f7a4 Merge pull request #1438 from aschweer/DS-3246-cocoon-recycling-ds5
[DS-3246] Improve cleanup in recyclable components
2016-06-29 14:40:55 -05:00
Andrea Schweer
9f0f5940e7 [DS-3246] Improve cleanup in recyclable components 2016-06-15 14:33:35 +01:00
Mark H. Wood
88ed833e2c Merge pull request #1017 from bram-atmire/dspace-5_x
[DS-2702] Cannot send email using SSL (5.x branch)
2016-04-06 12:36:14 -04:00
Ivan Masár
91d4081b03 DS-2874 make XSD enforce missing Description element 2016-04-01 17:15:35 +02:00
Tim Donohue
d9e986d669 [maven-release-plugin] prepare for next development iteration 2016-03-18 15:32:25 -05:00
Tim Donohue
132f37a10a [maven-release-plugin] prepare release dspace-5.5 2016-03-18 15:32:20 -05:00
Mark H. Wood
98a26fa3e7 [DS-3094] Apply attached patch 2016-03-18 14:11:53 -04:00
Ivan Masár
4f5f5acdbe DS-3085 fix style in Mirage 2016-02-29 16:17:17 +01:00
AmberPoo1
212011cc75 Correct Sherpa/Romeo ungraded journal (gray) error message
https://jira.duraspace.org/browse/DS-3085

Resolved: DSpace DS-3085 (Ticket in the Space Issue Tracker),
Sherpa/Romeo ungraded journal (gray) shows error
2016-02-29 16:17:14 +01:00
Andrea Bollini
e7b49d8310 Merge pull request #1303 from abollini/dspace-5_x
DS-3063 Add missing license headers
2016-02-16 11:58:25 +01:00
Andrea Bollini
a70f0bdd22 DS-3063 Add missing license headers 2016-02-16 11:50:42 +01:00
Andrea Bollini
a84763a258 DS-3063 Ensure proper access to news files 2016-02-16 10:53:08 +01:00
Ivan Masár
5a1028a7a9 DS-2517 replace erroneous sql column with correct column
fixes previous commit
2016-02-15 15:26:38 +01:00
helix84
16b123e9df Merge pull request #1300 from DylanMeeus/dspace-5_x-sqlfix
replace erroneous sql column with correct column
2016-02-15 14:32:05 +01:00
dylan
f057ed8c07 replace erroneous sql column with correct column 2016-02-15 14:18:21 +01:00
Christian Scheible
875bb59eb0 [DS-2820] fixes XOAI Not filter 2016-02-12 00:06:59 +01:00
cjuergen
2c09aea8fd DS-3050 XOAI wrong URL encoding 2016-02-09 13:02:34 +01:00
Christian Scheible
533245c8dd [DS-2426] added possibility to use relative import in oai xslt transformers 2016-01-30 17:05:58 +01:00
AmberPoo1
875bba3add Correct dcterm "dcterms.conformsTo" in registry configuration
Resolved: DSpaceDS-2998, Incorrect metadata element
"dcterms.comformsTo" in dspace registry configuration.
Ticket in the Space Issue Tracker: DS-2998
2016-01-22 08:45:46 +01:00
Ivan Masár
55e623d1c2 fix X-Forward-For -> X-Forwarded-For in dspace.cfg 2015-12-30 09:36:43 +01:00
cjuergen
81a6d173ca Fix for DS-2968 2015-12-23 14:00:09 +01:00
helix84
3ff604742b Merge pull request #1209 from bram-atmire/DS-2936
DS-2936 REST-API /handle endpoint broken
2015-12-14 13:23:09 +01:00
Hardy Pottinger
3bfe7b8ea8 Merge pull request #1215 from bram-atmire/DS-2946-2
Adding class to ensure REST API can register itself during startup
2015-12-11 15:21:46 -05:00
Bram Luyten
ee62f9d6f0 Adding class to ensure REST API can register itself during startup 2015-12-11 00:22:16 +01:00
Bram Luyten
be35b0450b Removing problematic static context 2015-12-07 10:31:02 +01:00
Bram Luyten
8c94edc29c DS-2936 Adding breaks and context completion 2015-12-06 20:00:47 +01:00
helix84
2bf0275678 Merge pull request #1199 from TimothyXL/DS-2893
DS-2893 Mirage2: printing an item page includes the URL to the bitstreams
2015-11-30 16:43:42 +01:00
Tim Van den Langenbergh
86ca33eaa3 DS-2893
Quick fix for printing URLs.
2015-11-30 10:36:56 +01:00
Pascal-Nicolas Becker
f64d4b3367 DS-2923: Update DataCite default configuration. 2015-11-27 12:39:20 +01:00
Tim Donohue
c908997900 [maven-release-plugin] prepare for next development iteration 2015-11-09 14:33:39 -06:00
Tim Donohue
e2dd1089c9 [maven-release-plugin] prepare release dspace-5.4 2015-11-09 14:33:33 -06:00
Peter Dietz
8809150e66 Merge pull request #1116 from arnodb/rest-dto-sanity-5_x
DS-2829: Add the logo setter to the Community DTO - 5_x
2015-11-06 11:32:40 -05:00
Jonas Van Goolen
1fd2723848 Addition of spacing to fix gear icon sticking to results 2015-11-06 10:17:09 -06:00
Jonas Van Goolen
454f40b3f4 DS-2637 Retention of offset when changing the rpp
The offset which was obtained before changing the rrp is kept instead of snapping to first page

Based on the jira-ticket + comment
https://jira.duraspace.org/browse/DS-2637#comment-45376
2015-11-06 10:16:55 -06:00
Jonas Van Goolen
f05c9e794f DS-2637 Possibility for users to configure the discovery browse page on the fly
Modifications to the following files:
-searchFacetFilter.java
-browse.js
-attribute-handles.xsl
-browse.xsl
,enable the user to change the pagination through the gear icon, as was already the case for other browse pages

The was an improvement based on the following Jira ticket
https://jira.duraspace.org/browse/DS-2637
2015-11-06 10:16:41 -06:00
Ivan Masár
56fc41cac3 DS-2871 fix viewport meta tag 2015-11-06 11:05:08 -05:00
Ivan Masár
0175e5edff DS-2871 mobile theme: correct order of imports 2015-11-06 12:15:47 +01:00
Hardy Pottinger
d17886c1cd Merge pull request #1151 from tdonohue/DS-2869
DS-2869 : Refactor SolrServiceImpl to always specify a list of fields for Solr to return
2015-11-05 22:27:34 -05:00
Chris Wilper
06668c363e DS-1207 Stop throwing ResourceNotFoundException for redirects 2015-11-05 17:37:13 +00:00
Tim Donohue
4b3a07120c DS-2869: Ensure all Solr queries specify fields to return. Refactor slightly to use global constants for objId fields. Add comments to DiscoverQuery. 2015-11-05 10:37:11 -06:00
Tim Donohue
50c4a54bd6 Remove odd characters from search schema config 2015-11-05 10:36:25 -06:00
Andrea Schweer
0aabf5d780 DS-2699 Only escape colon-space, not other characters
Escaping all characters with special meaning in Solr query syntax prevents
users from doing advanced searches, including those with explicit operators
(AND/OR), range queries and NOT-type queries. The colon character quite
commonly occurs in titles of research publications, where it is typically
followed by a space. Unfortunately, it's regarded as a special character by
Solr and would normally need to be escaped when it's just part of a phrase
search (not part of a fielded search). Escaping the colon character _only_ when
it's followed by a space character still allows the user to manually enter
fielded queries (eg -fulltext:[* TO *] to find all items without fulltext). At
the same time, queries where someone pastes in a publication title containing
colon-space still "just work".
2015-11-04 18:31:07 +00:00
helix84
04ce6ff2f4 Revert "DS-1821 Internationalize the bitstream access icon alt text" 2015-11-04 16:43:03 +00:00
Peter Dietz
1f8f6241c2 fix /{collection_id}/items to properly process offset parameter 2015-11-04 11:22:21 -05:00
Peter Dietz
4a2f392ed8 Merge pull request #1122 from arnodb/DS-2831-database-connections-cleanup
DS-2831 connections cleanup and context reuse
2015-11-04 11:14:04 -05:00
Peter Dietz
fac705ec3f Merge pull request #1121 from arnodb/DS-2830-rest-authentication-safety
DS-2830 add proper synchronization in TokenHolder
2015-11-04 10:25:02 -05:00
Tim Donohue
e1263249f5 Merge pull request #1146 from tdonohue/DS-2542
DS-2542: Fix bug for day granularity (from zuki's PR#912)
2015-11-04 09:12:58 -06:00
Pascal-Nicolas Becker
553b1a72c5 Merge pull request #1145 from tdonohue/DS-2736
DS-2736 and DS-2737: Ensure all string parameters are properly escaped in results
2015-11-04 15:46:48 +01:00
Tim Donohue
6242865207 DS-2737: Escape message keys which are passed in as url params 2015-11-03 15:45:26 +00:00
Tim Donohue
59fa31641a DS-2542: Fix bug for day granularity (from zuki's PR#912) 2015-11-03 14:47:35 +00:00
Tim Donohue
58344b610f DS-2736: Ensure all string parameters are escaped in results 2015-11-02 22:26:23 +00:00
Andrea Schweer
563d90f7c4 [DS-2858] Revert "DS-2424 workaround for bug in xoai library. changed ref to red for Filter in Contexts"
This reverts commit 16b45601f1.

The workaround is no longer needed with xoai 3.2.10.x, where the parsing bug is no longer present.
2015-11-02 21:01:35 +00:00
Andrea Schweer
131555604a [DS-2865] Upgrade xoai dependency version & groupId 2015-11-02 20:26:03 +00:00
Andrea Schweer
fbde108024 Merge pull request #1049 from pmarrone/DS-2744-oai-base-url
[Ds-2744] Accept the dspace.oai.url as baseUrl for Dspace OAI
2015-11-02 22:29:36 +13:00
Andrea Schweer
2c59a9dd35 Merge pull request #1132 from tdonohue/DS-2408-5x
DS-2408: Fix ordering of listeners in web.xml to ensure Kernel always starts before DB migrations happen
2015-11-02 22:09:05 +13:00
Andrea Schweer
d307c56d07 DS-2698 Use all result info in browse page cache validity
Stepping through the code in a debugger showed that the singleEntry arrays
typically hold three entries: the metadata value in [0], the authority key (if
present) in [1] and the frequency of this metadata value in the current browse
in [2]. The validity used to take into account only [0] and [1], probably from
the old lucene browse (which didn't include frequencies).

This change ensures that the cache validity object includes all entries in the
singleEntry arrays by avoiding to pick out individual array entries.
2015-10-28 20:51:11 +00:00
Peter Dietz
1d2b954889 Merge pull request #1007 from ufal/DS-2692
DS-2692 REST-API /handle not reflecting updates
2015-10-28 15:29:11 -04:00
Tim Donohue
69cfc61167 DS-2408: Fix ordering of listeners in web.xml to ensure Kernel always starts before DB migrations. Add comments to others. 2015-10-28 15:51:01 +00:00
bill
b944ceb112 add left hand variable, 'fileDescription', to catch a value. 2015-10-28 15:32:15 +00:00
Jonas Van Goolen
9885ed851a DS-2733 Erronous string comparing fix 2015-10-28 15:25:01 +00:00
Peter Dietz
52ce1eb52b Merge pull request #1100 from akotynski/DS-2784
[DS-2784] jersey version changed to 1.19
2015-10-28 11:15:31 -04:00
Tim Donohue
deeef45943 Limit requiresIndexing() query to only returning the LAST_INDEXED_FIELD 2015-10-28 14:49:17 +00:00
Hardy Pottinger
ad21875ac8 [DS-2826] changed arrow characters for navigation to improve legibility,
increased the navigation size to be .larger
2015-10-27 17:20:05 -05:00
Arnaud de Bossoreille
4ee79a3d89 Add the logo setter to the Community DTO
That fixes potential deserialization issues.
This is covered by a test on the generated JAXB schema.
2015-10-22 22:21:23 +02:00
Arnaud de Bossoreille
c01c3af153 DS-2831 connections cleanup and context reuse 2015-10-22 17:28:41 +02:00
Arnaud de Bossoreille
f493a475fd DS-2830 add proper synchronization in TokenHolder 2015-10-22 17:02:57 +02:00
Hardy Pottinger
a3a5f562c9 [DS-2706] removing configuration for more lib folders in authority solr config (dist and contrib) to match Discovery/search solr config 2015-10-21 17:49:45 +00:00
Hardy Pottinger
3479b0a254 [DS-2706] removing more unused lib configurations from authority solr config 2015-10-21 17:49:35 +00:00
Hardy Pottinger
39289b6762 [DS-2706] removing more unused lib configurations from authority solrconfig 2015-10-21 17:49:24 +00:00
Hardy Pottinger
edf7ea6524 removed unused example lib folders from the Authority Solr config 2015-10-21 17:49:14 +00:00
Pascal-Nicolas Becker
2045fee8ab Fixes html5 file upload during workflow (if allowed by configuration). 2015-10-21 17:47:30 +00:00
Christian Scheible
bac9beaffa [DS-2813] fixed NullPointer in submission lookup if pubmed is down. 2015-10-19 13:44:11 +02:00
Mark H. Wood
569ad5f546 [DS-2502] Correct some dependencies to prevent pulling in servlet-api 2015-10-16 19:32:05 +00:00
Andrea Schweer
b465f26646 [DS-2591] Fix link to respond.min.js 2015-10-16 13:46:43 +02:00
Andrea Schweer
ad19c3aeb6 [DS-2592] Fix OpenUrl description.xml link 2015-10-16 08:09:58 +02:00
Hardy Pottinger
34c20d49ad [DS-2790] removed duplicate log4j config lines for Solr 2015-10-13 14:14:24 +00:00
aleksanderkotbury
eaa08adb62 [DS-2784] jersey version changed to 1.19 2015-10-09 16:55:13 +02:00
Peter Dietz
15f3c247bc DS-2740 Conditionally show publisher for sherpa romeo, if present 2015-10-08 09:54:17 +02:00
Brad Dewar
2a44765f39 Add dc.creator to qdc.xsl output 2015-10-07 19:41:39 +00:00
Brad Dewar
87c34f1f1c Add dc.creator to qdc.xsl output 2015-10-07 19:41:29 +00:00
Andrea Schweer
fce84880bc DS-1924 Include current locale in calculating cache key
This ensures that the value of the 'current locale' page meta element reflects locale switches made by the user.
2015-09-28 12:48:30 +02:00
Roeland Dillen
3f94c3acb4 set mail.extraproperties before obtaining session 2015-08-13 22:48:43 +02:00
Ondřej Košarko
50cb865ea2 Extend Handle from Resource and use createContext similarly to other *Resource 2015-08-06 14:48:47 +02:00
RomanticCat
a9b8d8bfbc DS-2533 : update version for Eirslett - forntend-maven-plugin 2015-08-06 09:30:12 +02:00
Mark H. Wood
600f680cd6 Make the assembly descriptor schema-valid. 2015-08-04 21:07:58 +00:00
Mark H. Wood
01d7d060d7 [DS-2694] Avoid munging more binary types during release 2015-08-04 21:07:49 +00:00
Christian Scheible
4a6663c2f4 [DS-2679] Retain ordering of authors for Google Scholar metatags. 2015-08-04 13:13:55 +02:00
Jonas Van Goolen
b3c87b2be7 DS-2672 Typos in constants in DOIIdentifierProvider 2015-08-03 14:17:54 +02:00
Kim Shepherd
ac08b6a4e3 [maven-release-plugin] prepare for next development iteration 2015-07-29 09:30:59 +00:00
Kim Shepherd
a2f5fe34eb [maven-release-plugin] prepare release dspace-5.3 2015-07-29 09:30:55 +00:00
Kim Shepherd
ace19199e5 Updates to license files for 5.3 2015-07-29 08:18:54 +00:00
Tim Donohue
6d9fa26535 Minor fix. Since addBitstream() inherits polices, we need to first remove inherited custom policies 2015-07-28 11:42:41 -05:00
Pascal-Nicolas Becker
3efe549774 DS-2358: Preserves custom policy rules during versioning 2015-07-28 11:42:31 -05:00
Andrea Schweer
734744ec4f DS-2571 Fix jumping to value in descending browse 2015-07-23 14:37:44 -05:00
rradillen
829c30bab4 change default of findAuthorizedPerformanceOptimize
it is now false
2015-07-22 19:36:04 +00:00
rradillen
83cb04ed53 move Collection policy optimization property 2015-07-22 19:35:54 +00:00
rradillen
0911d60290 [DS-2527] Disable collection authorisation enumeration optimisation
Disable collection authorisation enumeration optimisation so LDAP and Shibboleth may work out of the box.
2015-07-22 19:35:43 +00:00
Pablo Buenaposada
9bb7036857 closing more span tags
Missing closing more span tags
2015-07-22 19:24:13 +00:00
pablobuenaposada
e0368f3ade fixed dots in upper pagination 2015-07-22 19:22:59 +00:00
Tim Donohue
660217c3f9 Add a new DSpaceWithdrawnFilter in place of hardcoding in DSpaceAuthorizationFilter. Update configs, and fix bugs. 2015-07-22 19:13:28 +00:00
Tim Donohue
5f13b8cc64 Update XSL stylesheet to display "deleted" status, and correct misspellings 2015-07-22 19:13:15 +00:00
Tim Donohue
a2caabc79a Fix DS-2593 : Withdrawn items are now given a "tombstone" in OAI-PMH. Also fix Context mgmt issues & authorization code. 2015-07-22 19:13:05 +00:00
Hardy Pottinger
cb9710cda4 Merge pull request #993 from ufal/DS-2658
DS-2658: Fix wrong mapping for dc metadata in html head
2015-07-22 14:07:55 -05:00
Ondrej Kosarko
56abebaece fixes DS-2658 2015-07-17 10:13:37 +02:00
Pascal-Nicolas Becker
0310db74aa DS-2614: Ignore custom resource policies for unfinished items 2015-07-15 14:48:10 +00:00
Tim Donohue
3e1bac69df Escape special characters in JSPUI queries as well 2015-07-15 14:19:21 +00:00
Tim Donohue
ec86af5a82 Also ensure query escaped in AbstractSearch 2015-07-15 14:19:11 +00:00
Tim Donohue
79e111996b Fix DS-2602 and DS-2461 by properly escaping user entered queries 2015-07-15 14:19:00 +00:00
Tim Donohue
f4c6f2680c Revert "DS-2461 Escape some colons in queries"
This reverts commit 2575d73b2d.
2015-07-15 14:18:49 +00:00
nicolasschwab
f3487be040 DS-2603: now if the item doesn't have a primary bitstream the value of citation_pdf_url metadata will be a link to the first public bitstream according to the order established by the user. 2015-07-07 16:35:41 +00:00
Tim Donohue
87d0770974 Merge pull request #979 from bram-atmire/dspace-5_x
DS-2560 - Did you mean option missing in Mirage2 (backport to 5.x branch)
2015-07-06 17:24:13 -04:00
junwei1229
1c9fa656aa fix the oai index issue when submitter is null
when submitter is null, it will cause NPE exception, so it will stop the OAI index process. eg. if using harvest, the submitter probably will be null in db.
2015-07-06 21:04:22 +00:00
cjuergen
59ff964f4f Fix for DS-2543 cleans the cached OAI responses after doing a full item import with the -c option 2015-07-06 15:42:00 +00:00
Hardy Pottinger
10c4661885 Merge pull request #955 from Mini-Pillai/DS-2560
DS 2560 - Did you mean option missing in Mirage2
2015-06-30 08:46:48 +02:00
Ivan Masár
afe9c1294f test DSpace build on Travis container infrastructure 2015-06-23 13:45:00 +00:00
Bram Luyten
7a54972ed1 Merge pull request #965 from ufal/DS-2620
DS-2620 typo in the word cocoon
2015-06-20 14:33:00 +02:00
Ondrej Kosarko
b2cb0ef4dd typo in the word cocoon 2015-06-18 10:02:07 +02:00
Àlex Magaz Graça
5edf641d6c DS-2594 Long file names overlap the second column of item metadata in Mirage 2 2015-06-16 14:48:14 +02:00
Roeland Dillen
d9b14a86f0 DS-2618: Process mail.server.disabled in test-email 2015-06-16 14:43:21 +02:00
Andrea Schweer
7b8fa49632 DS-2598 Correct XPATH for available date in mets format xoai
This ensures that dc.date.available is shown when using the mets metadata
format in OAI-PMH. Previously, the dateAvailable element was present but empty.
2015-06-02 15:33:36 +02:00
Mark H. Wood
b5540d5999 Merge pull request #951 from mwoodiupui/DS-2590
[DS-2590] Fix multiple issues with distributed archives.
2015-05-26 12:29:19 -04:00
Mark H. Wood
494ff0c4c1 [DS-2590] Improved commentary about these obscure problems. 2015-05-26 12:14:58 -04:00
Mark H. Wood
1c4c8943a9 [DS-2590] Roll back problematic upgrade of maven-assembly-plugin 2015-05-26 11:53:57 -04:00
Mark H. Wood
5cd56fb834 [DS-2590] Fix multiple issues with distributed archives.
Include dspace/modules/*/src/main/webapps so build succeeds.
Avoid damaging a sample ZIP archive by munging "line endings".
Upgrade to maven-assembly-plugin 2.5.4 (which uncovered the line
ending problem).
2015-05-22 14:45:34 -04:00
Ondřej Košarko
ed89d6b00e DS-2587 Resource policies rptype is null after upgrading 2015-05-21 17:18:46 +02:00
Hardy Pottinger
19b28f4734 [maven-release-plugin] prepare for next development iteration 2015-05-20 11:42:40 -05:00
Hardy Pottinger
4a8fdf6843 [maven-release-plugin] prepare release dspace-5.2 2015-05-20 11:42:37 -05:00
Tim Donohue
d040b9dd4e Fix DS-2582: Remove all milliseconds from dates. Refactor code slightly. 2015-05-19 14:01:32 -05:00
Ondřej Košarko
4036bf781a DS-2020 null check & turning _ to / in handles 2015-05-18 11:34:55 -05:00
Antoine Snyers
d011e24f74 DS-2529 CSV import bugfix for fields under authority control with a language 2015-05-18 11:07:57 -05:00
Tim Donohue
0e9f78e9df Fix for DS-2577. Query for PostgreSQL constraint name. Surround with double quotes if value is $1 or similar. 2015-05-15 18:18:27 +00:00
Christian Scheible
254097b2e2 [DS-2546] added missing curly brackets 2015-05-15 18:01:52 +00:00
Christian Scheible
8049cef23b [DS-2546] Added missing ZULU time zones where applicable 2015-05-15 18:01:43 +00:00
Christian Scheible
de842dbf30 [DS-2546] fixes problem in DateUtils parsing 2015-05-15 18:01:33 +00:00
Ivan Masár
8bcac58154 minor fix: remove extra colon in string 2015-05-15 10:07:21 +02:00
Àlex Magaz Graça
511b78277f [DS-2186] Request item copy doesn't always use RequestItemAuthorExtractor 2015-05-15 16:37:18 +12:00
KevinVdV
dbd019943a [DS-2131] SWORDv2 ingestion fails with NullPointerException when replacing a non archived item 2015-05-15 15:07:57 +12:00
Pascal-Nicolas Becker
7d8a9d5636 DS-1965: Adds date fields to the form used to edit policies (JSPUI). 2015-05-15 10:30:36 +12:00
ctu-developers
2ab6b10a03 Removed unnecessary changes from previous commit. 2015-05-14 16:42:45 -05:00
ctu-developers
cd7789e8df Fix of getLink() by returning servlet context.
Added static method to Resource.java and using it in DSpaceObject.java
2015-05-14 16:42:35 -05:00
Ivo Prajer
9287aa891f Quick fix of getLink() 2015-05-14 16:42:22 -05:00
Pascal-Nicolas Becker
a99203382c DS-2551: JSPUI show thumbnails only if user has read permission 2015-05-14 16:32:21 -05:00
tmtvl
6ec649df78 DS-2562, fix incorrect if statement. 2015-05-14 21:22:29 +00:00
Mark H. Wood
e9f4e4c2cc [DS-2379] Lists returned by JDOM can't be sort()ed, so use a more cooperative class. 2015-05-14 13:40:50 -04:00
Mark H. Wood
18cc6bb3ff [DS-2379] Sort the list of commands by their names 2015-05-14 13:40:50 -04:00
ctu-developers
8094d8fe18 DS-2511: Repaired resource policy endpoints
Repaired all endpoints in REST api.
Added XML annotation in ResourcePolicy.
Repaired bug in Bitstream with expand field.
Repaired creating ResourcePolicy with bitstream.
2015-05-14 16:21:28 +02:00
Andrea Schweer
b7a469d53c DS-2575 Ensure pooled/owned workflow task are listed in fixed order 2015-05-14 15:40:52 +12:00
Andrea Schweer
f168c6c33d DS-2461 Escape some colons in queries
This allows searching for titles with colons while still allowing fielded searches
2015-05-14 11:13:37 +12:00
Pascal-Nicolas Becker
981b62d9e9 DS-2545: Show collections the user can submits items to only.
The JSPSelectColletionStep and JSPStartSubmissionLookupStep already set
the collections -the user can submit to- as request attribute. The JSPs
us these argument already. This commit lets the SelectCollectionTag use
this attribute too instead of looking for the collections on itself.
2015-05-13 17:10:09 -05:00
Andrea Schweer
2c42d71a6a DS-2544 Delete temp files when exception is encountered
As suggested by William Tantzen on Jira.
2015-05-14 08:48:52 +12:00
Andrea Schweer
ca6bc57c6d [DS-2544] Improve temp file handling for IM thumbnailer 2015-05-14 08:48:52 +12:00
Andrea Schweer
0f0be17d0a [DS-2549] Render Repo identifier / Sample identifier on Identify page 2015-05-14 08:44:06 +12:00
Panagiotis Koutsourakis
5e5a7922d0 Fix a bug in the "Jump to" browse feature
When computing the offset for the "jump to" feature at
SolrBrowseDAO.doOffsetQuery we should take into account if we are
browsing a subset of the items (e.g. we are viewing the items that have
a specific subject) and not all of them (e.g. by title).
2015-05-13 15:42:07 -05:00
Andrea Schweer
bb4cb39373 Remove box styling for file upload in Mirage 2 2015-05-14 08:39:24 +12:00
Andrea Schweer
a257f516fa DS-2449 Restore template item label for Mirage 2 2015-05-14 08:39:24 +12:00
Andrea Schweer
9d8284d85f [DS-2212] Ignore _version_ field when sharding solr stats 2015-05-13 15:13:35 -05:00
Christian Scheible
57efa4f628 [DS-2423] Added oai overlays to classpath to ensure that oai command line tools work (like clean-cache) 2015-05-06 18:49:56 +02:00
Christian Scheible
5b5f44085a [DS-2423] changed arcitecture of DSpace filters. Removed need for @Autowire because filters are not handled by spring. 2015-05-06 18:49:56 +02:00
Christian Scheible
46ce2741bc [DS-2423] changed tests for OAI-interface to autowire the Filters. 2015-05-06 18:49:56 +02:00
Christian Scheible
0b799fc882 [DS-2423] Added possibility to create additional Filter for DSpace OAI-PMH interface 2015-05-06 18:49:56 +02:00
Andrea Schweer
04b57a60b3 [DS-2486] Increase robustness, improve directory delete behaviour
As suggested by Mark Wood, delete directories only when they were actually
created (and when --keep is not given).

Also refuse to go ahead with reindexing when it's obvious that there won't be
enough space, plus deal a little more gracefully with common errors (initial
export failing; -temp core still left from previous attempt).
2015-05-01 12:02:04 -05:00
Andrea Schweer
02b4314046 Disable version check when importing temporary stats data 2015-05-01 12:01:48 -05:00
Andrea Schweer
3d79fa76ab Make import/export of temporary core more robust 2015-05-01 12:01:33 -05:00
Andrea Schweer
ca1803ae93 Use stats component to get minimum date 2015-05-01 12:01:21 -05:00
Andrea Schweer
9046ec21d4 Export monthly batches to limit the number of docs to sort 2015-05-01 12:01:06 -05:00
Andrea Schweer
b30654e3d5 DS-2486 Add Solr import/export to launcher.xml 2015-05-01 12:00:53 -05:00
Andrea Schweer
ee19e11e6d DS-2486 New scripts to export/clear/import solr indexes 2015-05-01 12:00:34 -05:00
Andrea Schweer
a990c97959 DS-2486 Add UUID processing to CSV, JSON update handlers too 2015-05-01 12:00:18 -05:00
Pascal-Nicolas Becker
56816b13ba Merge pull request #926 from tuub/DS-2550-dspace-5_x
DS-2550: fix ImageMagick/Ghostscript problems with transparent pdfs
2015-04-27 14:30:25 +02:00
Pascal-Nicolas Becker
b414aaa195 DS-2550: fix ImageMagick/Ghostscript problems with transparent pdfs 2015-04-27 14:24:00 +02:00
Ivo Prajer
1a1ae35ec9 DS-2218: Unable to use command "update-handle-prefix"
* Removed extra semicolon in the sql command
* added check for "up-to-date"
* fix updating metadata values
* basic logging to DSpace log and SQL exception handling
* Changed, customized, added user message and repaired their order.
* Fixed return codes and some typos.
* Changed re-index engine from DSIndexer to Discovery and info text about manual re-indexing.
* Changes in SQL formatting and formatting of code.
2015-04-22 11:28:46 +02:00
Ivo Prajer
1029f393e4 Fix passing parameters LIMIT and OFFSET to sql query in the method getItems() for oracle 2015-04-20 10:47:22 +02:00
Ivo Prajer
c1039dfe26 Fix passing parameters LIMIT/OFFSET to sql query in the findAll() 2015-04-20 10:47:11 +02:00
Ivan Masár
cc96646e37 DS-2474 METS format in OAI includes only the first author 2015-04-20 09:44:17 +02:00
Ivan Masár
d2ad7c81de DS-2491 set deletedRecord=transient in OAI Identify 2015-04-20 09:12:45 +02:00
Bram Luyten
00e9c1131f DS-2531 New entries for the robots hostname list 2015-04-20 09:09:37 +02:00
Chris Wilper
77cc9abe49 fix year and capitalization in displayed copyright 2015-04-16 20:28:45 +02:00
Mark H. Wood
91018bfe0f Merge pull request #909 from mwoodiupui/DS-2518-5x
[DS-2518] EZID DOI IdentityProvider doesn't set the location in metadata
2015-04-08 12:53:55 -04:00
Mark H. Wood
7f9bcb283f Repair testing environment, enable real unit tests, add test of metadata crosswalking. 2015-04-08 11:49:35 -04:00
Mark H. Wood
ae11c1c795 Add location metadata so that the DOI actually resolves properly. 2015-04-08 11:49:35 -04:00
cjuergen
9cd5fa596b Fix for DS-2482 adds the attribute dspace.community or dspace.collection to the search and browse request if we browse or search a community or collection 2015-04-08 17:24:02 +02:00
rradillen
e10b10224a [DS-2532] botness of a visit is not properly logged when a location cannot be determined
Extract isBot from the location==null if in two places.
2015-04-02 08:52:03 +02:00
Pascal-Nicolas Becker
e08886ae09 Merge pull request #898 from tuub/DS-2403-dspace-5_x
DS-2403: Resolves DS-2403 and reduce logging of RDFConsumer.
2015-03-25 19:42:30 +01:00
Pascal-Nicolas Becker
df3ffcf7f9 DS-2403: Resolves DS-2403 and reduce logging of RDFConsumer. 2015-03-25 19:14:20 +01:00
Andrea Schweer
0c77f7be91 [DS-2513] Improve multipart header parsing
The original code broke when files were uploaded whose name contains
the semicolon-space sequence.
2015-03-18 10:53:07 +01:00
David Cook
cdc8e3144e DS-2514 Packaged version of html5shiv.js is missing "main" element
Added "main" element to html5shiv.js, which should bring it inline
with the 3.6.2pre distribution from aFarkas's Github repo:
https://raw.githubusercontent.com/aFarkas/html5shiv/
3.6.2pre/dist/html5shiv.js

This can be verified by unminifying html5shiv.js in the above link
and html5shiv.js in DSpace master, and comparing them in any merge
program like vimdiff or WinMerge.

Without this patch, IE 8 self-closes the "main" element, and pushes
its child DIVs after it instead of nesting them within itself, which
has repercussions when styling the JSPUI with CSS.

With this patch, IE 8 comprehends the "main" element, and nests the
DIVs correctly.
2015-03-18 10:19:16 +01:00
Ivan Masár
92847079d7 Updated README.md 2015-03-16 18:59:08 +01:00
Ivan Masár
b023c36941 Updated README.md 2015-03-16 15:19:01 +01:00
ctu-developers
aee3b0b710 Updated README.md 2015-03-16 15:18:55 +01:00
Christian Scheible
d0c8afb601 DS-2424 workaround for bug in xoai library. changed ref to red for Filter in Contexts 2015-03-11 10:50:22 -05:00
Ivan Masár
e9c14bbcea DS-2501 fix SQL in REST /items/find-by-metadata-field 2015-03-09 22:17:14 +01:00
Àlex Magaz Graça
2eca19daa3 [DS-2493] "View more" link is shown even when there aren't more items. 2015-03-06 13:54:03 +01:00
Tim Donohue
bcc7a75baa DS-2483 : Fix mispelling of "sword.compatibility"
https://jira.duraspace.org/browse/DS-2483
2015-03-05 21:32:42 +00:00
Tim Donohue
19222e9341 DS-2477 : Ensure distribution packages alwasy get created with Unix (LF) line endings 2015-02-27 17:48:12 +01:00
Tim Donohue
8124a61738 [maven-release-plugin] prepare for next development iteration 2015-02-25 12:27:33 -06:00
Tim Donohue
09007146d0 [maven-release-plugin] prepare release dspace-5.1 2015-02-25 12:27:24 -06:00
Tim Donohue
e715c64404 Updates to LICENSES_THIRD_PARTY for 5.1 2015-02-25 11:54:42 -06:00
Luigi Andrea Pascarelli
53ff4510ac [DS-2044] fix cross-site scripting vulnerability and minor related issue
(verbose error output, avoid NPE on JSP during an attack)
2015-02-23 20:27:43 +00:00
Tim Donohue
495031001d DS-2278 : Fix two issues in XMLUI which block proper 404 Page Not Found pages from displaying for some URL patterns 2015-02-23 12:48:21 -06:00
Mark H. Wood
97e89384f1 Don't close the current sitemap if we never opened one 2015-02-22 15:43:01 -06:00
cjuergen
72913cda76 Fix for DS-2419 JSP UI ignores authorization.admin.usage. Just an incomplete name for the configuration parameter which determines the accessibility of usage statistics. 2015-02-22 15:42:31 -06:00
Tim Donohue
03097aaa35 DS-2448 - Fix for JSPUI path traversal issue from Pascal-Nicolas Becker 2015-02-20 22:38:42 +00:00
Tim Donohue
f6d3f67b52 Add in missing imports from previous commit 2015-02-20 20:20:26 +00:00
Luigi Andrea Pascarelli
62e0ac462e DS-1702 add code to prevent XSS attach on recent submission 2015-02-20 19:07:17 +00:00
Bill Tantzen
54310b014b fixed formatting 2015-02-20 12:30:14 -06:00
Bill Tantzen
beaf54f624 added synchroniztion for ArrayLists: agents and domains 2015-02-20 12:30:03 -06:00
Tim Donohue
114f1e0985 XMLUI path bug fixes and security fixes for DS-2445 DS-2130 DS-1896 2015-02-20 17:31:30 +00:00
Hardy Pottinger
1fdfe05c4c clarified the test expression, as a kindness to future generations 2015-02-17 14:45:42 -06:00
Hardy Pottinger
9c1f91d40b added back null handling, which I inadevertently dropped in favor of emptystring handling 2015-02-17 14:45:31 -06:00
Hardy Pottinger
39711b332f [DS-2034] refactored notnull method to notempty, at the suggestion of mhwood 2015-02-17 14:45:19 -06:00
Hardy Pottinger
6cfda147b4 [DS-2034] added emptystring handling to the notnull method in ControlPanel.java 2015-02-17 14:45:09 -06:00
Tim Donohue
eabdc610a0 Merge pull request #857 from tdonohue/DS-2427
Fix DS-2427 for 5.1 by consolidating problematic schema code into DatabaseUtils...
2015-02-11 15:51:25 -06:00
Tim Donohue
da74f5aa7e Add back in missing "canonicalize()" for Oracle 2015-02-04 10:58:11 -06:00
Tim Donohue
14c575a7c4 Fix DS-2427 for 5.1 by consolidating problematic code into DatabaseUtils.getSchemaName() so that it can be replaced easily in future. Also cleaned up config comments 2015-02-04 10:44:26 -06:00
Christian Scheible
d8c8d28c13 [DS-2438] fixed problem with immense metadata values for oai solr core 2015-02-04 10:05:50 +01:00
Pascal-Nicolas Becker
bf56f1f7e3 DS-640: Fixes Internal System Error if browse index is missing in JSPUI. 2015-02-03 15:29:21 +01:00
Pascal-Nicolas Becker
8046d154ee DS-2435: JSPUI send 400 Bad Request for unexisting browse index. 2015-02-03 15:29:13 +01:00
ctu-developers
589117e204 Add canonicalize for "db.schema" property
DS-2201: Unable to complete installation of DSpace with non-empty variable "db.schema" configuration file "build.properties"
2015-01-28 11:20:19 -06:00
Christian Scheible
e9e5423f97 [DS-2425] fixed typos in xoai.xml 2015-01-27 11:45:44 +01:00
Ondřej Košarko
c08f447cec ResumptionToken link for other verbs 2015-01-20 16:37:54 +01:00
Ivan Masár
cf25175155 [maven-release-plugin] prepare for next development iteration 2015-01-20 15:27:37 +01:00
3812 changed files with 429873 additions and 204990 deletions

6
.dockerignore Normal file
View File

@@ -0,0 +1,6 @@
.git/
.idea/
.settings/
*/target/
dspace/modules/*/target/
Dockerfile.*

6
.gitattributes vendored
View File

@@ -1,6 +1,12 @@
# Auto detect text files and perform LF normalization
* text=auto
# Ensure Unix files always keep Unix line endings
*.sh text eol=lf
# Ensure Windows files always keep Windows line endings
*.bat text eol=crlf
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain

84
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,84 @@
# DSpace 5.x Continuous Integration/Build via GitHub Actions
# Concepts borrowed from
# https://docs.github.com/en/free-pro-team@latest/actions/guides/building-and-testing-java-with-maven
name: Build
# Run this Build for all pushes / PRs to current branch
on: [push, pull_request]
jobs:
tests:
runs-on: ubuntu-18.04
env:
# Give Maven 1GB of memory to work with
# Suppress all Maven "downloading" messages in Travis logs (see https://stackoverflow.com/a/35653426)
# This also slightly speeds builds, as there is less logging
MAVEN_OPTS: "-Xmx1024M -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
# These are the actual CI steps to perform per job
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v1
# https://github.com/actions/setup-java
- name: Install JDK 8
uses: actions/setup-java@v1
with:
java-version: 8
# https://github.com/actions/setup-ruby
- name: Install Ruby v2.4 (for Mirage 2)
uses: actions/setup-ruby@v1
with:
ruby-version: 2.4
- name: Install Node.js v6.5 (for Mirage 2)
shell: bash -l {0}
run: nvm install 6.5.0
# Install prerequisites for building Mirage2 more rapidly
# Includes NPM, Bower, Grunt, Ruby, Sass, Compass
# These versions should be kept in sync with ./dspace/modules/xml-mirage2/pom.xml
- name: Install Mirage 2 prerequisites
run: |
sudo npm install -g npm@3.10.8
npm --version
sudo npm install -g bower
sudo npm install -g grunt && sudo npm install -g grunt-cli
grunt --version
gem install sass -v 3.4.25
sass -v
gem install compass -v 1.0.1
compass version
gem env
# https://github.com/actions/cache
- name: Cache Maven dependencies
uses: actions/cache@v2
with:
# Cache entire ~/.m2/repository
path: ~/.m2/repository
# Cache key is hash of all pom.xml files. Therefore any changes to POMs will invalidate cache
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
# [Build & Unit Test] Check source code licenses and run source code Unit Tests
# license:check => Validate all source code license headers
# -Dmaven.test.skip=false => Enable DSpace Unit Tests
# -DskipITs=false => Enable DSpace Integration Tests
# -P !assembly => Skip normal assembly (as it can be memory intensive)
# -B => Maven batch/non-interactive mode (recommended for CI)
# -V => Display Maven version info before build
# -Dsurefire.rerunFailingTestsCount=2 => try again for flaky tests, and keep track of/report on number of retries
- name: Run Maven Build & Test
run: mvn clean install license:check -Dmaven.test.skip=false -DskipITs=false -P !assembly -B -V -Dsurefire.rerunFailingTestsCount=2
# [Assemble DSpace] Ensure assembly process works (from [src]/dspace/), including Mirage 2
# -Dmirage2.on=true => Build Mirage2
# -Dmirage2.deps.included=false => Don't include Mirage2 build dependencies (we installed them above)
# -P !assembly => SKIP the actual building of [src]/dspace/dspace-installer (as it can be memory intensive)
- name: Assemble DSpace & Build Mirage 2
run: cd dspace && mvn package -Dmirage2.on=true -Dmirage2.deps.included=false -P !assembly -B -V -Dsurefire.rerunFailingTestsCount=2
env:
# Set GEM env variables (for Mirage 2) based on output of 'gem env' in "Install Mirage 2 prerequisites" step
GEM_HOME: "/home/runner/.gem/ruby/2.4.0"
GEM_PATH: "/home/runner/.gem/ruby/2.4.0:/opt/hostedtoolcache/Ruby/2.4.10/x64/lib/ruby/gems/2.4.0"

14
.gitignore vendored
View File

@@ -1,15 +1,11 @@
## Ignore the MVN compiled output directories from version tracking
target/
## Ignore tags index files created by Exuberant Ctags
tags
## Ignore project files created by Eclipse
.settings/
/bin/
.project
.classpath
.checkstyle
## Ignore project files created by IntelliJ IDEA
*.iml
@@ -26,19 +22,11 @@ dist/
nbdist/
nbactions.xml
nb-configuration.xml
META-INF/
## Ignore all *.properties file in root folder, EXCEPT build.properties (the default)
## KEPT FOR BACKWARDS COMPATIBILITY WITH 5.x (build.properties is now replaced with local.cfg)
/*.properties
!/build.properties
# Ignore a local.cfg file in root folder, if it exists
/local.cfg
# Also ignore it under dspace/config
/dspace/config/local.cfg
##Mac noise
.DS_Store
##Ignore JRebel project configuration
rebel.xml

View File

@@ -1,44 +0,0 @@
language: java
sudo: false
env:
# Give Maven 1GB of memory to work with
- MAVEN_OPTS=-Xmx1024M
jdk:
# DS-3384 Oracle JDK 8 has DocLint enabled by default.
# Let's use this to catch any newly introduced DocLint issues.
- oraclejdk8
## Should we run into any problems with oraclejdk8 on Travis, we may try the following workaround.
## https://docs.travis-ci.com/user/languages/java#Testing-Against-Multiple-JDKs
## https://github.com/travis-ci/travis-ci/issues/3259#issuecomment-130860338
#addons:
# apt:
# packages:
# - oracle-java8-installer
# Install prerequisites for building Mirage2 more rapidly
before_install:
# Remove outdated settings.xml from Travis builds. Workaround for https://github.com/travis-ci/travis-ci/issues/4629
- rm ~/.m2/settings.xml
# Skip install stage, as we'll do it below
install: "echo 'Skipping install stage, dependencies will be downloaded during build and test stages.'"
# Two stage Build and Test
# 1. Install & Unit Test APIs
# 2. Assemble DSpace
script:
# 1. [Install & Unit Test] Check source code licenses and run source code Unit Tests
# license:check => Validate all source code license headers
# -Dmaven.test.skip=false => Enable DSpace Unit Tests
# -DskipITs=false => Enable DSpace Integration Tests
# -P !assembly => Skip normal assembly (as it can be memory intensive)
# -B => Maven batch/non-interactive mode (recommended for CI)
# -V => Display Maven version info before build
# -Dsurefire.rerunFailingTestsCount=2 => try again for flakey tests, and keep track of/report on number of retries
- "mvn clean install license:check -Dmaven.test.skip=false -DskipITs=false -P !assembly -B -V -Dsurefire.rerunFailingTestsCount=2"
# 2. [Assemble DSpace] Ensure overlay & assembly process works (from [src]/dspace/)
# -P !assembly => SKIP the actual building of [src]/dspace/dspace-installer (as it can be memory intensive)
- "cd dspace && mvn package -P !assembly -B -V -Dsurefire.rerunFailingTestsCount=2"

60
Dockerfile.cli.jdk8 Normal file
View File

@@ -0,0 +1,60 @@
# This image will be published as dspace/dspace
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
#
# This version is JDK8 compatible
# - openjdk:8-jdk
# - ANT 1.10.7
# - maven:3-jdk-8
# - note:
# - default tag for branch: dspace/dspace-cli: dspace/dspace-cli:dspace-5_x
# Step 1 - Run Maven Build
FROM dspace/dspace-dependencies:dspace-5_x-jdk8 as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# The dspace-install directory will be written to /install
RUN mkdir /install \
&& chown -Rv dspace: /install
USER dspace
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
COPY --chown=dspace dspace/src/main/docker/build.properties /app/build.properties
# Build DSpace. Copy the dspace-install directory to /install. Clean up the build to keep the docker image small
RUN mvn package -P'!dspace-solr,!dspace-jspui,!dspace-xmlui,!dspace-rest,!dspace-xmlui-mirage2,!dspace-rdf,!dspace-sword,!dspace-swordv2' && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
FROM openjdk:8-jdk as ant_build
ARG TARGET_DIR=dspace-installer
COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.7
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
RUN mkdir $ANT_HOME && \
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
RUN ant init_installation update_configs update_code
# Step 3 - Run jdk
# Create a new jdk image that does not retain the the build directory contents
FROM openjdk:8-jdk
ENV DSPACE_INSTALL=/dspace
COPY --from=ant_build /dspace $DSPACE_INSTALL
ENV JAVA_OPTS=-Xmx1000m
# This script is used to parse environment variables to configs in dspace.cfg
# It is not executed in this Docker file, so it's up to docker-compose to call it.
COPY dspace/src/main/docker/parse_env_to_configs.sh $DSPACE_INSTALL/bin/parse_env_to_configs.sh
# Ensure all scripts are executable
RUN chmod +x $DSPACE_INSTALL/bin/*

View File

@@ -0,0 +1,24 @@
# This image will be published as dspace/dspace-dependencies:dspace-5_x-jdk7
# The purpose of this image is to make the build for dspace/dspace run faster
# Step 1 - Run Maven Build
FROM maven:3-jdk-7 as build
WORKDIR /app
# The Mirage2 build cannot run as root. Setting the user to dspace.
RUN useradd dspace \
&& mkdir /home/dspace /app/target \
&& chown -Rv dspace: /home/dspace /app /app/target
USER dspace
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
COPY --chown=dspace dspace/src/main/docker/build.properties /app/build.properties
# Trigger the installation of all maven dependencies including the Mirage2 dependencies
# Clean up the built artifacts in the same step to keep the docker image small
RUN mvn package -Dmirage2.on=true && cd /app && mvn clean
# Clear the contents of the /app directory so no artifacts are left when dspace:dspace is built
USER root
RUN rm -rf /app/*

View File

@@ -0,0 +1,24 @@
# This image will be published as dspace/dspace-dependencies:dspace-5_x-jdk8
# The purpose of this image is to make the build for dspace/dspace run faster
# Step 1 - Run Maven Build
FROM maven:3-jdk-8 as build
WORKDIR /app
# The Mirage2 build cannot run as root. Setting the user to dspace.
RUN useradd dspace \
&& mkdir /home/dspace /app/target \
&& chown -Rv dspace: /home/dspace /app /app/target
USER dspace
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
COPY dspace/src/main/docker/build.properties /app/build.properties
# Trigger the installation of all maven dependencies including the Mirage2 dependencies
# Clean up the built artifacts in the same step to keep the docker image small
RUN mvn package -Dmirage2.on=true && mvn clean
# Clear the contents of the /app directory so no artifacts are left when dspace:dspace is built
USER root
RUN rm -rf /app/*

63
Dockerfile.jdk7 Normal file
View File

@@ -0,0 +1,63 @@
# This image will be published as dspace/dspace
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
#
# This version is JDK7 compatible
# - tomcat:7-jre7
# - ANT 1.9.14
# - maven:3-jdk-7
# - note:
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-5_x-jdk7
# Step 1 - Run Maven Build
FROM dspace/dspace-dependencies:dspace-5_x-jdk7 as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# The dspace-install directory will be written to /install
RUN mkdir /install \
&& chown -Rv dspace: /install
USER dspace
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
COPY --chown=dspace dspace/src/main/docker/build.properties /app/build.properties
# Build DSpace. Copy the dspace-install directory to /install. Clean up the build to keep the docker image small
RUN mvn package -Dmirage2.on=true && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
FROM tomcat:7-jre7 as ant_build
ARG TARGET_DIR=dspace-installer
COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.9.14
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
RUN mkdir $ANT_HOME && \
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
RUN ant init_installation update_configs update_code update_webapps update_solr_indexes
# Step 3 - Run tomcat
# Create a new tomcat image that does not retain the the build directory contents
FROM tomcat:7-jre7
ENV DSPACE_INSTALL=/dspace
COPY --from=ant_build /dspace $DSPACE_INSTALL
EXPOSE 8080 8009
ENV JAVA_OPTS=-Xmx2000m
RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \
ln -s $DSPACE_INSTALL/webapps/xmlui /usr/local/tomcat/webapps/xmlui && \
ln -s $DSPACE_INSTALL/webapps/jspui /usr/local/tomcat/webapps/jspui && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \
ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \
ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \
ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \
ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2

69
Dockerfile.jdk7-test Normal file
View File

@@ -0,0 +1,69 @@
# This image will be published as dspace/dspace
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
#
# This version is JDK7 compatible
# - tomcat:7-jre7
# - ANT 1.9.14
# - maven:3-jdk-7
# - note:
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-5_x-jdk7
# Step 1 - Run Maven Build
FROM dspace/dspace-dependencies:dspace-5_x-jdk7 as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# The dspace-install directory will be written to /install
RUN mkdir /install \
&& chown -Rv dspace: /install
USER dspace
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
COPY --chown=dspace dspace/src/main/docker/build.properties /app/build.properties
# Build DSpace. Copy the dspace-install directory to /install. Clean up the build to keep the docker image small
RUN mvn package -Dmirage2.on=true && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
FROM tomcat:7-jre7 as ant_build
ARG TARGET_DIR=dspace-installer
COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.9.14
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
RUN mkdir $ANT_HOME && \
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
RUN ant init_installation update_configs update_code update_webapps update_solr_indexes
# Step 3 - Run tomcat
# Create a new tomcat image that does not retain the the build directory contents
FROM tomcat:7-jre7
ENV DSPACE_INSTALL=/dspace
COPY --from=ant_build /dspace $DSPACE_INSTALL
EXPOSE 8080 8009
ENV JAVA_OPTS=-Xmx2000m
RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \
ln -s $DSPACE_INSTALL/webapps/xmlui /usr/local/tomcat/webapps/xmlui && \
ln -s $DSPACE_INSTALL/webapps/jspui /usr/local/tomcat/webapps/jspui && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \
ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \
ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \
ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \
ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2
COPY dspace/src/main/docker/test/solr_web.xml $DSPACE_INSTALL/webapps/solr/WEB-INF/web.xml
COPY dspace/src/main/docker/test/rest_web.xml $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml
RUN sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/solr/WEB-INF/web.xml && \
sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml

72
Dockerfile.jdk8 Normal file
View File

@@ -0,0 +1,72 @@
# This image will be published as dspace/dspace
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
#
# This version is JDK8 compatible
# - tomcat:7-jre8
# - ANT 1.10.7
# - maven:3-jdk-8
# - note:
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-5_x-jdk8
# Step 1 - Run Maven Build
FROM dspace/dspace-dependencies:dspace-5_x-jdk8 as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# The dspace-install directory will be written to /install
RUN mkdir /install \
&& chown -Rv dspace: /install
USER dspace
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
COPY --chown=dspace dspace/src/main/docker/build.properties /app/build.properties
# Build DSpace. Copy the dspace-install directory to /install. Clean up the build to keep the docker image small
RUN mvn package -Dmirage2.on=true && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
FROM tomcat:7-jre8 as ant_build
ARG TARGET_DIR=dspace-installer
COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.7
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
RUN mkdir $ANT_HOME && \
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
RUN ant init_installation update_configs update_code update_webapps update_solr_indexes
# Step 3 - Run tomcat
# Create a new tomcat image that does not retain the the build directory contents
FROM tomcat:7-jre8
ENV DSPACE_INSTALL=/dspace
COPY --from=ant_build /dspace $DSPACE_INSTALL
EXPOSE 8080 8009
ENV JAVA_OPTS=-Xmx2000m
RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \
ln -s $DSPACE_INSTALL/webapps/xmlui /usr/local/tomcat/webapps/xmlui && \
ln -s $DSPACE_INSTALL/webapps/jspui /usr/local/tomcat/webapps/jspui && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \
ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \
ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \
ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \
ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2
COPY dspace/src/main/docker/parse_env_to_configs.sh $DSPACE_INSTALL/bin/parse_env_to_configs.sh
# Ensure all scripts are executable
RUN chmod +x $DSPACE_INSTALL/bin/*
# On startup run this command to parse environment variables to configs in dspace.cfg
# Then start Tomcat
CMD ["sh", "-c", "$DSPACE_INSTALL/bin/parse_env_to_configs.sh && catalina.sh run"]

78
Dockerfile.jdk8-test Normal file
View File

@@ -0,0 +1,78 @@
# This image will be published as dspace/dspace
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
#
# This version is JDK8 compatible
# - tomcat:7-jre8
# - ANT 1.10.7
# - maven:3-jdk-8
# - note:
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-5_x-jdk8
# Step 1 - Run Maven Build
FROM dspace/dspace-dependencies:dspace-5_x-jdk8 as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# The dspace-install directory will be written to /install
RUN mkdir /install \
&& chown -Rv dspace: /install
USER dspace
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
COPY --chown=dspace dspace/src/main/docker/build.properties /app/build.properties
# Build DSpace. Copy the dspace-install directory to /install. Clean up the build to keep the docker image small
RUN mvn package -Dmirage2.on=true && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
FROM tomcat:7-jre8 as ant_build
ARG TARGET_DIR=dspace-installer
COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.7
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
RUN mkdir $ANT_HOME && \
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
RUN ant init_installation update_configs update_code update_webapps update_solr_indexes
# Step 3 - Run tomcat
# Create a new tomcat image that does not retain the the build directory contents
FROM tomcat:7-jre8
ENV DSPACE_INSTALL=/dspace
COPY --from=ant_build /dspace $DSPACE_INSTALL
EXPOSE 8080 8009
ENV JAVA_OPTS=-Xmx2000m
RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \
ln -s $DSPACE_INSTALL/webapps/xmlui /usr/local/tomcat/webapps/xmlui && \
ln -s $DSPACE_INSTALL/webapps/jspui /usr/local/tomcat/webapps/jspui && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \
ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \
ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \
ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \
ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2
COPY dspace/src/main/docker/test/solr_web.xml $DSPACE_INSTALL/webapps/solr/WEB-INF/web.xml
COPY dspace/src/main/docker/test/rest_web.xml $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml
RUN sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/solr/WEB-INF/web.xml && \
sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml
COPY dspace/src/main/docker/parse_env_to_configs.sh $DSPACE_INSTALL/bin/parse_env_to_configs.sh
# Ensure all scripts are executable
RUN chmod +x $DSPACE_INSTALL/bin/*
# On startup run this command to parse environment variables to configs in dspace.cfg
# Then start Tomcat
CMD ["sh", "-c", "$DSPACE_INSTALL/bin/parse_env_to_configs.sh && catalina.sh run"]

23
LICENSE
View File

@@ -1,7 +1,6 @@
DSpace source code license:
BSD 3-Clause License
Copyright (c) 2002-2016, DuraSpace. All rights reserved.
Copyright (c) 2002-2022, LYRASIS. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -14,13 +13,12 @@ notice, this list of conditions and the following disclaimer.
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name DuraSpace nor the name of the DSpace Foundation
nor the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
- Neither the name of the copyright holder nor the names of its
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
"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,
@@ -30,11 +28,4 @@ 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.
DSpace uses third-party libraries which may be distributed under
different licenses to the above. Information about these licenses
is detailed in the LICENSES_THIRD_PARTY file at the root of the source
tree. You must agree to the terms of these licenses, in addition to
the above DSpace source code license, in order to use this software.
DAMAGE.

View File

@@ -1,19 +1,19 @@
DSpace uses third-party libraries which may be distributed under different
DSpace uses third-party libraries which may be distributed under different
licenses. We have listed all of these third party libraries and their licenses
below. This file can be regenerated at any time by simply running:
mvn clean verify -Dthird.party.licenses=true
You must agree to the terms of these licenses, in addition to the DSpace
You must agree to the terms of these licenses, in addition to the DSpace
source code license, in order to use this software.
---------------------------------------------------
Third party Java libraries listed by License type.
PLEASE NOTE: Some dependencies may be listed under multiple licenses if they
are dual-licensed. This is especially true of anything listed as
"GNU General Public Library" below, as DSpace actually does NOT allow for any
are dual-licensed. This is especially true of anything listed as
"GNU General Public Library" below, as DSpace actually does NOT allow for any
dependencies that are solely released under GPL terms. For more info see:
https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines
---------------------------------------------------
@@ -21,69 +21,72 @@ https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines
Apache Software License, Version 2.0:
* Ant-Contrib Tasks (ant-contrib:ant-contrib:1.0b3 - http://ant-contrib.sourceforge.net)
* Code Generation Library (cglib:cglib:2.2.2 - http://cglib.sourceforge.net/)
* Code Generation Library (cglib:cglib:3.1 - http://cglib.sourceforge.net/)
* AWS SDK for Java - Core (com.amazonaws:aws-java-sdk-core:1.10.50 - https://aws.amazon.com/sdkforjava)
* AWS Java SDK for AWS KMS (com.amazonaws:aws-java-sdk-kms:1.10.50 - https://aws.amazon.com/sdkforjava)
* AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.10.50 - https://aws.amazon.com/sdkforjava)
* HPPC Collections (com.carrotsearch:hppc:0.5.2 - http://labs.carrotsearch.com/hppc.html/hppc)
* metadata-extractor (com.drewnoakes:metadata-extractor:2.6.2 - http://code.google.com/p/metadata-extractor/)
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.5.4 - http://github.com/FasterXML/jackson)
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.7.0 - http://github.com/FasterXML/jackson)
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.5.4 - https://github.com/FasterXML/jackson)
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.7.0 - https://github.com/FasterXML/jackson-core)
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.5.4 - http://github.com/FasterXML/jackson)
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.7.0 - http://github.com/FasterXML/jackson)
* Jackson-JAXRS-base (com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:2.5.4 - http://wiki.fasterxml.com/JacksonHome/jackson-jaxrs-base)
* Jackson-JAXRS-JSON (com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.5.4 - http://wiki.fasterxml.com/JacksonHome/jackson-jaxrs-json-provider)
* Jackson-module-JAXB-annotations (com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.5.4 - http://wiki.fasterxml.com/JacksonJAXBAnnotations)
* Google APIs Client Library for Java (com.google.api-client:google-api-client:1.21.0 - https://github.com/google/google-api-java-client/google-api-client)
* Google Analytics API v3-rev123-1.21.0 (com.google.apis:google-api-services-analytics:v3-rev123-1.21.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-analytics)
* FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.1 - http://findbugs.sourceforge.net/)
* Gson (com.google.code.gson:gson:2.6.1 - https://github.com/google/gson/gson)
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.3.0 - http://wiki.fasterxml.com/JacksonHome)
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.9.3 - http://github.com/FasterXML/jackson)
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.3.3 - http://wiki.fasterxml.com/JacksonHome)
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.9.3 - https://github.com/FasterXML/jackson-core)
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.3.3 - http://wiki.fasterxml.com/JacksonHome)
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.9.3 - http://github.com/FasterXML/jackson)
* Google APIs Client Library for Java (com.google.api-client:google-api-client:1.19.1 - http://code.google.com/p/google-api-java-client/google-api-client/)
* Google Analytics API v3-rev103-1.19.0 (com.google.apis:google-api-services-analytics:v3-rev103-1.19.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-analytics)
* FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.0 - http://findbugs.sourceforge.net/)
* Gson (com.google.code.gson:gson:2.2.1 - http://code.google.com/p/google-gson/)
* Guava: Google Core Libraries for Java (com.google.guava:guava:13.0 - http://code.google.com/p/guava-libraries/guava)
* Guava: Google Core Libraries for Java (com.google.guava:guava:14.0.1 - http://code.google.com/p/guava-libraries/guava)
* Guava: Google Core Libraries for Java (com.google.guava:guava:19.0 - https://github.com/google/guava/guava)
* Guava: Google Core Libraries for Java (JDK5 Backport) (com.google.guava:guava-jdk5:17.0 - http://code.google.com/p/guava-libraries/guava-jdk5)
* Google HTTP Client Library for Java (com.google.http-client:google-http-client:1.21.0 - https://github.com/google/google-http-java-client/google-http-client)
* Jackson 2 extensions to the Google HTTP Client Library for Java. (com.google.http-client:google-http-client-jackson2:1.21.0 - https://github.com/google/google-http-java-client/google-http-client-jackson2)
* Google OAuth Client Library for Java (com.google.oauth-client:google-oauth-client:1.21.0 - https://github.com/google/google-oauth-java-client/google-oauth-client)
* Guava: Google Core Libraries for Java (com.google.guava:guava:18.0 - http://code.google.com/p/guava-libraries/guava)
* Guava: Google Core Libraries for Java (com.google.guava:guava-jdk5:13.0 - http://code.google.com/p/guava-libraries/guava-jdk5)
* Google HTTP Client Library for Java (com.google.http-client:google-http-client:1.19.0 - http://code.google.com/p/google-http-java-client/google-http-client/)
* Jackson 2 extensions to the Google HTTP Client Library for Java. (com.google.http-client:google-http-client-jackson2:1.19.0 - http://code.google.com/p/google-http-java-client/google-http-client-jackson2/)
* Google OAuth Client Library for Java (com.google.oauth-client:google-oauth-client:1.19.0 - http://code.google.com/p/google-oauth-java-client/google-oauth-client/)
* ConcurrentLinkedHashMap (com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.2 - http://code.google.com/p/concurrentlinkedhashmap)
* FORESITE :: Object Reuse and Exchange library (com.googlecode.foresite-toolkit:foresite:0.9 - http://www.openarchives.org/ore)
* ISO Parser (com.googlecode.mp4parser:isoparser:1.0-RC-1 - http://code.google.com/p/mp4parser/)
* builder-commons (com.lyncode:builder-commons:1.0.2 - http://nexus.sonatype.org/oss-repository-hosting.html/builder-commons)
* Jtwig Core (com.lyncode:jtwig-core:2.0.1 - http://www.lyncode.com/jtwig-core)
* Jtwig Core Functions (com.lyncode:jtwig-functions:2.0.1 - http://www.lyncode.com/jtwig-functions)
* Jtwig Spring (com.lyncode:jtwig-spring:2.0.1 - http://www.lyncode.com/jtwig-spring)
* Test Support (com.lyncode:test-support:1.0.3 - http://nexus.sonatype.org/oss-repository-hosting.html/test-support)
* MaxMind DB Reader (com.maxmind.db:maxmind-db:1.2.2 - http://dev.maxmind.com/)
* MaxMind GeoIP2 API (com.maxmind.geoip2:geoip2:2.11.0 - http://dev.maxmind.com/geoip/geoip2/web-services)
* Spatial4J (com.spatial4j:spatial4j:0.4.1 - https://github.com/spatial4j/spatial4j)
* Apache Commons BeanUtils (commons-beanutils:commons-beanutils:1.9.2 - http://commons.apache.org/proper/commons-beanutils/)
* Apache Commons CLI (commons-cli:commons-cli:1.3.1 - http://commons.apache.org/proper/commons-cli/)
* Apache Commons Codec (commons-codec:commons-codec:1.10 - http://commons.apache.org/proper/commons-codec/)
* Commons BeanUtils (commons-beanutils:commons-beanutils:1.8.3 - http://commons.apache.org/beanutils/)
* Commons CLI (commons-cli:commons-cli:1.2 - http://commons.apache.org/cli/)
* Apache Commons Codec (commons-codec:commons-codec:1.9 - http://commons.apache.org/proper/commons-codec/)
* Apache Commons Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/)
* Apache Commons Configuration (commons-configuration:commons-configuration:1.10 - http://commons.apache.org/configuration/)
* Commons Digester (commons-digester:commons-digester:1.8.1 - http://commons.apache.org/digester/)
* Apache Commons FileUpload (commons-fileupload:commons-fileupload:1.3.1 - http://commons.apache.org/proper/commons-fileupload/)
* Commons Configuration (commons-configuration:commons-configuration:1.6 - http://commons.apache.org/${pom.artifactId.substring(8)}/)
* Commons Configuration (commons-configuration:commons-configuration:1.8 - http://commons.apache.org/configuration/)
* Commons DBCP (commons-dbcp:commons-dbcp:1.4 - http://commons.apache.org/dbcp/)
* Digester (commons-digester:commons-digester:1.8 - http://jakarta.apache.org/commons/digester/)
* Commons FileUpload (commons-fileupload:commons-fileupload:1.2.1 - http://commons.apache.org/fileupload/)
* HttpClient (commons-httpclient:commons-httpclient:3.1 - http://jakarta.apache.org/httpcomponents/httpclient-3.x/)
* Commons IO (commons-io:commons-io:2.4 - http://commons.apache.org/io/)
* Commons IO (commons-io:commons-io:2.3 - http://commons.apache.org/io/)
* commons-jexl (commons-jexl:commons-jexl:1.0 - no url defined)
* Commons JXPath (commons-jxpath:commons-jxpath:1.3 - http://commons.apache.org/jxpath/)
* Commons Lang (commons-lang:commons-lang:2.6 - http://commons.apache.org/lang/)
* Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/)
* Apache Commons Validator (commons-validator:commons-validator:1.5.0 - http://commons.apache.org/proper/commons-validator/)
* Commons Logging (commons-logging:commons-logging:1.1.1 - http://commons.apache.org/logging)
* Commons Pool (commons-pool:commons-pool:1.4 - http://commons.apache.org/pool/)
* Commons Validator (commons-validator:commons-validator:1.4.0 - http://commons.apache.org/validator/)
* Boilerpipe -- Boilerplate Removal and Fulltext Extraction from HTML pages (de.l3s.boilerpipe:boilerpipe:1.1.0 - http://code.google.com/p/boilerpipe/)
* The Netty Project (io.netty:netty:3.7.0.Final - http://netty.io/)
* jakarta-regexp (jakarta-regexp:jakarta-regexp:1.4 - no url defined)
* javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
* Bean Validation API (javax.validation:validation-api:1.1.0.Final - http://beanvalidation.org)
* jdbm (jdbm:jdbm:1.0 - no url defined)
* Joda time (joda-time:joda-time:2.2 - http://joda-time.sourceforge.net)
* Joda-Time (joda-time:joda-time:2.9.2 - http://www.joda.org/joda-time/)
* Joda-Time (joda-time:joda-time:2.3 - http://www.joda.org/joda-time/)
* Apache Log4j (log4j:log4j:1.2.16 - http://logging.apache.org/log4j/1.2/)
* Apache Log4j (log4j:log4j:1.2.17 - http://logging.apache.org/log4j/1.2/)
* "Java Concurrency in Practice" book annotations (net.jcip:jcip-annotations:1.0 - http://jcip.net/)
* Ehcache Core (net.sf.ehcache:ehcache-core:2.4.3 - http://ehcache.org)
* Ehcache Core (net.sf.ehcache:ehcache-core:1.7.2 - http://ehcache.sf.net/ehcache-core)
* opencsv (net.sf.opencsv:opencsv:2.0 - http://opencsv.sf.net)
* opencsv (net.sf.opencsv:opencsv:2.3 - http://opencsv.sf.net)
* Abdera Client (org.apache.abdera:abdera-client:1.1.3 - http://abdera.apache.org/abdera-client)
* Abdera Core (org.apache.abdera:abdera-core:1.1.3 - http://abdera.apache.org/abdera-core)
* I18N Libraries (org.apache.abdera:abdera-i18n:1.1.3 - http://abdera.apache.org)
* Abdera Parser (org.apache.abdera:abdera-parser:1.1.3 - http://abdera.apache.org/abdera-parser)
* Abdera Client (org.apache.abdera:abdera-client:1.1.1 - http://abdera.apache.org/abdera-client)
* Abdera Core (org.apache.abdera:abdera-core:1.1.1 - http://abdera.apache.org/abdera-core)
* I18N Libraries (org.apache.abdera:abdera-i18n:1.1.1 - http://abdera.apache.org)
* Abdera Parser (org.apache.abdera:abdera-parser:1.1.1 - http://abdera.apache.org/abdera-parser)
* org.apache.tools.ant (org.apache.ant:ant:1.7.0 - http://ant.apache.org/ant/)
* ant-launcher (org.apache.ant:ant-launcher:1.7.0 - http://ant.apache.org/ant-launcher/)
* Avalon Framework API (org.apache.avalon.framework:avalon-framework-api:4.3.1 - http://www.apache.org/excalibur/avalon-framework/avalon-framework-api/)
@@ -112,16 +115,14 @@ https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines
* Cocoon XML Resolver (org.apache.cocoon:cocoon-xml-resolver:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-resolver/1.0/)
* Cocoon XML Utilities (org.apache.cocoon:cocoon-xml-util:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-util/1.0/)
* Apache Commons Compress (org.apache.commons:commons-compress:1.7 - http://commons.apache.org/proper/commons-compress/)
* Apache Commons CSV (org.apache.commons:commons-csv:1.0 - http://commons.apache.org/proper/commons-csv/)
* Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.1.1 - http://commons.apache.org/dbcp/)
* Apache Commons Lang (org.apache.commons:commons-lang3:3.3.2 - http://commons.apache.org/proper/commons-lang/)
* Apache Commons Pool (org.apache.commons:commons-pool2:2.4.2 - http://commons.apache.org/proper/commons-pool/)
* Commons Lang (org.apache.commons:commons-lang3:3.1 - http://commons.apache.org/lang/)
* Excalibur Pool API (org.apache.excalibur.components:excalibur-pool-api:2.2.1 - http://www.apache.org/excalibur/excalibur-components-modules/excalibur-pool-modules/excalibur-pool-api/)
* Excalibur Sourceresolve (org.apache.excalibur.components:excalibur-sourceresolve:2.2.3 - http://www.apache.org/excalibur/excalibur-sourceresolve/)
* Excalibur Store (org.apache.excalibur.components:excalibur-store:2.2.1 - http://www.apache.org/excalibur/excalibur-components-modules/excalibur-store/)
* Excalibur XML Utilities (org.apache.excalibur.components:excalibur-xmlutil:2.2.1 - http://www.apache.org/excalibur/excalibur-components-modules/excalibur-xmlutil/)
* Excalibur Instrument API (org.apache.excalibur.containerkit:excalibur-instrument-api:2.2.1 - http://www.apache.org/excalibur/excalibur-containerkit/excalibur-instrument-modules/excalibur-instrument-api/)
* Excalibur Logger (org.apache.excalibur.containerkit:excalibur-logger:2.2.1 - http://www.apache.org/excalibur/excalibur-containerkit/excalibur-logger/)
* Activation (org.apache.geronimo.specs:geronimo-activation_1.0.2_spec:1.1 - http://geronimo.apache.org/geronimo-activation_1.0.2_spec)
* Activation 1.1 (org.apache.geronimo.specs:geronimo-activation_1.1_spec:1.1 - http://geronimo.apache.org/maven/specs/geronimo-activation_1.1_spec/1.1)
* JavaMail 1.4 (org.apache.geronimo.specs:geronimo-javamail_1.4_spec:1.7.1 - http://geronimo.apache.org/maven/specs/geronimo-javamail_1.4_spec/1.7.1)
* Streaming API for XML (STAX API 1.0) (org.apache.geronimo.specs:geronimo-stax-api_1.0_spec:1.0.1 - http://geronimo.apache.org/specs/geronimo-stax-api_1.0_spec)
@@ -129,116 +130,106 @@ https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines
* Apache Hadoop Auth (org.apache.hadoop:hadoop-auth:2.2.0 - no url defined)
* Apache Hadoop Common (org.apache.hadoop:hadoop-common:2.2.0 - no url defined)
* Apache Hadoop HDFS (org.apache.hadoop:hadoop-hdfs:2.2.0 - no url defined)
* Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.1 - http://hc.apache.org/httpcomponents-client)
* Apache HttpClient (org.apache.httpcomponents:httpclient:4.3.5 - http://hc.apache.org/httpcomponents-client)
* Apache HttpClient Cache (org.apache.httpcomponents:httpclient-cache:4.2.6 - http://hc.apache.org/httpcomponents-client)
* Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.4 - http://hc.apache.org/httpcomponents-core-ga)
* Apache HttpCore (org.apache.httpcomponents:httpcore:4.3.2 - http://hc.apache.org/httpcomponents-core-ga)
* Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.3.1 - http://hc.apache.org/httpcomponents-client)
* Apache JAMES Mime4j (Core) (org.apache.james:apache-mime4j-core:0.7.2 - http://james.apache.org/mime4j/apache-mime4j-core)
* Apache JAMES Mime4j (DOM) (org.apache.james:apache-mime4j-dom:0.7.2 - http://james.apache.org/mime4j/apache-mime4j-dom)
* Apache Jena - Libraries POM (org.apache.jena:apache-jena-libs:2.13.0 - http://jena.apache.org/apache-jena-libs/)
* Apache Jena - ARQ (SPARQL 1.1 Query Engine) (org.apache.jena:jena-arq:2.13.0 - http://jena.apache.org/jena-arq/)
* Apache Jena - Core (org.apache.jena:jena-core:2.13.0 - http://jena.apache.org/jena-core/)
* Apache Jena - IRI (org.apache.jena:jena-iri:1.1.2 - http://jena.apache.org/jena-iri/)
* Apache Jena - TDB (Native Triple Store) (org.apache.jena:jena-tdb:1.1.2 - http://jena.apache.org/jena-tdb/)
* Apache Jena - Libraries POM (org.apache.jena:apache-jena-libs:2.12.0 - http://jena.apache.org/apache-jena-libs/)
* Apache Jena - ARQ (SPARQL 1.1 Query Engine) (org.apache.jena:jena-arq:2.12.0 - http://jena.apache.org/jena-arq/)
* Apache Jena - Core (org.apache.jena:jena-core:2.12.0 - http://jena.apache.org/jena-core/)
* Apache Jena - IRI (org.apache.jena:jena-iri:1.1.0 - http://jena.apache.org/jena-iri/)
* Apache Jena - TDB (Native Triple Store) (org.apache.jena:jena-tdb:1.1.0 - http://jena.apache.org/jena-tdb/)
* Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-analyzers-common)
* Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-common)
* Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-icu)
* Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji)
* Lucene Morfologik Polish Lemmatizer (org.apache.lucene:lucene-analyzers-morfologik:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-morfologik)
* Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic)
* Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn)
* Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-stempel)
* Lucene codecs (org.apache.lucene:lucene-codecs:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-codecs)
* Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-analyzers-icu)
* Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji)
* Lucene Morfologik Polish Lemmatizer (org.apache.lucene:lucene-analyzers-morfologik:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-analyzers-morfologik)
* Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic)
* Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn)
* Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-analyzers-stempel)
* Lucene codecs (org.apache.lucene:lucene-codecs:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-codecs)
* Lucene Core (org.apache.lucene:lucene-core:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-core)
* Lucene Core (org.apache.lucene:lucene-core:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-core)
* Lucene Expressions (org.apache.lucene:lucene-expressions:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-expressions)
* Lucene Expressions (org.apache.lucene:lucene-expressions:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-expressions)
* Lucene Grouping (org.apache.lucene:lucene-grouping:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-grouping)
* Lucene Grouping (org.apache.lucene:lucene-grouping:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-grouping)
* Lucene Highlighter (org.apache.lucene:lucene-highlighter:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-highlighter)
* Lucene Highlighter (org.apache.lucene:lucene-highlighter:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-highlighter)
* Lucene Join (org.apache.lucene:lucene-join:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-join)
* Lucene Join (org.apache.lucene:lucene-join:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-join)
* Lucene Memory (org.apache.lucene:lucene-memory:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-memory)
* Lucene Memory (org.apache.lucene:lucene-memory:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-memory)
* Lucene Miscellaneous (org.apache.lucene:lucene-misc:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-misc)
* Lucene Miscellaneous (org.apache.lucene:lucene-misc:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-misc)
* Lucene Queries (org.apache.lucene:lucene-queries:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-queries)
* Lucene Queries (org.apache.lucene:lucene-queries:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-queries)
* Lucene QueryParsers (org.apache.lucene:lucene-queryparser:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-queryparser)
* Lucene QueryParsers (org.apache.lucene:lucene-queryparser:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-queryparser)
* Lucene Sandbox (org.apache.lucene:lucene-sandbox:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-sandbox)
* Lucene Spatial (org.apache.lucene:lucene-spatial:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-spatial)
* Lucene Spatial (org.apache.lucene:lucene-spatial:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-spatial)
* Lucene Suggest (org.apache.lucene:lucene-suggest:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-suggest)
* Lucene Suggest (org.apache.lucene:lucene-suggest:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-suggest)
* Apache FontBox (org.apache.pdfbox:fontbox:2.0.2 - http://pdfbox.apache.org/)
* Apache JempBox (org.apache.pdfbox:jempbox:1.8.4 - http://www.apache.org/pdfbox-parent/jempbox/)
* Apache PDFBox (org.apache.pdfbox:pdfbox:2.0.2 - http://www.apache.org/pdfbox-parent/pdfbox/)
* Apache POI (org.apache.poi:poi:3.13 - http://poi.apache.org/)
* Apache POI (org.apache.poi:poi-ooxml:3.13 - http://poi.apache.org/)
* Apache FontBox (org.apache.pdfbox:fontbox:1.8.12 - http://pdfbox.apache.org/)
* Apache JempBox (org.apache.pdfbox:jempbox:1.8.12 - http://www.apache.org/pdfbox-parent/jempbox/)
* Apache PDFBox (org.apache.pdfbox:pdfbox:1.8.12 - http://www.apache.org/pdfbox-parent/pdfbox/)
* Apache POI (org.apache.poi:poi:3.6 - http://poi.apache.org/)
* Apache POI (org.apache.poi:poi-ooxml:3.6 - http://poi.apache.org/)
* Apache POI (org.apache.poi:poi-ooxml-schemas:3.10.1 - http://poi.apache.org/)
* Apache POI (org.apache.poi:poi-ooxml-schemas:3.13 - http://poi.apache.org/)
* Apache POI (org.apache.poi:poi-scratchpad:3.13 - http://poi.apache.org/)
* Apache Solr Search Server (org.apache.solr:solr:4.10.4 - http://lucene.apache.org/solr-parent/solr)
* Apache Solr Analysis Extras (org.apache.solr:solr-analysis-extras:4.10.4 - http://lucene.apache.org/solr-parent/solr-analysis-extras)
* Apache Solr Content Extraction Library (org.apache.solr:solr-cell:4.10.4 - http://lucene.apache.org/solr-parent/solr-cell)
* Apache Solr Core (org.apache.solr:solr-core:4.10.4 - http://lucene.apache.org/solr-parent/solr-core)
* Apache Solr Solrj (org.apache.solr:solr-solrj:4.10.4 - http://lucene.apache.org/solr-parent/solr-solrj)
* Apache Thrift (org.apache.thrift:libthrift:0.9.2 - http://thrift.apache.org)
* Apache POI (org.apache.poi:poi-ooxml-schemas:3.6 - http://poi.apache.org/)
* Apache POI (org.apache.poi:poi-scratchpad:3.6 - http://poi.apache.org/)
* Apache Solr Search Server (org.apache.solr:solr:4.10.2 - http://lucene.apache.org/solr-parent/solr)
* Apache Solr Analysis Extras (org.apache.solr:solr-analysis-extras:4.10.2 - http://lucene.apache.org/solr-parent/solr-analysis-extras)
* Apache Solr Content Extraction Library (org.apache.solr:solr-cell:4.10.2 - http://lucene.apache.org/solr-parent/solr-cell)
* Apache Solr Core (org.apache.solr:solr-core:4.10.2 - http://lucene.apache.org/solr-parent/solr-core)
* Apache Solr Solrj (org.apache.solr:solr-solrj:4.10.2 - http://lucene.apache.org/solr-parent/solr-solrj)
* Apache Tika core (org.apache.tika:tika-core:1.5 - http://tika.apache.org/)
* Apache Tika parsers (org.apache.tika:tika-parsers:1.5 - http://tika.apache.org/)
* Apache Tika XMP (org.apache.tika:tika-xmp:1.5 - http://tika.apache.org/)
* Axiom API (org.apache.ws.commons.axiom:axiom-api:1.2.14 - http://ws.apache.org/axiom/)
* Axiom Impl (org.apache.ws.commons.axiom:axiom-impl:1.2.14 - http://ws.apache.org/axiom/)
* XmlBeans (org.apache.xmlbeans:xmlbeans:2.3.0 - http://xmlbeans.apache.org)
* XmlBeans (org.apache.xmlbeans:xmlbeans:2.6.0 - http://xmlbeans.apache.org)
* zookeeper (org.apache.zookeeper:zookeeper:3.4.6 - no url defined)
* Evo Inflector (org.atteo:evo-inflector:1.2.1 - http://atteo.org/static/evo-inflector)
* Evo Inflector (org.atteo:evo-inflector:1.0.1 - http://atteo.org/static/evo-inflector)
* TagSoup (org.ccil.cowan.tagsoup:tagsoup:1.2.1 - http://home.ccil.org/~cowan/XML/tagsoup/)
* Jackson (org.codehaus.jackson:jackson-core-asl:1.9.13 - http://jackson.codehaus.org)
* Jackson (org.codehaus.jackson:jackson-core-asl:1.9.2 - http://jackson.codehaus.org)
* JAX-RS provider for JSON content type (org.codehaus.jackson:jackson-jaxrs:1.9.2 - http://jackson.codehaus.org)
* Data Mapper for Jackson (org.codehaus.jackson:jackson-mapper-asl:1.9.13 - http://jackson.codehaus.org)
* Data Mapper for Jackson (org.codehaus.jackson:jackson-mapper-asl:1.9.2 - http://jackson.codehaus.org)
* Xml Compatibility extensions for Jackson (org.codehaus.jackson:jackson-xc:1.9.2 - http://jackson.codehaus.org)
* Jettison (org.codehaus.jettison:jettison:1.1 - no url defined)
* Woodstox (org.codehaus.woodstox:woodstox-core-asl:4.1.4 - http://woodstox.codehaus.org)
* Woodstox (org.codehaus.woodstox:wstx-asl:3.2.0 - http://woodstox.codehaus.org)
* Woodstox (org.codehaus.woodstox:wstx-asl:3.2.7 - http://woodstox.codehaus.org)
* flyway-core (org.flywaydb:flyway-core:4.0.3 - https://flywaydb.org/flyway-core)
* databene ContiPerf (org.databene:contiperf:2.2.0 - http://databene.org/contiperf)
* elasticsearch (org.elasticsearch:elasticsearch:1.4.0 - http://nexus.sonatype.org/oss-repository-hosting.html/elasticsearch)
* flyway-core (org.flywaydb:flyway-core:3.0 - http://flywaydb.org/flyway-core)
* Ogg and Vorbis for Java, Core (org.gagravarr:vorbis-java-core:0.1 - https://github.com/Gagravarr/VorbisJava)
* Apache Tika plugin for Ogg, Vorbis and FLAC (org.gagravarr:vorbis-java-tika:0.1 - https://github.com/Gagravarr/VorbisJava)
* Javassist (org.javassist:javassist:3.16.1-GA - http://www.javassist.org/)
* Javassist (org.javassist:javassist:3.18.1-GA - http://www.javassist.org/)
* Jetty Server (org.mortbay.jetty:jetty:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/modules/jetty)
* Jetty Servlet Tester (org.mortbay.jetty:jetty-servlet-tester:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-servlet-tester)
* Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util)
* Servlet Specification API (org.mortbay.jetty:servlet-api:2.5-20081211 - http://jetty.mortbay.org/servlet-api)
* Jetty Server (org.mortbay.jetty:jetty:6.1.14 - http://jetty.mortbay.org/project/modules/jetty)
* Jetty Servlet Tester (org.mortbay.jetty:jetty-servlet-tester:6.1.14 - http://jetty.mortbay.org/project/jetty-servlet-tester)
* Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.14 - http://jetty.mortbay.org/project/jetty-util)
* Noggit (org.noggit:noggit:0.5 - http://noggit.org)
* Objenesis (org.objenesis:objenesis:2.1 - http://objenesis.org)
* parboiled-core (org.parboiled:parboiled-core:1.1.6 - http://parboiled.org)
* parboiled-java (org.parboiled:parboiled-java:1.1.6 - http://parboiled.org)
* org.restlet (org.restlet.jee:org.restlet:2.1.1 - no url defined)
* org.restlet.ext.servlet (org.restlet.jee:org.restlet.ext.servlet:2.1.1 - no url defined)
* Restlet Core - API and Engine (org.restlet.jee:org.restlet:2.1.1 - http://www.restlet.org/org.restlet)
* Restlet Extension - Servlet (org.restlet.jee:org.restlet.ext.servlet:2.1.1 - http://www.restlet.org/org.restlet.ext.servlet)
* rome-modules (org.rometools:rome-modules:1.0 - http://www.rometools.org)
* Spring AOP (org.springframework:spring-aop:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* spring-aop (org.springframework:spring-aop:3.1.1.RELEASE - no url defined)
* Spring AOP (org.springframework:spring-aop:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Beans (org.springframework:spring-beans:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* spring-asm (org.springframework:spring-asm:3.1.1.RELEASE - no url defined)
* spring-beans (org.springframework:spring-beans:3.1.1.RELEASE - no url defined)
* Spring Beans (org.springframework:spring-beans:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Context (org.springframework:spring-context:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* spring-context (org.springframework:spring-context:3.1.1.RELEASE - no url defined)
* Spring Context (org.springframework:spring-context:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Context Support (org.springframework:spring-context-support:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Core (org.springframework:spring-core:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* spring-context-support (org.springframework:spring-context-support:3.1.1.RELEASE - no url defined)
* spring-core (org.springframework:spring-core:3.1.1.RELEASE - no url defined)
* Spring Core (org.springframework:spring-core:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Expression Language (SpEL) (org.springframework:spring-expression:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* spring-expression (org.springframework:spring-expression:3.1.1.RELEASE - no url defined)
* Spring Expression Language (SpEL) (org.springframework:spring-expression:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring JDBC (org.springframework:spring-jdbc:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring JDBC (org.springframework:spring-jdbc:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Object/Relational Mapping (org.springframework:spring-orm:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Object/Relational Mapping (org.springframework:spring-orm:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* spring-jdbc (org.springframework:spring-jdbc:3.1.1.RELEASE - no url defined)
* Spring Framework: Mock (org.springframework:spring-mock:2.0.8 - http://www.springframework.org)
* Spring TestContext Framework (org.springframework:spring-test:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Transaction (org.springframework:spring-tx:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Transaction (org.springframework:spring-tx:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Web (org.springframework:spring-web:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* spring-tx (org.springframework:spring-tx:3.1.1.RELEASE - no url defined)
* spring-web (org.springframework:spring-web:3.1.1.RELEASE - no url defined)
* Spring Web (org.springframework:spring-web:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Web MVC (org.springframework:spring-webmvc:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* spring-webmvc (org.springframework:spring-webmvc:3.1.1.RELEASE - no url defined)
* Spring Web MVC (org.springframework:spring-webmvc:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* spring-security-config (org.springframework.security:spring-security-config:3.2.9.RELEASE - http://spring.io/spring-security)
* spring-security-core (org.springframework.security:spring-security-core:3.2.9.RELEASE - http://spring.io/spring-security)
* spring-security-web (org.springframework.security:spring-security-web:3.2.9.RELEASE - http://spring.io/spring-security)
* SWORD Java API, GUI and CLI (org.swordapp:sword-common:1.1 - http://nexus.sonatype.org/oss-repository-hosting.html/sword-common)
* SWORD v2 :: Common Server Library (org.swordapp:sword2-server:1.0 - http://www.swordapp.org/)
* xml-matchers (org.xmlmatchers:xml-matchers:0.10 - http://code.google.com/p/xml-matchers/)
@@ -249,58 +240,59 @@ https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines
* oai4j (se.kb:oai4j:0.6b1 - http://oai4j-client.sourceforge.net/)
* StAX API (stax:stax-api:1.0.1 - http://stax.codehaus.org/)
* standard (taglibs:standard:1.1.2 - no url defined)
* Xalan Java Serializer (xalan:serializer:2.7.2 - http://xml.apache.org/xalan-j/)
* Xalan Java (xalan:xalan:2.7.2 - http://xml.apache.org/xalan-j/)
* Xerces2-j (xerces:xercesImpl:2.11.0 - https://xerces.apache.org/xerces2-j/)
* xalan (xalan:xalan:2.7.0 - no url defined)
* Xerces2 Java Parser (xerces:xercesImpl:2.8.1 - http://xerces.apache.org/xerces2-j/)
* xmlParserAPIs (xerces:xmlParserAPIs:2.6.2 - no url defined)
* XML Commons External Components XML APIs (xml-apis:xml-apis:1.4.01 - http://xml.apache.org/commons/components/external/)
* XML Commons External Components XML APIs (xml-apis:xml-apis:1.0.b2 - http://xml.apache.org/commons/#external)
* xml-apis (xml-apis:xml-apis:1.3.02 - http://xml.apache.org/commons/#external)
* xmlParserAPIs (xml-apis:xmlParserAPIs:2.0.2 - no url defined)
* XML Commons Resolver Component (xml-resolver:xml-resolver:1.2 - http://xml.apache.org/commons/components/resolver/)
BSD License:
* AntLR Parser Generator (antlr:antlr:2.7.7 - http://www.antlr.org/)
* ASM Core (asm:asm:3.3.1 - http://asm.objectweb.org/asm/)
* XMP Library for Java (com.adobe.xmp:xmpcore:5.1.2 - http://www.adobe.com/devnet/xmp.html)
* coverity-escapers (com.coverity.security:coverity-escapers:1.1.1 - http://coverity.com/security)
* JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.5.1 - http://github.com/jsonld-java/jsonld-java/jsonld-java/)
* JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.5.0 - http://github.com/jsonld-java/jsonld-java/jsonld-java/)
* Protocol Buffer Java API (com.google.protobuf:protobuf-java:2.5.0 - http://code.google.com/p/protobuf)
* Jena IRI (com.hp.hpl.jena:iri:0.8 - http://jena.sf.net/iri)
* Jena (com.hp.hpl.jena:jena:2.6.4 - http://www.openjena.org/)
* yui compressor (com.yahoo.platform.yui:yuicompressor:2.3.6 - http://developer.yahoo.com/yui/compressor/)
* dnsjava (dnsjava:dnsjava:2.1.7 - http://www.dnsjava.org)
* dnsjava (dnsjava:dnsjava:2.1.1 - http://www.dnsjava.org)
* dom4j (dom4j:dom4j:1.6.1 - http://dom4j.org)
* Biblio Transformation Engine :: Core (gr.ekt.bte:bte-core:0.9.3.5 - http://github.com/EKT/Biblio-Transformation-Engine/bte-core)
* Biblio Transformation Engine :: Input/Output (gr.ekt.bte:bte-io:0.9.3.5 - http://github.com/EKT/Biblio-Transformation-Engine/bte-io)
* jaxen (jaxen:jaxen:1.1.6 - http://jaxen.codehaus.org/)
* JLine (jline:jline:0.9.94 - http://jline.sourceforge.net)
* jaxen (jaxen:jaxen:1.1 - http://jaxen.codehaus.org/)
* ANTLR 3 Runtime (org.antlr:antlr-runtime:3.5 - http://www.antlr.org)
* Morfologik FSA (org.carrot2:morfologik-fsa:1.7.1 - http://morfologik.blogspot.com/morfologik-fsa/)
* Morfologik Stemming Dictionary for Polish (org.carrot2:morfologik-polish:1.7.1 - http://morfologik.blogspot.com/morfologik-polish/)
* Morfologik Stemming APIs (org.carrot2:morfologik-stemming:1.7.1 - http://morfologik.blogspot.com/morfologik-stemming/)
* Stax2 API (org.codehaus.woodstox:stax2-api:3.1.1 - http://woodstox.codehaus.org/StAX2)
* DSpace Kernel :: API and Implementation (org.dspace:dspace-api:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-api)
* DSpace I18N :: Language Packs (org.dspace:dspace-api-lang:6.0.3 - https://github.com/dspace/dspace-api-lang)
* DSpace JSP-UI (org.dspace:dspace-jspui:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-jspui)
* DSpace OAI-PMH (org.dspace:dspace-oai:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-oai)
* DSpace RDF (org.dspace:dspace-rdf:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-rdf)
* DSpace REST :: API and Implementation (org.dspace:dspace-rest:6.0-rc4-SNAPSHOT - http://demo.dspace.org)
* DSpace Services Framework :: API and Implementation (org.dspace:dspace-services:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-services)
* Apache Solr Webapp (org.dspace:dspace-solr:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-solr)
* DSpace SWORD (org.dspace:dspace-sword:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-sword)
* DSpace SWORD v2 (org.dspace:dspace-swordv2:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-swordv2)
* DSpace XML-UI (Manakin) (org.dspace:dspace-xmlui:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-xmlui)
* DSpace XML-UI (Manakin) I18N :: Language Packs (org.dspace:dspace-xmlui-lang:6.0.3 - https://github.com/dspace/dspace-xmlui-lang)
* databene ContiPerf (org.databene:contiperf:2.2.0 - http://databene.org/contiperf)
* DSpace Kernel :: API and Implementation (org.dspace:dspace-api:5.10-SNAPSHOT - https://github.com/dspace/DSpace/dspace-api)
* DSpace I18N :: Language Packs (org.dspace:dspace-api-lang:5.0.7 - http://nexus.sonatype.org/oss-repository-hosting.html/dspace-api-lang)
* DSpace JSP-UI (org.dspace:dspace-jspui:5.10-SNAPSHOT - https://github.com/dspace/DSpace/dspace-jspui)
* DSpace OAI-PMH (org.dspace:dspace-oai:5.10-SNAPSHOT - https://github.com/dspace/DSpace/dspace-oai)
* DSpace RDF (org.dspace:dspace-rdf:5.10-SNAPSHOT - https://github.com/dspace/DSpace/dspace-rdf)
* DSpace REST :: API and Implementation (org.dspace:dspace-rest:5.10-SNAPSHOT - http://demo.dspace.org)
* DSpace Services Framework :: API and Implementation (org.dspace:dspace-services:5.10-SNAPSHOT - https://github.com/dspace/DSpace/dspace-services)
* Apache Solr Webapp (org.dspace:dspace-solr:5.10-SNAPSHOT - https://github.com/dspace/DSpace/dspace-solr)
* DSpace SWORD (org.dspace:dspace-sword:5.10-SNAPSHOT - https://github.com/dspace/DSpace/dspace-sword)
* DSpace SWORD v2 (org.dspace:dspace-swordv2:5.10-SNAPSHOT - https://github.com/dspace/DSpace/dspace-swordv2)
* DSpace XML-UI (Manakin) (org.dspace:dspace-xmlui:5.10-SNAPSHOT - https://github.com/dspace/DSpace/dspace-xmlui)
* DSpace XML-UI (Manakin) I18N :: Language Packs (org.dspace:dspace-xmlui-lang:5.0.7 - http://nexus.sonatype.org/oss-repository-hosting.html/dspace-xmlui-lang)
* handle (org.dspace:handle:6.2 - no url defined)
* jargon (org.dspace:jargon:1.4.25 - no url defined)
* mets (org.dspace:mets:1.5.2 - no url defined)
* oclc-harvester2 (org.dspace:oclc-harvester2:0.1.12 - no url defined)
* XOAI : OAI-PMH Java Toolkit (org.dspace:xoai:3.2.10 - http://nexus.sonatype.org/oss-repository-hosting.html/xoai)
* Repackaged Cocoon Servlet Service Implementation (org.dspace.dependencies.cocoon:dspace-cocoon-servlet-service-impl:1.0.3 - http://projects.dspace.org/dspace-pom/dspace-cocoon-servlet-service-impl)
* DSpace Kernel :: Additions and Local Customizations (org.dspace.modules:additions:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/modules/additions)
* DSpace Kernel :: Additions and Local Customizations (org.dspace.modules:additions:5.10-SNAPSHOT - https://github.com/dspace/DSpace/modules/additions)
* Hamcrest All (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all)
* Hamcrest Core (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all)
* Hamcrest Core (org.hamcrest:hamcrest-core:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-core)
* JBibTeX (org.jbibtex:jbibtex:1.0.10 - http://www.jbibtex.org)
* JAXB2 Basics - Runtime (org.jvnet.jaxb2_commons:jaxb2-basics-runtime:0.9.5 - https://github.com/highsource/jaxb2-basics/jaxb2-basics-runtime)
* ASM Core (org.ow2.asm:asm:4.1 - http://asm.objectweb.org/asm/)
* ASM Core (org.ow2.asm:asm:4.2 - http://asm.objectweb.org/asm/)
* ASM Analysis (org.ow2.asm:asm-analysis:4.1 - http://asm.objectweb.org/asm-analysis/)
* ASM Commons (org.ow2.asm:asm-commons:4.1 - http://asm.objectweb.org/asm-commons/)
* ASM Tree (org.ow2.asm:asm-tree:4.1 - http://asm.objectweb.org/asm-tree/)
@@ -310,97 +302,98 @@ https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines
Common Development and Distribution License (CDDL):
* jersey-core (com.sun.jersey:jersey-core:1.19 - https://jersey.java.net/jersey-core/)
* jersey-json (com.sun.jersey:jersey-json:1.19 - https://jersey.java.net/jersey-json/)
* jersey-server (com.sun.jersey:jersey-server:1.19 - https://jersey.java.net/jersey-server/)
* jersey-servlet (com.sun.jersey:jersey-servlet:1.19 - https://jersey.java.net/jersey-servlet/)
* jersey-spring (com.sun.jersey.contribs:jersey-spring:1.19 - http://maven.apache.org)
* JAXB RI (com.sun.xml.bind:jaxb-impl:2.2.3-1 - http://jaxb.java.net/)
* JAXB Reference Implementation (com.sun.xml.bind:jaxb-impl:2.2.5 - http://jaxb.java.net/)
* JHighlight (com.uwyn:jhighlight:1.0 - https://jhighlight.dev.java.net/)
* JavaBeans(TM) Activation Framework (javax.activation:activation:1.1.1 - http://java.sun.com/javase/technologies/desktop/javabeans/jaf/index.jsp)
* JavaBeans Activation Framework (JAF) (javax.activation:activation:1.1 - http://java.sun.com/products/javabeans/jaf/index.jsp)
* javax.annotation API (javax.annotation:javax.annotation-api:1.2 - http://jcp.org/en/jsr/detail?id=250)
* JavaMail API (compat) (javax.mail:mail:1.4.7 - http://kenai.com/projects/javamail/mail)
* JavaMail API (javax.mail:mail:1.4 - https://glassfish.dev.java.net/javaee5/mail/)
* Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
* jsp-api (javax.servlet:jsp-api:2.0 - no url defined)
* jstl (javax.servlet:jstl:1.2 - no url defined)
* jstl (javax.servlet:jstl:1.1.2 - no url defined)
* servlet-api (javax.servlet:servlet-api:2.5 - no url defined)
* javax.ws.rs-api (javax.ws.rs:javax.ws.rs-api:2.0.1 - http://jax-rs-spec.java.net)
* Class Model for Hk2 (org.glassfish.hk2:class-model:2.4.0-b31 - https://hk2.java.net/class-model)
* HK2 config types (org.glassfish.hk2:config-types:2.4.0-b31 - https://hk2.java.net/hk2-configuration/hk2-configuration-persistence/hk2-xml-dom/config-types)
* HK2 module of HK2 itself (org.glassfish.hk2:hk2:2.4.0-b31 - https://hk2.java.net/hk2)
* jsr311-api (javax.ws.rs:jsr311-api:1.1.1 - https://jsr311.dev.java.net)
* JAXB API bundle for GlassFish V3 (javax.xml.bind:jaxb-api:2.2.2 - https://jaxb.dev.java.net/)
* Streaming API for XML (javax.xml.stream:stax-api:1.0-2 - no url defined)
* HK2 API module (org.glassfish.hk2:hk2-api:2.4.0-b31 - https://hk2.java.net/hk2-api)
* HK2 configuration module (org.glassfish.hk2:hk2-config:2.4.0-b31 - https://hk2.java.net/hk2-configuration/hk2-configuration-persistence/hk2-xml-dom/hk2-config)
* HK2 core module (org.glassfish.hk2:hk2-core:2.4.0-b31 - https://hk2.java.net/hk2-core)
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:2.4.0-b31 - https://hk2.java.net/hk2-locator)
* Run Level Service (org.glassfish.hk2:hk2-runlevel:2.4.0-b31 - https://hk2.java.net/hk2-runlevel)
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:2.4.0-b31 - https://hk2.java.net/hk2-utils)
* OSGi resource locator bundle - used by various API providers that rely on META-INF/services mechanism to locate providers. (org.glassfish.hk2:osgi-resource-locator:1.0.1 - http://glassfish.org/osgi-resource-locator/)
* HK2 Spring Bridge (org.glassfish.hk2:spring-bridge:2.4.0-b31 - https://hk2.java.net/spring-bridge)
* aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:2.4.0-b31 - https://hk2.java.net/external/aopalliance-repackaged)
* ASM library repackaged as OSGi bundle (org.glassfish.hk2.external:asm-all-repackaged:2.4.0-b31 - https://hk2.java.net/external/asm-all-repackaged)
* javax.validation:1.1.0.Final as OSGi bundle (org.glassfish.hk2.external:bean-validator:2.4.0-b31 - https://hk2.java.net/external/bean-validator)
* javax.inject:1 as OSGi bundle (org.glassfish.hk2.external:javax.inject:2.4.0-b31 - https://hk2.java.net/external/javax.inject)
* jersey-repackaged-guava (org.glassfish.jersey.bundles.repackaged:jersey-guava:2.22.1 - https://jersey.java.net/project/project/jersey-guava/)
* jersey-container-servlet (org.glassfish.jersey.containers:jersey-container-servlet:2.22.1 - https://jersey.java.net/project/jersey-container-servlet/)
* jersey-container-servlet-core (org.glassfish.jersey.containers:jersey-container-servlet-core:2.22.1 - https://jersey.java.net/project/jersey-container-servlet-core/)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.22.1 - https://jersey.java.net/jersey-client/)
* jersey-core-common (org.glassfish.jersey.core:jersey-common:2.22.1 - https://jersey.java.net/jersey-common/)
* jersey-core-server (org.glassfish.jersey.core:jersey-server:2.22.1 - https://jersey.java.net/jersey-server/)
* jersey-ext-entity-filtering (org.glassfish.jersey.ext:jersey-entity-filtering:2.22.1 - https://jersey.java.net/project/jersey-entity-filtering/)
* jersey-spring3 (org.glassfish.jersey.ext:jersey-spring3:2.22.1 - https://jersey.java.net/project/jersey-spring3/)
* jersey-media-jaxb (org.glassfish.jersey.media:jersey-media-jaxb:2.22.1 - https://jersey.java.net/project/jersey-media-jaxb/)
* jersey-media-json-jackson (org.glassfish.jersey.media:jersey-media-json-jackson:2.22.1 - https://jersey.java.net/project/jersey-media-json-jackson/)
* Java Transaction API (org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.1.Final - http://www.jboss.org/jboss-transaction-api_1.1_spec)
* Type arithmetic library for Java5 (org.jvnet:tiger-types:1.4 - http://java.net/tiger-types/)
* Servlet Specification 2.5 API (org.mortbay.jetty:servlet-api-2.5:6.1.14 - http://jetty.mortbay.org/project/modules/servlet-api-2.5)
* Restlet Core - API and Engine (org.restlet.jee:org.restlet:2.1.1 - http://www.restlet.org/org.restlet)
* Restlet Extension - Servlet (org.restlet.jee:org.restlet.ext.servlet:2.1.1 - http://www.restlet.org/org.restlet.ext.servlet)
Eclipse Public License:
* JUnit (junit:junit:4.11 - http://junit.org)
* AspectJ runtime (org.aspectj:aspectjrt:1.6.11 - http://www.aspectj.org)
* JPA 2.0 API (org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final - http://hibernate.org)
* Jetty Server (org.mortbay.jetty:jetty:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/modules/jetty)
* Jetty Servlet Tester (org.mortbay.jetty:jetty-servlet-tester:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-servlet-tester)
* Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util)
* databene ContiPerf (org.databene:contiperf:2.2.0 - http://databene.org/contiperf)
* Restlet Core - API and Engine (org.restlet.jee:org.restlet:2.1.1 - http://www.restlet.org/org.restlet)
* Restlet Extension - Servlet (org.restlet.jee:org.restlet.ext.servlet:2.1.1 - http://www.restlet.org/org.restlet.ext.servlet)
GNU General Public License, Version 2 with the Classpath Exception:
GNU General Public Library:
* Java Transaction API (org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.1.Final - http://www.jboss.org/jboss-transaction-api_1.1_spec)
* Streaming API for XML (javax.xml.stream:stax-api:1.0-2 - no url defined)
GNU Lesser General Public License (LGPL):
* FindBugs-Annotations (com.google.code.findbugs:annotations:3.0.1u2 - http://findbugs.sourceforge.net/)
* MaxMind GeoIP Legacy API (com.maxmind.geoip:geoip-api:1.3.0 - https://github.com/maxmind/geoip-api-java)
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.3.0 - http://wiki.fasterxml.com/JacksonHome)
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.3.3 - http://wiki.fasterxml.com/JacksonHome)
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.3.3 - http://wiki.fasterxml.com/JacksonHome)
* FindBugs-Annotations (com.google.code.findbugs:annotations:3.0.0 - http://findbugs.sourceforge.net/)
* JHighlight (com.uwyn:jhighlight:1.0 - https://jhighlight.dev.java.net/)
* JAX-RS provider for JSON content type (org.codehaus.jackson:jackson-jaxrs:1.9.2 - http://jackson.codehaus.org)
* Xml Compatibility extensions for Jackson (org.codehaus.jackson:jackson-xc:1.9.2 - http://jackson.codehaus.org)
* databene ContiPerf (org.databene:contiperf:2.2.0 - http://databene.org/contiperf)
* DSpace TM-Extractors Dependency (org.dspace.dependencies:dspace-tm-extractors:1.0.1 - http://projects.dspace.org/dspace-pom/dspace-tm-extractors)
* A Hibernate O/RM Module (org.hibernate:hibernate-core:4.2.21.Final - http://hibernate.org)
* A Hibernate O/RM Module (org.hibernate:hibernate-ehcache:4.2.21.Final - http://hibernate.org)
* Hibernate Commons Annotations (org.hibernate.common:hibernate-commons-annotations:4.0.2.Final - http://hibernate.org)
* im4java (org.im4java:im4java:1.4.0 - http://sourceforge.net/projects/im4java/)
* Javassist (org.javassist:javassist:3.16.1-GA - http://www.javassist.org/)
* Javassist (org.javassist:javassist:3.18.1-GA - http://www.javassist.org/)
* JBoss Logging 3 (org.jboss.logging:jboss-logging:3.1.0.GA - http://www.jboss.org)
* org.jdesktop - Swing Worker (org.jdesktop:swing-worker:1.1 - no url defined)
* Restlet Core - API and Engine (org.restlet.jee:org.restlet:2.1.1 - http://www.restlet.org/org.restlet)
* Restlet Extension - Servlet (org.restlet.jee:org.restlet.ext.servlet:2.1.1 - http://www.restlet.org/org.restlet.ext.servlet)
* xom (xom:xom:1.1 - http://www.xom.nu)
* XOM (xom:xom:1.2.5 - http://xom.nu)
ICU License:
* ICU4J (com.ibm.icu:icu4j:56.1 - http://icu-project.org/)
* ICU4J (com.ibm.icu:icu4j:51.1 - http://icu-project.org/)
JDOM License (Apache-style license):
JDOM License:
* jdom (jdom:jdom:1.0 - no url defined)
MIT License:
* Bouncy Castle CMS and S/MIME API (org.bouncycastle:bcmail-jdk15:1.46 - http://www.bouncycastle.org/java.html)
* Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15:1.46 - http://www.bouncycastle.org/java.html)
* Main (org.jmockit:jmockit:1.21 - http://www.jmockit.org)
* Bouncy Castle CMS and S/MIME API (org.bouncycastle:bcmail-jdk15:1.44 - http://www.bouncycastle.org/java.html)
* Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15:1.44 - http://www.bouncycastle.org/java.html)
* ORCID Java API generated via JAXB (org.dspace:orcid-jaxb-api:2.1.0 - https://github.com/DSpace/orcid-jaxb-api)
* Main (org.jmockit:jmockit:1.10 - http://www.jmockit.org)
* OpenCloud (org.mcavallo:opencloud:0.3 - http://opencloud.mcavallo.org/)
* Mockito (org.mockito:mockito-core:1.10.19 - http://www.mockito.org)
* JCL 1.1.1 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.14 - http://www.slf4j.org)
* JUL to SLF4J bridge (org.slf4j:jul-to-slf4j:1.7.14 - http://www.slf4j.org)
* SLF4J API Module (org.slf4j:slf4j-api:1.7.14 - http://www.slf4j.org)
* SLF4J LOG4J-12 Binding (org.slf4j:slf4j-log4j12:1.7.14 - http://www.slf4j.org)
* Mockito (org.mockito:mockito-all:1.9.5 - http://www.mockito.org)
* Mockito (org.mockito:mockito-core:1.9.5 - http://www.mockito.org)
* Objenesis (org.objenesis:objenesis:1.0 - http://objenesis.googlecode.com/svn/docs/index.html)
* JCL 1.1.1 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.6.1 - http://www.slf4j.org)
* JUL to SLF4J bridge (org.slf4j:jul-to-slf4j:1.6.1 - http://www.slf4j.org)
* SLF4J API Module (org.slf4j:slf4j-api:1.6.1 - http://www.slf4j.org)
* SLF4J JDK14 Binding (org.slf4j:slf4j-jdk14:1.6.1 - http://www.slf4j.org)
* SLF4J LOG4J-12 Binding (org.slf4j:slf4j-log4j12:1.6.1 - http://www.slf4j.org)
Mozilla Public License:
* juniversalchardet (com.googlecode.juniversalchardet:juniversalchardet:1.0.3 - http://juniversalchardet.googlecode.com/)
* h2 (com.h2database:h2:1.4.187 - no url defined)
* H2 Database Engine (com.h2database:h2:1.4.180 - http://www.h2database.com)
* Javassist (org.javassist:javassist:3.16.1-GA - http://www.javassist.org/)
* Javassist (org.javassist:javassist:3.18.1-GA - http://www.javassist.org/)
* Rhino (rhino:js:1.6R7 - http://www.mozilla.org/rhino/)
@@ -411,14 +404,10 @@ https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines
* Reflections (org.reflections:reflections:0.9.9-RC1 - http://code.google.com/p/reflections/reflections/)
* XZ for Java (org.tukaani:xz:1.4 - http://tukaani.org/xz/java.html)
Similar to Apache License but with the acknowledgment clause removed:
The JSON License:
* JDOM (org.jdom:jdom:1.1.3 - http://www.jdom.org)
* JSON in Java (org.json:json:20180130 - https://github.com/douglascrockford/JSON-java)
The PostgreSQL License:
* PostgreSQL JDBC Driver - JDBC 4.2 (org.postgresql:postgresql:9.4.1211 - https://github.com/pgjdbc/pgjdbc)
license.txt:
* JPA 2.0 API (org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final - http://hibernate.org)
* PostgreSQL JDBC Driver - JDBC 4.1 (org.postgresql:postgresql:42.2.1.jre7 - https://github.com/pgjdbc/pgjdbc-parent-poms/pgjdbc-core-parent/pgjdbc-core-prevjre/postgresql)

31
NOTICE
View File

@@ -1,15 +1,28 @@
Licenses of Third-Party Libraries
=================================
Licensing Notice
DSpace uses third-party libraries which may be distributed under
different licenses than specified in our LICENSE file. Information
about these licenses is detailed in the LICENSES_THIRD_PARTY file at
the root of the source tree. You must agree to the terms of these
licenses, in addition to the DSpace source code license, in order to
use this software.
Fedora Commons joined with the DSpace Foundation and began operating under
Licensing Notices
=================
[July 2019] DuraSpace joined with LYRASIS (another 501(c)3 organization) in July 2019.
LYRASIS holds the copyrights of DuraSpace.
[July 2009] Fedora Commons joined with the DSpace Foundation and began operating under
the new name DuraSpace in July 2009. DuraSpace holds the copyrights of
the DSpace Foundation, Inc.
The DSpace Foundation, Inc. is a 501(c)3 corporation established in July 2007
with a mission to promote and advance the dspace platform enabling management,
access and preservation of digital works. The Foundation was able to transfer
the legal copyright from Hewlett-Packard Company (HP) and Massachusetts
Institute of Technology (MIT) to the DSpace Foundation in October 2007. Many
of the files in the source code may contain a copyright statement stating HP
and MIT possess the copyright, in these instances please note that the copy
[July 2007] The DSpace Foundation, Inc. is a 501(c)3 corporation established in July 2007
with a mission to promote and advance the dspace platform enabling management,
access and preservation of digital works. The Foundation was able to transfer
the legal copyright from Hewlett-Packard Company (HP) and Massachusetts
Institute of Technology (MIT) to the DSpace Foundation in October 2007. Many
of the files in the source code may contain a copyright statement stating HP
and MIT possess the copyright, in these instances please note that the copy
right has transferred to the DSpace foundation, and subsequently to DuraSpace.

49
README Normal file
View File

@@ -0,0 +1,49 @@
DSpace version information can be viewed online at
- https://wiki.lyrasis.org/display/DSDOC/
Documentation for the most recent stable release(s) may be downloaded
or viewed online at
- http://www.dspace.org/latest-release/
- https://wiki.lyrasis.org/display/DSDOC/
Installation instructions are to be found in that documentation.
In addition, a listing of all known contributors to DSpace software can be
found online at:
https://wiki.lyrasis.org/display/DSPACE/DSpaceContributors
Installation instructions for other versions may be different, so you
are encouraged to obtain the appropriate version of the Documentation
from the links above.
To obtain files from the repository and build, please see:
- https://github.com/DSpace/DSpace/
or just:
- git clone git://github.com/DSpace/DSpace.git
Please refer any further problems to the dspace-tech@googlegroups.com
mailing list.
- https://groups.google.com/d/forum/dspace-tech
Detailed Issue Tracking for DSpace is done in GitHub issues
- https://github.com/DSpace/DSpace/issues
To contribute to DSpace, please see:
- https://wiki.lyrasis.org/display/DSPACE/How+to+Contribute+to+DSpace
For more details about DSpace, including a list of service providers,
places to seek help, news articles and lists of other users, please see:
- http://www.dspace.org/
DSpace source code is freely available under a standard [BSD 3-Clause license](https://opensource.org/licenses/BSD-3-Clause).
The full license is available at http://www.dspace.org/license/

View File

@@ -1,85 +0,0 @@
# DSpace
## NOTE: The rest-tutorial branch has been created to support the [DSpace 7 REST documentation](https://dspace-labs.github.io/DSpace7RestTutorial/walkthrough/intro)
- This branch provides stable, referencable line numbers in code
[![Build Status](https://travis-ci.org/DSpace/DSpace.png?branch=master)](https://travis-ci.org/DSpace/DSpace)
[DSpace Documentation](https://wiki.duraspace.org/display/DSDOC/) |
[DSpace Releases](https://github.com/DSpace/DSpace/releases) |
[DSpace Wiki](https://wiki.duraspace.org/display/DSPACE/Home) |
[Support](https://wiki.duraspace.org/display/DSPACE/Support)
DSpace open source software is a turnkey repository application used by more than
2,000 organizations and institutions worldwide to provide durable access to digital resources.
For more information, visit http://www.dspace.org/
***
:warning: **Work on DSpace 7 has begun on our `master` branch.** This means that there is temporarily NO user interface on this `master` branch. DSpace 7 will feature a new, unified [Angular](https://angular.io/) user interface, along with an enhanced, rebuilt REST API. The latest status of this work can be found on the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) page. Additionally, the codebases can be found in the following places:
* DSpace 7 REST API work is occurring on the [`master` branch](https://github.com/DSpace/DSpace/tree/master/dspace-spring-rest) of this repository.
* The REST Contract is being documented at https://github.com/DSpace/Rest7Contract
* DSpace 7 Angular UI work is occurring at https://github.com/DSpace/dspace-angular
**If you would like to get involved in our DSpace 7 development effort, we welcome new contributors.** Just join one of our meetings or get in touch via Slack. See the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) wiki page for more info.
**If you are looking for the ongoing maintenance work for DSpace 6 (or prior releases)**, you can find that work on the corresponding maintenance branch (e.g. [`dspace-6_x`](https://github.com/DSpace/DSpace/tree/dspace-6_x)) in this repository.
***
## Downloads
The latest release of DSpace can be downloaded from the [DSpace website](http://www.dspace.org/latest-release/) or from [GitHub](https://github.com/DSpace/DSpace/releases).
Past releases are all available via GitHub at https://github.com/DSpace/DSpace/releases
## Documentation / Installation
Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.duraspace.org/display/DSDOC/).
The latest DSpace Installation instructions are available at:
https://wiki.duraspace.org/display/DSDOC6x/Installing+DSpace
Please be aware that, as a Java web application, DSpace requires a database (PostgreSQL or Oracle)
and a servlet container (usually Tomcat) in order to function.
More information about these and all other prerequisites can be found in the Installation instructions above.
## Contributing
DSpace is a community built and supported project. We do not have a centralized development or support team,
but have a dedicated group of volunteers who help us improve the software, documentation, resources, etc.
We welcome contributions of any type. Here's a few basic guides that provide suggestions for contributing to DSpace:
* [How to Contribute to DSpace](https://wiki.duraspace.org/display/DSPACE/How+to+Contribute+to+DSpace): How to contribute in general (via code, documentation, bug reports, expertise, etc)
* [Code Contribution Guidelines](https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines): How to give back code or contribute features, bug fixes, etc.
* [DSpace Community Advisory Team (DCAT)](https://wiki.duraspace.org/display/cmtygp/DSpace+Community+Advisory+Team): If you are not a developer, we also have an interest group specifically for repository managers. The DCAT group meets virtually, once a month, and sends open invitations to join their meetings via the [DCAT mailing list](https://groups.google.com/d/forum/DSpaceCommunityAdvisoryTeam).
We also encourage GitHub Pull Requests (PRs) at any time. Please see our [Development with Git](https://wiki.duraspace.org/display/DSPACE/Development+with+Git) guide for more info.
In addition, a listing of all known contributors to DSpace software can be
found online at: https://wiki.duraspace.org/display/DSPACE/DSpaceContributors
## Getting Help
DSpace provides public mailing lists where you can post questions or raise topics for discussion.
We welcome everyone to participate in these lists:
* [dspace-community@googlegroups.com](https://groups.google.com/d/forum/dspace-community) : General discussion about DSpace platform, announcements, sharing of best practices
* [dspace-tech@googlegroups.com](https://groups.google.com/d/forum/dspace-tech) : Technical support mailing list. See also our guide for [How to troubleshoot an error](https://wiki.duraspace.org/display/DSPACE/Troubleshoot+an+error).
* [dspace-devel@googlegroups.com](https://groups.google.com/d/forum/dspace-devel) : Developers / Development mailing list
Great Q&A is also available under the [DSpace tag on Stackoverflow](http://stackoverflow.com/questions/tagged/dspace)
Additional support options are listed at https://wiki.duraspace.org/display/DSPACE/Support
DSpace also has an active service provider network. If you'd rather hire a service provider to
install, upgrade, customize or host DSpace, then we recommend getting in touch with one of our
[Registered Service Providers](http://www.dspace.org/service-providers).
## Issue Tracker
The DSpace Issue Tracker can be found at: https://jira.duraspace.org/projects/DS/summary
## License
DSpace source code is freely available under a standard [BSD 3-Clause license](https://opensource.org/licenses/BSD-3-Clause).
The full license is available at http://www.dspace.org/license/

171
build.properties Normal file
View File

@@ -0,0 +1,171 @@
# DSpace build.properties
# This file should be customised to suit your build environment.
# Note that not all configuration is handled here, only the most common
# properties that tend to differ between build environments.
# For adjusting global settings or more complex settings, edit the relevant config file.
#
# IMPORTANT: Do not remove or comment out settings in build.properties
# When you edit the "build.properties" file (or a custom *.properties file),
# take care not to remove or comment out any settings. Doing so, may cause
# your final "dspace.cfg" file to be misconfigured with regards to that
# particular setting. Instead, if you wish to remove/disable a particular
# setting, just clear out its value. For example, if you don't want to be
# notified of new user registrations, ensure the "mail.registration.notify"
# setting has no value, e.g. "mail.registration.notify="
#
##########################
# SERVER CONFIGURATION #
##########################
# DSpace installation directory. This is the location where you want
# to install DSpace. NOTE: this value will be copied over to the
# "dspace.dir" setting in the final "dspace.cfg" file. It can be
# modified later on in your "dspace.cfg", if needed.
dspace.install.dir=/dspace
# DSpace host name - should match base URL. Do not include port number
dspace.hostname = localhost
# DSpace base host URL. Include port number etc.
dspace.baseUrl = http://localhost:8080
# The user interface you will be using for DSpace. Common usage is either xmlui or jspui
dspace.ui = xmlui
# Full link your end users will use to access DSpace. In most cases, this will be the baseurl followed by
# the context path to the UI you are using.
#
# Alternatively, you can use a url redirect or deploy the web application under the servlet container root.
# In this case, make sure to remove the /${dspace.ui} from the dspace.url property.
dspace.url = ${dspace.baseUrl}/${dspace.ui}
# Name of the site
dspace.name = DSpace at My University
# Solr server
solr.server=http://localhost:8080/solr
# Default language for metadata values
default.language = en_US
##########################
# DATABASE CONFIGURATION #
##########################
# Uncomment the appropriate block below for your database.
# postgres
db.driver=org.postgresql.Driver
db.url=jdbc:postgresql://localhost:5432/dspace
db.username=dspace
db.password=dspace
# oracle
#db.driver= oracle.jdbc.OracleDriver
#db.url=jdbc:oracle:thin:@//localhost:1521/xe
#db.username=dspace
#db.password=dspace
# Schema name - if your database contains multiple schemas, you can avoid
# problems with retrieving the definitions of duplicate object names by
# specifying the schema name that is used for DSpace.
# ORACLE USAGE NOTE: In Oracle, schema is equivalent to "username". This means
# specifying a "db.schema" is often unnecessary (i.e. you can leave it blank),
# UNLESS your Oracle DB Account (in db.username) has access to multiple schemas.
db.schema =
# Maximum number of DB connections in pool
db.maxconnections = 30
# Maximum time to wait before giving up if all connections in pool are busy (milliseconds)
db.maxwait = 5000
# Maximum number of idle connections in pool (-1 = unlimited)
db.maxidle = -1
# Determine if prepared statement should be cached. (default is true)
db.statementpool = true
# Specify a name for the connection pool (useful if you have multiple applications sharing Tomcat's dbcp)
# If not specified, defaults to 'dspacepool'
db.poolname = dspacepool
#######################
# EMAIL CONFIGURATION #
#######################
# SMTP mail server
mail.server = smtp.example.com
# SMTP mail server authentication username and password (if required)
# mail.server.username = myusername
# mail.server.password = mypassword
mail.server.username=
mail.server.password=
# SMTP mail server alternate port (defaults to 25)
mail.server.port = 25
# From address for mail
mail.from.address = dspace-noreply@myu.edu
# Currently limited to one recipient!
mail.feedback.recipient = dspace-help@myu.edu
# General site administration (Webmaster) e-mail
mail.admin = dspace-help@myu.edu
# Recipient for server errors and alerts
#mail.alert.recipient = email-address-here
mail.alert.recipient=
# Recipient for new user registration emails
#mail.registration.notify = email-address-here
mail.registration.notify=
########################
# HANDLE CONFIGURATION #
########################
# Canonical Handle URL prefix
#
# By default, DSpace is configured to use http://hdl.handle.net/
# as the canonical URL prefix when generating dc.identifier.uri
# during submission, and in the 'identifier' displayed in JSPUI
# item record pages.
#
# If you do not subscribe to CNRI's handle service, you can change this
# to match the persistent URL service you use, or you can force DSpace
# to use your site's URL, eg.
#handle.canonical.prefix = ${dspace.url}/handle/
#
# Note that this will not alter dc.identifer.uri metadata for existing
# items (only for subsequent submissions), but it will alter the URL
# in JSPUI's 'identifier' message on item record pages for existing items.
#
# If omitted, the canonical URL prefix will be http://hdl.handle.net/
handle.canonical.prefix = http://hdl.handle.net/
# CNRI Handle prefix
handle.prefix = 123456789
#######################
# PROXY CONFIGURATION #
#######################
# uncomment and specify both properties if proxy server required
# proxy server for external http requests - use regular hostname without port number
http.proxy.host =
# port number of proxy server
http.proxy.port =
#####################
# LOGLEVEL SETTINGS #
#####################
loglevel.other = INFO
# loglevel.other: Log level for other third-party tools/APIs used by DSpace
# Possible values (from most to least info): DEBUG, INFO, WARN, ERROR, FATAL
loglevel.dspace = INFO
# loglevel.dspace: Log level for all DSpace-specific code (org.dspace.*)
# Possible values (from most to least info): DEBUG, INFO, WARN, ERROR, FATAL

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.2//EN"
"http://checkstyle.sourceforge.net/dtds/suppressions_1_2.dtd">
<suppressions>
<!-- Temporarily suppress indentation checks for all Tests -->
<!-- TODO: We should have these turned on. But, currently there's a known bug with indentation checks
on JMockIt Expectations blocks and similar. See https://github.com/checkstyle/checkstyle/issues/3739 -->
<suppress checks="Indentation" files="src[/\\]test[/\\]java"/>
</suppressions>

View File

@@ -1,144 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
<!--
DSpace CodeStyle Requirements
1. 4-space indents for Java, and 2-space indents for XML. NO TABS ALLOWED.
2. K&R style braces required. Braces required on all blocks.
3. Do not use wildcard imports (e.g. import java.util.*). Duplicated or unused imports also not allowed.
4. Javadocs should exist for all public classes and methods. (Methods rule is unenforced at this time.) Keep it short and to the point
5. Maximum line length is 120 characters (except for long URLs, packages or imports)
6. No trailing spaces allowed (except in comments)
7. Tokens should be surrounded by whitespace (see http://checkstyle.sourceforge.net/config_whitespace.html#WhitespaceAround)
8. Each source file must include our license header (validated separately by license-maven-plugin, see pom.xml)
For more information on CheckStyle configurations below, see: http://checkstyle.sourceforge.net/checks.html
-->
<module name="Checker">
<!-- Configure checker to use UTF-8 encoding -->
<property name="charset" value="UTF-8"/>
<!-- Configure checker to run on files with these extensions -->
<property name="fileExtensions" value="java, properties, cfg, xml"/>
<!-- Suppression configurations in checkstyle-suppressions.xml in same directory -->
<module name="SuppressionFilter">
<property name="file" value="${checkstyle.suppressions.file}" default="checkstyle-suppressions.xml"/>
</module>
<!-- No tab characters ('\t') allowed in the source code -->
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
<property name="fileExtensions" value="java, properties, cfg, css, js, xml"/>
</module>
<!-- No Trailing Whitespace, except on lines that only have an asterisk (e.g. Javadoc comments) -->
<module name="RegexpSingleline">
<property name="format" value="(?&lt;!\*)\s+$|\*\s\s+$"/>
<property name="message" value="Line has trailing whitespace"/>
<property name="fileExtensions" value="java, properties, cfg, css, js, xml"/>
</module>
<!-- Allow individual lines of code to be excluded from these rules, if they are annotated
with @SuppressWarnings. See also SuppressWarningsHolder below -->
<module name="SuppressWarningsFilter" />
<!-- Check individual Java source files for specific rules -->
<module name="TreeWalker">
<!-- Maximum line length is 120 characters -->
<module name="LineLength">
<property name="max" value="120"/>
<!-- Only exceptions for packages, imports, URLs, and JavaDoc {@link} tags -->
<property name="ignorePattern" value="^package.*|^import.*|http://|https://|@link"/>
</module>
<!-- Highlight any TODO or FIXME comments in info messages -->
<module name="TodoComment">
<property name="severity" value="info"/>
<property name="format" value="(TODO)|(FIXME)"/>
</module>
<!-- Do not report errors on any lines annotated with @SuppressWarnings -->
<module name="SuppressWarningsHolder"/>
<!-- ##### Import statement requirements ##### -->
<!-- Star imports (e.g. import java.util.*) are NOT ALLOWED -->
<module name="AvoidStarImport"/>
<!-- Redundant import statements are NOT ALLOWED -->
<module name="RedundantImport"/>
<!-- Unused import statements are NOT ALLOWED -->
<module name="UnusedImports"/>
<!-- Ensure imports appear alphabetically and grouped -->
<module name="CustomImportOrder">
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="separateLineBetweenGroups" value="true"/>
<property name="customImportOrderRules" value="STATIC###STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE"/>
</module>
<!-- ##### Javadocs requirements ##### -->
<!-- Requirements for Javadocs for classes/interfaces -->
<module name="JavadocType">
<!-- All public classes/interfaces MUST HAVE Javadocs -->
<property name="scope" value="public"/>
<!-- Add an exception for anonymous inner classes -->
<property name="excludeScope" value="anoninner"/>
<!-- Ignore errors related to unknown tags -->
<property name="allowUnknownTags" value="true"/>
<!-- Allow params tags to be optional -->
<property name="allowMissingParamTags" value="false"/>
</module>
<!-- Requirements for Javadocs for methods -->
<module name="JavadocMethod">
<!-- All public methods MUST HAVE Javadocs -->
<!-- <property name="scope" value="public"/> -->
<!-- TODO: Above rule has been disabled because of large amount of missing public method Javadocs -->
<property name="scope" value="nothing"/>
<!-- Allow RuntimeExceptions to be undeclared -->
<property name="allowUndeclaredRTE" value="true"/>
<!-- Allow params, throws and return tags to be optional -->
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
</module>
<!-- ##### Requirements for K&R Style braces ##### -->
<!-- Code blocks MUST HAVE braces, even single line statements (if, while, etc) -->
<module name="NeedBraces"/>
<!-- Left braces should be at the end of current line (default value)-->
<module name="LeftCurly"/>
<!-- Right braces should be on start of a new line (default value) -->
<module name="RightCurly"/>
<!-- ##### Indentation / Whitespace requirements ##### -->
<!-- Require 4-space indentation (default value) -->
<module name="Indentation"/>
<!-- Whitespace should exist around all major tokens -->
<module name="WhitespaceAround">
<!-- However, make an exception for empty constructors, methods, types, etc. -->
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
</module>
<!-- Validate whitespace around Generics (angle brackets) per typical conventions
http://checkstyle.sourceforge.net/config_whitespace.html#GenericWhitespace -->
<module name="GenericWhitespace"/>
<!-- ##### Requirements for "switch" statements ##### -->
<!-- "switch" statements MUST have a "default" clause -->
<module name="MissingSwitchDefault"/>
<!-- "case" clauses in switch statements MUST include break, return, throw or continue -->
<module name="FallThrough"/>
<!-- ##### Other / Miscellaneous requirements ##### -->
<!-- Require utility classes do not have a public constructor -->
<module name="HideUtilityClassConstructor"/>
<!-- Require each variable declaration is its own statement on its own line -->
<module name="MultipleVariableDeclarations"/>
<!-- Each line of code can only include one statement -->
<module name="OneStatementPerLine"/>
<!-- Require that "catch" statements are not empty (must at least contain a comment) -->
<module name="EmptyCatchBlock"/>
</module>
</module>

43
docker-compose-cli.yml Normal file
View File

@@ -0,0 +1,43 @@
#
# 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/
#
version: "3.7"
services:
dspace-cli:
image: "dspace/dspace-cli:${DSPACE_VER:-dspace-5_x}"
container_name: dspace-cli
build:
context: .
dockerfile: Dockerfile.cli.jdk8
environment:
# Env vars with double underbars in names will be replaced with periods and written to dspace.cfg
# The defaul values for dspace.cfg will be provided here
# __D__ -> -
# __P__ -> .
- dspace__P__dir=/dspace
- db__P__url=jdbc:postgresql://dspacedb:5432/dspace
- dspace__P__hostname=localhost
- dspace__P__baseUrl=http://localhost:8080
- dspace__P__name=DSpace Started with Docker Compose
- solr__P__server=http://dspace:8080/solr
volumes:
- assetstore:/dspace/assetstore
entrypoint: /dspace/bin/parse_env_to_configs.sh
# Any commands passed here will be forwarded to /dspace/bin/dspace by parse_env_to_configs.sh (see its code)
command: help
networks:
- dspacenet
tty: true
stdin_open: true
volumes:
assetstore:
networks:
dspacenet:

64
docker-compose.yml Normal file
View File

@@ -0,0 +1,64 @@
#
# 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/
#
version: '3.7'
networks:
dspacenet:
services:
dspace:
container_name: dspace
depends_on:
- dspacedb
image: "${DOCKER_OWNER:-dspace}/dspace:${DSPACE_VER:-dspace-5_x-jdk8-test}"
environment:
# Env vars with double underbars in names will be replaced with periods and written to dspace.cfg
# The defaul values for dspace.cfg will be provided here
# __D__ -> -
# __P__ -> .
- dspace__P__dir=/dspace
- db__P__url=jdbc:postgresql://dspacedb:5432/dspace
- dspace__P__hostname=localhost
- dspace__P__baseUrl=http://localhost:8080
- dspace__P__name=DSpace Started with Docker Compose
- solr__P__server=http://localhost:8080/solr
build:
context: .
dockerfile: Dockerfile.jdk8-test
networks:
dspacenet:
ports:
- published: 8080
target: 8080
stdin_open: true
tty: true
volumes:
- ./dspace/src/main/docker-compose/xmlui.xconf:/dspace/config/xmlui.xconf
- ./dspace/src/main/docker-compose/parse_configs.sh:/dspace/bin/parse_configs.sh
- assetstore:/dspace/assetstore
- solr_authority:/dspace/solr/authority/data
- solr_oai:/dspace/solr/oai/data
- solr_search:/dspace/solr/search/data
- solr_statistics:/dspace/solr/statistics/data
dspacedb:
container_name: dspacedb
environment:
PGDATA: /pgdata
image: dspace/dspace-postgres-pgcrypto
networks:
dspacenet:
stdin_open: true
tty: true
volumes:
- pgdata:/pgdata
volumes:
assetstore:
pgdata:
solr_authority:
solr_oai:
solr_search:
solr_statistics:

View File

@@ -1,5 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dspace</groupId>
<artifactId>dspace-api</artifactId>
@@ -13,7 +12,7 @@
<parent>
<groupId>org.dspace</groupId>
<artifactId>dspace-parent</artifactId>
<version>7.0-SNAPSHOT</version>
<version>5.11</version>
<relativePath>..</relativePath>
</parent>
@@ -90,7 +89,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<version>1.9</version>
<executions>
<execution>
<phase>validate</phase>
@@ -104,7 +103,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.4</version>
<version>1.3</version>
<executions>
<execution>
<phase>validate</phase>
@@ -114,7 +113,6 @@
</execution>
</executions>
</plugin>
</plugins>
</build>
@@ -138,7 +136,6 @@
</plugins>
</build>
</profile>
<!-- If Unit Testing is enabled, then setup the Unit Test Environment.
See also the 'skiptests' profile in Parent POM. -->
<profile>
@@ -159,18 +156,6 @@
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<configuration>
<outputDirectory>${project.build.directory}/testing</outputDirectory>
<artifactItems>
<artifactItem>
<groupId>org.dspace</groupId>
<artifactId>dspace-parent</artifactId>
<version>${project.version}</version>
<type>zip</type>
<classifier>testEnvironment</classifier>
</artifactItem>
</artifactItems>
</configuration>
<executions>
<execution>
<id>setupTestEnvironment</id>
@@ -178,13 +163,18 @@
<goals>
<goal>unpack</goal>
</goals>
</execution>
<execution>
<id>setupIntegrationTestEnvironment</id>
<phase>pre-integration-test</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/testing</outputDirectory>
<artifactItems>
<artifactItem>
<groupId>org.dspace</groupId>
<artifactId>dspace-parent</artifactId>
<version>${project.version}</version>
<type>zip</type>
<classifier>testEnvironment</classifier>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
@@ -206,81 +196,86 @@
<executions>
<execution>
<id>setproperty</id>
<phase>generate-test-resources
</phase> <!-- XXX I think this should be 'initialize' - MHW -->
<phase>generate-test-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
println("Initializing Maven property 'agnostic.build.dir' to: " + project.properties['agnostic.build.dir']);
project.properties['agnostic.build.dir']=project.build.directory.replace(File.separator,'/');
println("Initializing Maven property 'agnostic.build.dir' to: " + project.properties['agnostic.build.dir']);
</source>
</configuration>
</execution>
</executions>
</plugin>
<!-- Run Unit Testing! This plugin just kicks off the tests (when enabled). -->
<!-- FileWeaver plugin is in charge of initializing & "weaving" together
the dspace.cfg file to be used by the Unit Testing environment.
It weaves two files, the default 'dspace.cfg' and 'dspace.cfg.more',
both of which are included in the testEnvironment.zip. -->
<plugin>
<groupId>edu.iu.ul.maven.plugins</groupId>
<artifactId>fileweaver</artifactId>
<version>1.0</version>
<configuration>
<outputs>
<output>
<outputPath>${agnostic.build.dir}/testing</outputPath>
<name>dspace.cfg.woven</name>
<parts>
<part>
<path>${agnostic.build.dir}/testing/dspace/config/dspace.cfg</path>
</part>
<part>
<path>${agnostic.build.dir}/testing/dspace.cfg.more</path>
</part>
</parts>
<properties>
<dspace.install.dir>${agnostic.build.dir}/testing/dspace</dspace.install.dir>
</properties>
</output>
</outputs>
</configuration>
<executions>
<execution>
<id>edit-dspace-cfg</id>
<phase>process-test-resources</phase>
<goals>
<goal>weave</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- The ant plugin below ensures that the final "woven" dspace.cfg
ends up in the /target/testing/dspace/ directory. This becomes
our final dspace.cfg for the Unit Testing environment. The dspace
service manager needs this "woven" configuration file when it starts.-->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>process-test-resources</phase>
<configuration>
<target>
<copy file="${agnostic.build.dir}/testing/dspace.cfg.woven" tofile="${agnostic.build.dir}/testing/dspace/config/dspace.cfg" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Run Unit/Integration Testing! This plugin just kicks off the tests (when enabled). -->
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<!-- Specify the dspace.dir to use for test environment -->
<!-- This system property is loaded by AbstractDSpaceTest to initialize the test environment -->
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
<!-- Turn off any DSpace logging -->
<dspace.log.init.disable>true</dspace.log.init.disable>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xml-maven-plugin</artifactId>
<version>1.0.1</version>
<executions>
<execution>
<id>validate-ALL-xml-and-xsl</id>
<phase>process-test-resources</phase>
<goals>
<goal>validate</goal>
</goals>
</execution>
</executions>
<configuration>
<validationSets>
<!-- validate ALL XML and XSL config files in the testing folder -->
<validationSet>
<dir>${agnostic.build.dir}/testing</dir>
<includes>
<include>**/*.xml</include>
<include>**/*.xsl</include>
<include>**/*.xconf</include>
</includes>
</validationSet>
<!-- validate ALL XML and XSL files throughout the project -->
<validationSet>
<dir>${root.basedir}</dir>
<includes>
<include>**/*.xml</include>
<include>**/*.xsl</include>
<include>**/*.xmap</include>
</includes>
</validationSet>
</validationSets>
</configuration>
</plugin>
<!-- Run Integration Testing! This plugin just kicks off the tests (when enabled). -->
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<!-- Specify the dspace.dir to use for test environment -->
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
<!-- Specify the dspace.cfg file to use for test environment -->
<dspace.configuration>${agnostic.build.dir}/testing/dspace/config/dspace.cfg</dspace.configuration>
<!-- Turn off any DSpace logging -->
<dspace.log.init.disable>true</dspace.log.init.disable>
</systemPropertyVariables>
@@ -292,36 +287,8 @@
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<exclusions>
<exclusion>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-cdi</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b10</version>
</dependency>
<dependencies>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>handle</artifactId>
@@ -338,20 +305,22 @@
<groupId>org.dspace.dependencies</groupId>
<artifactId>dspace-tm-extractors</artifactId>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
</dependency>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>apache-jena-libs</artifactId>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
@@ -366,12 +335,8 @@
<artifactId>commons-collections</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
@@ -387,8 +352,8 @@
<artifactId>commons-lang</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
@@ -414,7 +379,7 @@
</exclusions>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<groupId>jdom</groupId>
<artifactId>jdom</artifactId>
</dependency>
<dependency>
@@ -430,8 +395,12 @@
<artifactId>pdfbox</artifactId>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>jempbox</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
@@ -449,6 +418,10 @@
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
@@ -464,16 +437,10 @@
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<exclusions>
<exclusion>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<artifactId>xmlParserAPIs</artifactId>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
@@ -512,11 +479,10 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<groupId>org.databene</groupId>
<artifactId>contiperf</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.rometools</groupId>
<artifactId>rome-modules</artifactId>
@@ -526,30 +492,11 @@
<groupId>gr.ekt.bte</groupId>
<artifactId>bte-core</artifactId>
<version>0.9.3.5</version>
<exclusions>
<!-- A more recent version is retrieved from another dependency -->
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>gr.ekt.bte</groupId>
<artifactId>bte-io</artifactId>
<version>0.9.3.5</version>
<exclusions>
<!-- A more recent version is retrieved from another dependency -->
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
<!-- A more recent version is retrieved from another dependency -->
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
@@ -578,6 +525,7 @@
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>com.maxmind.geoip2</groupId>
@@ -591,13 +539,13 @@
<dependency>
<groupId>dnsjava</groupId>
<artifactId>dnsjava</artifactId>
<version>2.1.7</version>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.10.4</version>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
@@ -616,7 +564,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
<version>18.0</version>
</dependency>
@@ -647,7 +595,7 @@
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>4.0.3</version>
<version>3.0</version>
</dependency>
<!-- Google Analytics -->
@@ -683,6 +631,7 @@
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
@@ -707,7 +656,7 @@
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
<version>2.22.1</version>
</dependency>
<!-- S3 -->
<dependency>
@@ -734,6 +683,22 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<!-- For ORCID v2 integration -->
<dependency>
<groupId>org.dspace</groupId>
<artifactId>orcid-jaxb-api</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180130</version>
</dependency>
</dependencies>
</project>

View File

@@ -19,145 +19,147 @@ package org.apache.solr.handler.extraction;
/**
* The various Solr Parameters names to use when extracting content.
*
**/
public interface ExtractingParams {
/**
* Map all generated attribute names to field names with lowercase and underscores.
*/
public static final String LOWERNAMES = "lowernames";
/**
* Map all generated attribute names to field names with lowercase and underscores.
*/
public static final String LOWERNAMES = "lowernames";
/**
* if true, ignore TikaException (give up to extract text but index meta data)
*/
public static final String IGNORE_TIKA_EXCEPTION = "ignoreTikaException";
/**
* if true, ignore TikaException (give up to extract text but index meta data)
*/
public static final String IGNORE_TIKA_EXCEPTION = "ignoreTikaException";
/**
* The param prefix for mapping Tika metadata to Solr fields.
* <p>
* To map a field, add a name like:
* <pre>fmap.title=solr.title</pre>
*
* In this example, the tika "title" metadata value will be added to a Solr field named "solr.title"
*/
public static final String MAP_PREFIX = "fmap.";
/**
* The param prefix for mapping Tika metadata to Solr fields.
* <p/>
* To map a field, add a name like:
* <pre>fmap.title=solr.title</pre>
*
* In this example, the tika "title" metadata value will be added to a Solr field named "solr.title"
*
*
*/
public static final String MAP_PREFIX = "fmap.";
/**
* The boost value for the name of the field. The boost can be specified by a name mapping.
* <p>
* For example
* <pre>
* map.title=solr.title
* boost.solr.title=2.5
* </pre>
* will boost the solr.title field for this document by 2.5
*/
public static final String BOOST_PREFIX = "boost.";
/**
* The boost value for the name of the field. The boost can be specified by a name mapping.
* <p/>
* For example
* <pre>
* map.title=solr.title
* boost.solr.title=2.5
* </pre>
* will boost the solr.title field for this document by 2.5
*
*/
public static final String BOOST_PREFIX = "boost.";
/**
* Pass in literal values to be added to the document, as in
* <pre>
* literal.myField=Foo
* </pre>
*/
public static final String LITERALS_PREFIX = "literal.";
/**
* Pass in literal values to be added to the document, as in
* <pre>
* literal.myField=Foo
* </pre>
*
*/
public static final String LITERALS_PREFIX = "literal.";
/**
* Restrict the extracted parts of a document to be indexed
* by passing in an XPath expression. All content that satisfies the XPath expr.
* will be passed to the {@link org.apache.solr.handler.extraction.SolrContentHandler}.
* <p>
* See Tika's docs for what the extracted document looks like.
*
* @see #CAPTURE_ELEMENTS
*/
public static final String XPATH_EXPRESSION = "xpath";
/**
* Restrict the extracted parts of a document to be indexed
* by passing in an XPath expression. All content that satisfies the XPath expr.
* will be passed to the {@link SolrContentHandler}.
* <p/>
* See Tika's docs for what the extracted document looks like.
* <p/>
* @see #CAPTURE_ELEMENTS
*/
public static final String XPATH_EXPRESSION = "xpath";
/**
* Only extract and return the content, do not index it.
*/
public static final String EXTRACT_ONLY = "extractOnly";
/**
* Only extract and return the content, do not index it.
*/
public static final String EXTRACT_ONLY = "extractOnly";
/**
* Content output format if extractOnly is true. Default is "xml", alternative is "text".
*/
public static final String EXTRACT_FORMAT = "extractFormat";
/**
* Content output format if extractOnly is true. Default is "xml", alternative is "text".
*/
public static final String EXTRACT_FORMAT = "extractFormat";
/**
* Capture attributes separately according to the name of the element, instead of just adding them to the string
* buffer
*/
public static final String CAPTURE_ATTRIBUTES = "captureAttr";
/**
* Capture attributes separately according to the name of the element, instead of just adding them to the string buffer
*/
public static final String CAPTURE_ATTRIBUTES = "captureAttr";
/**
* Literal field values will by default override other values such as metadata and content. Set this to false to
* revert to pre-4.0 behaviour
*/
public static final String LITERALS_OVERRIDE = "literalsOverride";
/**
* Literal field values will by default override other values such as metadata and content. Set this to false to revert to pre-4.0 behaviour
*/
public static final String LITERALS_OVERRIDE = "literalsOverride";
/**
* Capture the specified fields (and everything included below it that isn't capture by some other capture field)
* separately from the default. This is different
* then the case of passing in an XPath expression.
* <p>
* The Capture field is based on the localName returned to the
* {@link org.apache.solr.handler.extraction.SolrContentHandler}
* by Tika, not to be confused by the mapped field. The field name can then
* be mapped into the index schema.
* <p>
* For instance, a Tika document may look like:
* <pre>
* &lt;html&gt;
* ...
* &lt;body&gt;
* &lt;p&gt;some text here. &lt;div&gt;more text&lt;/div&gt;&lt;/p&gt;
* Some more text
* &lt;/body&gt;
* </pre>
* By passing in the p tag, you could capture all P tags separately from the rest of the t
* Thus, in the example, the capture of the P tag would be: "some text here. more text"
*/
public static final String CAPTURE_ELEMENTS = "capture";
/**
* Capture the specified fields (and everything included below it that isn't capture by some other capture field) separately from the default. This is different
* then the case of passing in an XPath expression.
* <p/>
* The Capture field is based on the localName returned to the {@link SolrContentHandler}
* by Tika, not to be confused by the mapped field. The field name can then
* be mapped into the index schema.
* <p/>
* For instance, a Tika document may look like:
* <pre>
* &lt;html&gt;
* ...
* &lt;body&gt;
* &lt;p&gt;some text here. &lt;div&gt;more text&lt;/div&gt;&lt;/p&gt;
* Some more text
* &lt;/body&gt;
* </pre>
* By passing in the p tag, you could capture all P tags separately from the rest of the t
* Thus, in the example, the capture of the P tag would be: "some text here. more text"
*
*/
public static final String CAPTURE_ELEMENTS = "capture";
/**
* The type of the stream. If not specified, Tika will use mime type detection.
*/
public static final String STREAM_TYPE = "stream.type";
/**
* The type of the stream. If not specified, Tika will use mime type detection.
*/
public static final String STREAM_TYPE = "stream.type";
/**
* Optional. The file name. If specified, Tika can take this into account while
* guessing the MIME type.
*/
public static final String RESOURCE_NAME = "resource.name";
/**
* Optional. The file name. If specified, Tika can take this into account while
* guessing the MIME type.
*/
public static final String RESOURCE_NAME = "resource.name";
/**
* Optional. The password for this resource. Will be used instead of the rule based password lookup mechanisms
*/
public static final String RESOURCE_PASSWORD = "resource.password";
/**
* Optional. The password for this resource. Will be used instead of the rule based password lookup mechanisms
*/
public static final String RESOURCE_PASSWORD = "resource.password";
/**
* Optional. If specified, the prefix will be prepended to all Metadata, such that it would be possible
* to setup a dynamic field to automatically capture it
*/
public static final String UNKNOWN_FIELD_PREFIX = "uprefix";
/**
* Optional. If specified, the prefix will be prepended to all Metadata, such that it would be possible
* to setup a dynamic field to automatically capture it
*/
public static final String UNKNOWN_FIELD_PREFIX = "uprefix";
/**
* Optional. If specified and the name of a potential field cannot be determined, the default Field specified
* will be used instead.
*/
public static final String DEFAULT_FIELD = "defaultField";
/**
* Optional. If specified and the name of a potential field cannot be determined, the default Field specified
* will be used instead.
*/
public static final String DEFAULT_FIELD = "defaultField";
/**
* Optional. If specified, loads the file as a source for password lookups for Tika encrypted documents.
* <p>
* File format is Java properties format with one key=value per line.
* The key is evaluated as a regex against the file name, and the value is the password
* The rules are evaluated top-bottom, i.e. the first match will be used
* If you want a fallback password to be always used, supply a .*=&lt;defaultmypassword&gt; at the end
*/
public static final String PASSWORD_MAP_FILE = "passwordsFile";
/**
* Optional. If specified, loads the file as a source for password lookups for Tika encrypted documents.
* <p>
* File format is Java properties format with one key=value per line.
* The key is evaluated as a regex against the file name, and the value is the password
* The rules are evaluated top-bottom, i.e. the first match will be used
* If you want a fallback password to be always used, supply a .*=&lt;defaultmypassword&gt; at the end
*/
public static final String PASSWORD_MAP_FILE = "passwordsFile";
}

View File

@@ -9,47 +9,31 @@ package org.dspace.administer;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.collections.CollectionUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Community;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.handle.HandleManager;
import org.dspace.storage.rdbms.DatabaseManager;
/**
* A command-line tool for setting/removing community/sub-community
* relationships. Takes community DB Id or handle arguments as inputs.
*
*
* @author rrodgers
* @version $Revision$
*/
public class CommunityFiliator {
protected CommunityService communityService;
protected HandleService handleService;
public CommunityFiliator() {
communityService = ContentServiceFactory.getInstance().getCommunityService();
handleService = HandleServiceFactory.getInstance().getHandleService();
}
/**
* @param argv the command line arguments given
* @throws Exception if error
*/
public static void main(String[] argv) throws Exception {
public class CommunityFiliator
{
public static void main(String[] argv) throws Exception
{
// create an options object and populate it
CommandLineParser parser = new PosixParser();
@@ -57,11 +41,11 @@ public class CommunityFiliator {
options.addOption("s", "set", false, "set a parent/child relationship");
options.addOption("r", "remove", false,
"remove a parent/child relationship");
"remove a parent/child relationship");
options.addOption("p", "parent", true,
"parent community (handle or database ID)");
"parent community (handle or database ID)");
options.addOption("c", "child", true,
"child community (handle or databaseID)");
"child community (handle or databaseID)");
options.addOption("h", "help", false, "help");
CommandLine line = parser.parse(options, argv);
@@ -70,48 +54,57 @@ public class CommunityFiliator {
String parentID = null;
String childID = null;
if (line.hasOption('h')) {
if (line.hasOption('h'))
{
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("CommunityFiliator\n", options);
System.out
.println("\nestablish a relationship: CommunityFiliator -s -p parentID -c childID");
.println("\nestablish a relationship: CommunityFiliator -s -p parentID -c childID");
System.out
.println("remove a relationship: CommunityFiliator -r -p parentID -c childID");
.println("remove a relationship: CommunityFiliator -r -p parentID -c childID");
System.exit(0);
}
if (line.hasOption('s')) {
if (line.hasOption('s'))
{
command = "set";
}
if (line.hasOption('r')) {
if (line.hasOption('r'))
{
command = "remove";
}
if (line.hasOption('p')) { // parent
if (line.hasOption('p')) // parent
{
parentID = line.getOptionValue('p');
}
if (line.hasOption('c')) { // child
if (line.hasOption('c')) // child
{
childID = line.getOptionValue('c');
}
// now validate
// must have a command set
if (command == null) {
if (command == null)
{
System.out
.println("Error - must run with either set or remove (run with -h flag for details)");
.println("Error - must run with either set or remove (run with -h flag for details)");
System.exit(1);
}
if ("set".equals(command) || "remove".equals(command)) {
if (parentID == null) {
if ("set".equals(command) || "remove".equals(command))
{
if (parentID == null)
{
System.out.println("Error - a parentID must be specified (run with -h flag for details)");
System.exit(1);
}
if (childID == null) {
if (childID == null)
{
System.out.println("Error - a childID must be specified (run with -h flag for details)");
System.exit(1);
}
@@ -123,147 +116,146 @@ public class CommunityFiliator {
// we are superuser!
c.turnOffAuthorisationSystem();
try {
try
{
// validate and resolve the parent and child IDs into commmunities
Community parent = filiator.resolveCommunity(c, parentID);
Community child = filiator.resolveCommunity(c, childID);
if (parent == null) {
if (parent == null)
{
System.out.println("Error, parent community cannot be found: "
+ parentID);
+ parentID);
System.exit(1);
}
if (child == null) {
if (child == null)
{
System.out.println("Error, child community cannot be found: "
+ childID);
+ childID);
System.exit(1);
}
if ("set".equals(command)) {
if ("set".equals(command))
{
filiator.filiate(c, parent, child);
} else {
}
else
{
filiator.defiliate(c, parent, child);
}
} catch (SQLException sqlE) {
}
catch (SQLException sqlE)
{
System.out.println("Error - SQL exception: " + sqlE.toString());
} catch (AuthorizeException authE) {
}
catch (AuthorizeException authE)
{
System.out.println("Error - Authorize exception: "
+ authE.toString());
} catch (IOException ioE) {
+ authE.toString());
}
catch (IOException ioE)
{
System.out.println("Error - IO exception: " + ioE.toString());
}
}
/**
* @param c context
* @param parent parent Community
* @param child child community
* @throws SQLException if database error
* @throws AuthorizeException if authorize error
* @throws IOException if IO error
*/
public void filiate(Context c, Community parent, Community child)
throws SQLException, AuthorizeException, IOException {
throws SQLException, AuthorizeException, IOException
{
// check that a valid filiation would be established
// first test - proposed child must currently be an orphan (i.e.
// top-level)
Community childDad = CollectionUtils.isNotEmpty(child.getParentCommunities()) ? child.getParentCommunities()
.iterator().next() : null;
Community childDad = child.getParentCommunity();
if (childDad != null) {
if (childDad != null)
{
System.out.println("Error, child community: " + child.getID()
+ " already a child of: " + childDad.getID());
+ " already a child of: " + childDad.getID());
System.exit(1);
}
// second test - circularity: parent's parents can't include proposed
// child
List<Community> parentDads = parent.getParentCommunities();
Community[] parentDads = parent.getAllParents();
for (int i = 0; i < parentDads.size(); i++) {
if (parentDads.get(i).getID().equals(child.getID())) {
for (int i = 0; i < parentDads.length; i++)
{
if (parentDads[i].getID() == child.getID())
{
System.out
.println("Error, circular parentage - child is parent of parent");
.println("Error, circular parentage - child is parent of parent");
System.exit(1);
}
}
// everthing's OK
communityService.addSubcommunity(c, parent, child);
parent.addSubcommunity(child);
// complete the pending transaction
c.complete();
System.out.println("Filiation complete. Community: '" + parent.getID()
+ "' is parent of community: '" + child.getID() + "'");
+ "' is parent of community: '" + child.getID() + "'");
}
/**
* @param c context
* @param parent parent Community
* @param child child community
* @throws SQLException if database error
* @throws AuthorizeException if authorize error
* @throws IOException if IO error
*/
public void defiliate(Context c, Community parent, Community child)
throws SQLException, AuthorizeException, IOException {
throws SQLException, AuthorizeException, IOException
{
// verify that child is indeed a child of parent
List<Community> parentKids = parent.getSubcommunities();
Community[] parentKids = parent.getSubcommunities();
boolean isChild = false;
for (int i = 0; i < parentKids.size(); i++) {
if (parentKids.get(i).getID().equals(child.getID())) {
for (int i = 0; i < parentKids.length; i++)
{
if (parentKids[i].getID() == child.getID())
{
isChild = true;
break;
}
}
if (!isChild) {
if (!isChild)
{
System.out
.println("Error, child community not a child of parent community");
.println("Error, child community not a child of parent community");
System.exit(1);
}
// OK remove the mappings - but leave the community, which will become
// top-level
child.getParentCommunities().remove(parent);
parent.getSubcommunities().remove(child);
communityService.update(c, child);
communityService.update(c, parent);
DatabaseManager.updateQuery(c,
"DELETE FROM community2community WHERE parent_comm_id= ? "+
"AND child_comm_id= ? ", parent.getID(), child.getID());
// complete the pending transaction
c.complete();
System.out.println("Defiliation complete. Community: '" + child.getID()
+ "' is no longer a child of community: '" + parent.getID()
+ "'");
+ "' is no longer a child of community: '" + parent.getID()
+ "'");
}
/**
* Find a community by ID
*
* @param c context
* @param communityID community ID
* @return Community object
* @throws SQLException if database error
*/
protected Community resolveCommunity(Context c, String communityID)
throws SQLException {
private Community resolveCommunity(Context c, String communityID)
throws SQLException
{
Community community = null;
if (communityID.indexOf('/') != -1) {
if (communityID.indexOf('/') != -1)
{
// has a / must be a handle
community = (Community) handleService.resolveToObject(c,
communityID);
community = (Community) HandleManager.resolveToObject(c,
communityID);
// ensure it's a community
if ((community == null)
|| (community.getType() != Constants.COMMUNITY)) {
|| (community.getType() != Constants.COMMUNITY))
{
community = null;
}
} else {
community = communityService.find(c, UUID.fromString(communityID));
}
else
{
community = Community.find(c, Integer.parseInt(communityID));
}
return community;

View File

@@ -15,15 +15,13 @@ import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang.StringUtils;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.core.I18nUtil;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.GroupService;
/**
* A command-line tool for creating an initial administrator for setting up a
@@ -33,221 +31,238 @@ import org.dspace.eperson.service.GroupService;
* <P>
* Alternatively, it can be used to take the email, first name, last name and
* desired password as arguments thus:
*
*
* CreateAdministrator -e [email] -f [first name] -l [last name] -p [password]
*
* This is particularly convenient for automated deploy scripts that require an
*
* This is particularly convenient for automated deploy scripts that require an
* initial administrator, for example, before deployment can be completed
*
*
* @author Robert Tansley
* @author Richard Jones
*
* @version $Revision$
*/
public final class CreateAdministrator {
/**
* DSpace Context object
*/
private final Context context;
protected EPersonService ePersonService;
protected GroupService groupService;
public final class CreateAdministrator
{
/** DSpace Context object */
private final Context context;
/**
* For invoking via the command line. If called with no command line arguments,
* it will negotiate with the user for the administrator details
*
* @param argv the command line arguments given
* @throws Exception if error
*
* @param argv
* command-line arguments
*/
public static void main(String[] argv)
throws Exception {
CommandLineParser parser = new PosixParser();
Options options = new Options();
CreateAdministrator ca = new CreateAdministrator();
options.addOption("e", "email", true, "administrator email address");
options.addOption("f", "first", true, "administrator first name");
options.addOption("l", "last", true, "administrator last name");
options.addOption("c", "language", true, "administrator language");
options.addOption("p", "password", true, "administrator password");
CommandLine line = parser.parse(options, argv);
if (line.hasOption("e") && line.hasOption("f") && line.hasOption("l") &&
line.hasOption("c") && line.hasOption("p")) {
ca.createAdministrator(line.getOptionValue("e"),
line.getOptionValue("f"), line.getOptionValue("l"),
line.getOptionValue("c"), line.getOptionValue("p"));
} else {
ca.negotiateAdministratorDetails();
}
throws Exception
{
CommandLineParser parser = new PosixParser();
Options options = new Options();
CreateAdministrator ca = new CreateAdministrator();
options.addOption("e", "email", true, "administrator email address");
options.addOption("f", "first", true, "administrator first name");
options.addOption("l", "last", true, "administrator last name");
options.addOption("c", "language", true, "administrator language");
options.addOption("p", "password", true, "administrator password");
CommandLine line = parser.parse(options, argv);
if (line.hasOption("e") && line.hasOption("f") && line.hasOption("l") &&
line.hasOption("c") && line.hasOption("p"))
{
ca.createAdministrator(line.getOptionValue("e"),
line.getOptionValue("f"), line.getOptionValue("l"),
line.getOptionValue("c"), line.getOptionValue("p"));
}
else
{
ca.negotiateAdministratorDetails();
}
}
/**
/**
* constructor, which just creates and object with a ready context
*
* @throws Exception if error
*
* @throws Exception
*/
protected CreateAdministrator()
throws Exception {
context = new Context();
groupService = EPersonServiceFactory.getInstance().getGroupService();
ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
private CreateAdministrator()
throws Exception
{
context = new Context();
}
/**
* Method which will negotiate with the user via the command line to
* Method which will negotiate with the user via the command line to
* obtain the administrator's details
*
* @throws Exception if error
*
* @throws Exception
*/
protected void negotiateAdministratorDetails()
throws Exception {
private void negotiateAdministratorDetails()
throws Exception
{
Console console = System.console();
System.out.println("Creating an initial administrator account");
boolean dataOK = false;
String email = null;
String firstName = null;
String lastName = null;
System.out.println("Creating an initial administrator account");
boolean dataOK = false;
String email = null;
String firstName = null;
String lastName = null;
char[] password1 = null;
char[] password2 = null;
String language = I18nUtil.DEFAULTLOCALE.getLanguage();
while (!dataOK) {
System.out.print("E-mail address: ");
System.out.flush();
email = console.readLine();
if (!StringUtils.isBlank(email)) {
String language = I18nUtil.DEFAULTLOCALE.getLanguage();
while (!dataOK)
{
System.out.print("E-mail address: ");
System.out.flush();
email = console.readLine();
if (!StringUtils.isBlank(email))
{
email = email.trim();
} else {
}
else
{
System.out.println("Please provide an email address.");
continue;
}
System.out.print("First name: ");
System.out.flush();
firstName = console.readLine();
System.out.print("First name: ");
System.out.flush();
firstName = console.readLine();
if (firstName != null) {
if (firstName != null)
{
firstName = firstName.trim();
}
System.out.print("Last name: ");
System.out.flush();
lastName = console.readLine();
System.out.print("Last name: ");
System.out.flush();
lastName = console.readLine();
if (lastName != null) {
if (lastName != null)
{
lastName = lastName.trim();
}
if (ConfigurationManager.getProperty("webui.supported.locales") != null) {
System.out.println("Select one of the following languages: " + ConfigurationManager
.getProperty("webui.supported.locales"));
if (ConfigurationManager.getProperty("webui.supported.locales") != null)
{
System.out.println("Select one of the following languages: " + ConfigurationManager.getProperty("webui.supported.locales"));
System.out.print("Language: ");
System.out.flush();
language = console.readLine();
language = console.readLine();
if (language != null) {
if (language != null)
{
language = language.trim();
language = I18nUtil.getSupportedLocale(new Locale(language)).getLanguage();
}
}
System.out.println("Password will not display on screen.");
System.out.print("Password: ");
System.out.flush();
System.out.println("Password will not display on screen.");
System.out.print("Password: ");
System.out.flush();
password1 = console.readPassword();
System.out.print("Again to confirm: ");
System.out.flush();
password2 = console.readPassword();
password1 = console.readPassword();
System.out.print("Again to confirm: ");
System.out.flush();
password2 = console.readPassword();
//TODO real password validation
if (password1.length > 1 && Arrays.equals(password1, password2)) {
// password OK
System.out.print("Is the above data correct? (y or n): ");
System.out.flush();
if (password1.length > 1 && Arrays.equals(password1, password2))
{
// password OK
System.out.print("Is the above data correct? (y or n): ");
System.out.flush();
String s = console.readLine();
String s = console.readLine();
if (s != null) {
if (s != null)
{
s = s.trim();
if (s.toLowerCase().startsWith("y")) {
if (s.toLowerCase().startsWith("y"))
{
dataOK = true;
}
}
} else {
System.out.println("Passwords don't match");
}
}
// if we make it to here, we are ready to create an administrator
createAdministrator(email, firstName, lastName, language, String.valueOf(password1));
}
else
{
System.out.println("Passwords don't match");
}
}
// if we make it to here, we are ready to create an administrator
createAdministrator(email, firstName, lastName, language, String.valueOf(password1));
//Cleaning arrays that held password
Arrays.fill(password1, ' ');
Arrays.fill(password2, ' ');
}
/**
* Create the administrator with the given details. If the user
* already exists then they are simply upped to administrator status
*
* @param email the email for the user
* @param first user's first name
* @param last user's last name
*
* @param email the email for the user
* @param first user's first name
* @param last user's last name
* @param language preferred language
* @param pw desired password
* @throws Exception if error
* @param pw desired password
*
* @throws Exception
*/
protected void createAdministrator(String email, String first, String last,
String language, String pw)
throws Exception {
// Of course we aren't an administrator yet so we need to
// circumvent authorisation
context.turnOffAuthorisationSystem();
// Find administrator group
Group admins = groupService.findByName(context, Group.ADMIN);
if (admins == null) {
throw new IllegalStateException("Error, no admin group (group 1) found");
}
// Create the administrator e-person
EPerson eperson = ePersonService.findByEmail(context, email);
private void createAdministrator(String email, String first, String last,
String language, String pw)
throws Exception
{
// Of course we aren't an administrator yet so we need to
// circumvent authorisation
context.turnOffAuthorisationSystem();
// Find administrator group
Group admins = Group.find(context, 1);
if (admins == null)
{
throw new IllegalStateException("Error, no admin group (group 1) found");
}
// Create the administrator e-person
EPerson eperson = EPerson.findByEmail(context,email);
// check if the email belongs to a registered user,
// if not create a new user with this email
if (eperson == null) {
eperson = ePersonService.create(context);
if (eperson == null)
{
eperson = EPerson.create(context);
eperson.setEmail(email);
eperson.setCanLogIn(true);
eperson.setRequireCertificate(false);
eperson.setSelfRegistered(false);
}
eperson.setLastName(context, last);
eperson.setFirstName(context, first);
eperson.setLanguage(context, language);
ePersonService.setPassword(eperson, pw);
ePersonService.update(context, eperson);
groupService.addMember(context, admins, eperson);
groupService.update(context, admins);
context.complete();
System.out.println("Administrator account created");
eperson.setLastName(last);
eperson.setFirstName(first);
eperson.setLanguage(language);
eperson.setPassword(pw);
eperson.update();
admins.addMember(eperson);
admins.update();
context.complete();
System.out.println("Administrator account created");
}
}

View File

@@ -0,0 +1,287 @@
/**
* 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.administer;
import java.io.IOException;
import java.sql.SQLException;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.NonUniqueMetadataException;
import org.dspace.core.Context;
/**
* Class representing a particular Dublin Core metadata type, with various
* utility methods. In general, only used for manipulating the registry of
* Dublin Core types in the system, so most users will not need this.
*
* <p>
* The DCType implementation has been deprecated, please use MetadataManager,
* MetadataSchema and MetadataField instead. For backward compatibility the this
* implementation has been updated to transparently call the new classes.
* </p>
*
* @author Robert Tansley
* @author Martin Hald
* @version $Revision$
* @deprecated
*/
public class DCType
{
/** Our context */
private Context ourContext;
/** The matching metadata field */
private MetadataField field = new MetadataField();
/**
* Create a DCType from an existing metadata field.
*
* @param context
* @param field
* @deprecated
*/
public DCType(Context context, MetadataField field)
{
this.ourContext = context;
this.field = field;
}
/**
* Default constructor.
*
* @param context
* @deprecated
*/
public DCType(Context context)
{
this.ourContext = context;
}
/**
* Utility method for quick access to an element and qualifier given the
* type ID.
*
* @param context
* context, in case DC types need to be read in from DB
* @param id
* the DC type ID
* @return a two-String array, string 0 is the element, string 1 is the
* qualifier
* @deprecated
*/
public static String[] quickFind(Context context, int id)
throws SQLException
{
MetadataField field = MetadataField.find(context, id);
String[] result = new String[2];
if (field == null)
{
return result;
}
else
{
result[0] = field.getElement();
result[1] = field.getQualifier();
return result;
}
}
/**
* Get a metadata field from the database.
*
* @param context
* DSpace context object
* @param id
* ID of the dublin core type
*
* @return the metadata field, or null if the ID is invalid.
* @deprecated
*/
public static DCType find(Context context, int id) throws SQLException
{
MetadataField field = MetadataField.find(context, id);
return new DCType(context, field);
}
/**
* Find a given Dublin Core type. Returns <code>null</code> if the Dublin
* Core type doesn't exist.
*
* @param context
* the DSpace context to use
* @param element
* the element to find
* @param qualifier
* the qualifier, or <code>null</code> to find an unqualified
* type
*
* @return the Dublin Core type, or <code>null</code> if there isn't a
* corresponding type in the registry
* @throws AuthorizeException
* @deprecated
*/
public static DCType findByElement(Context context, String element,
String qualifier) throws SQLException, AuthorizeException
{
MetadataField field = MetadataField.findByElement(context,
MetadataSchema.DC_SCHEMA_ID, element, qualifier);
if (field == null)
{
return null;
}
else
{
return new DCType(context, field);
}
}
/**
* Retrieve all Dublin Core types from the registry
*
* @return an array of all the Dublin Core types
* @deprecated
*/
public static DCType[] findAll(Context context) throws SQLException
{
MetadataField field[] = MetadataField.findAll(context);
DCType[] typeArray = new DCType[field.length];
for (int ii = 0; ii < field.length; ii++)
{
typeArray[ii] = new DCType(context, field[ii]);
}
// Return the array
return typeArray;
}
/**
* Create a new Dublin Core type
*
* @param context
* DSpace context object
* @return the newly created DCType
* @throws NonUniqueMetadataException
* @throws IOException
* @deprecated
*/
public static DCType create(Context context) throws SQLException,
AuthorizeException, IOException, NonUniqueMetadataException
{
MetadataField field = new MetadataField();
field.setSchemaID(MetadataSchema.DC_SCHEMA_ID);
field.create(context);
return new DCType(context, field);
}
/**
* Delete this DC type. This won't work if there are any DC values in the
* database of this type - they need to be updated first. An
* <code>SQLException</code> (referential integrity violation) will be
* thrown in this case.
* @deprecated
*/
public void delete() throws SQLException, AuthorizeException
{
field.delete(ourContext);
}
/**
* Get the internal identifier of this metadata field
*
* @return the internal identifier
*/
public int getID()
{
return field.getFieldID();
}
/**
* Get the DC element
*
* @return the element
*/
public String getElement()
{
return field.getElement();
}
/**
* Set the DC element
*
* @param s
* the new element
*/
public void setElement(String s)
{
field.setElement(s);
}
/**
* Get the DC qualifier, if any.
*
* @return the DC qualifier, or <code>null</code> if this is an
* unqualified element
*/
public String getQualifier()
{
return field.getQualifier();
}
/**
* Set the DC qualifier
*
* @param s
* the DC qualifier, or <code>null</code> if this is an
* unqualified element
*/
public void setQualifier(String s)
{
field.setQualifier(s);
}
/**
* Get the scope note - information about the DC type and its use
*
* @return the scope note
*/
public String getScopeNote()
{
return field.getScopeNote();
}
/**
* Set the scope note
*
* @param s
* the new scope note
*/
public void setScopeNote(String s)
{
field.setScopeNote(s);
}
/**
* Update the dublin core registry
*
* @throws IOException
* @throws NonUniqueMetadataException
* @deprecated
*/
public void update() throws SQLException, AuthorizeException,
NonUniqueMetadataException, IOException
{
field.update(ourContext);
}
}

View File

@@ -12,7 +12,6 @@ import java.io.FileWriter;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.cli.CommandLine;
@@ -25,9 +24,6 @@ import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.core.Context;
import org.xml.sax.SAXException;
@@ -37,75 +33,59 @@ import org.xml.sax.SAXException;
*
* This class creates an xml document as passed in the arguments and
* from the metadata schemas for the repository.
*
*
* The form of the XML is as follows
* {@code
*
* <metadata-schemas>
* <schema>
* <name>dc</name>
* <namespace>http://dublincore.org/documents/dcmi-terms/</namespace>
* </schema>
* <schema>
* <name>dc</name>
* <namespace>http://dublincore.org/documents/dcmi-terms/</namespace>
* </schema>
* </metadata-schemas>
* }
*/
public class MetadataExporter {
protected static MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance()
.getMetadataSchemaService();
protected static MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance()
.getMetadataFieldService();
public class MetadataExporter
{
/**
* Default constructor
* @param args
* @throws ParseException
* @throws SAXException
* @throws IOException
* @throws SQLException
* @throws RegistryExportException
*/
private MetadataExporter() { }
/**
* @param args commandline arguments
* @throws ParseException if parser error
* @throws SAXException if XML parse error
* @throws IOException if IO error
* @throws SQLException if database error
* @throws RegistryExportException if export error
*/
public static void main(String[] args)
throws ParseException, SQLException, IOException, SAXException, RegistryExportException {
public static void main(String[] args) throws ParseException, SQLException, IOException, SAXException, RegistryExportException
{
// create an options object and populate it
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("f", "file", true, "output xml file for registry");
options.addOption("f", "file", true, "output xml file for registry");
options.addOption("s", "schema", true, "the name of the schema to export");
CommandLine line = parser.parse(options, args);
String file = null;
String file = null;
String schema = null;
if (line.hasOption('f')) {
file = line.getOptionValue('f');
} else {
if (line.hasOption('f'))
{
file = line.getOptionValue('f');
}
else
{
usage();
System.exit(0);
}
if (line.hasOption('s')) {
if (line.hasOption('s'))
{
schema = line.getOptionValue('s');
}
saveRegistry(file, schema);
}
/**
* Save a registry to a filepath
*
* @param file filepath
* @param schema schema definition to save
* @throws SQLException if database error
* @throws IOException if IO error
* @throws SAXException if XML error
* @throws RegistryExportException if export error
*/
public static void saveRegistry(String file, String schema)
throws SQLException, IOException, SAXException, RegistryExportException {
public static void saveRegistry(String file, String schema) throws SQLException, IOException, SAXException, RegistryExportException
{
// create a context
Context context = new Context();
context.turnOffAuthorisationSystem();
@@ -113,102 +93,113 @@ public class MetadataExporter {
OutputFormat xmlFormat = new OutputFormat(Method.XML, "UTF-8", true);
xmlFormat.setLineWidth(120);
xmlFormat.setIndent(4);
XMLSerializer xmlSerializer = new XMLSerializer(new BufferedWriter(new FileWriter(file)), xmlFormat);
// XMLSerializer xmlSerializer = new XMLSerializer(System.out, xmlFormat);
xmlSerializer.startDocument();
xmlSerializer.startElement("dspace-dc-types", null);
// Save the schema definition(s)
saveSchema(context, xmlSerializer, schema);
List<MetadataField> mdFields = null;
MetadataField[] mdFields = null;
// If a single schema has been specified
if (schema != null && !"".equals(schema)) {
if (schema != null && !"".equals(schema))
{
// Get the id of that schema
MetadataSchema mdSchema = metadataSchemaService.find(context, schema);
if (mdSchema == null) {
MetadataSchema mdSchema = MetadataSchema.find(context, schema);
if (mdSchema == null)
{
throw new RegistryExportException("no schema to export");
}
// Get the metadata fields only for the specified schema
mdFields = metadataFieldService.findAllInSchema(context, mdSchema);
} else {
// Get the metadata fields for all the schemas
mdFields = metadataFieldService.findAll(context);
mdFields = MetadataField.findAllInSchema(context, mdSchema.getSchemaID());
}
else
{
// Get the metadata fields for all the schemas
mdFields = MetadataField.findAll(context);
}
// Output the metadata fields
for (MetadataField mdField : mdFields) {
for (MetadataField mdField : mdFields)
{
saveType(context, xmlSerializer, mdField);
}
xmlSerializer.endElement("dspace-dc-types");
xmlSerializer.endDocument();
// abort the context, as we shouldn't have changed it!!
context.abort();
}
/**
* Serialize the schema registry. If the parameter 'schema' is null or empty, save all schemas
*
* @param context DSpace Context
* @param xmlSerializer XML serializer
* @param schema schema (may be null to save all)
* @throws SQLException if database error
* @throws SAXException if XML error
* @throws RegistryExportException if export error
* @param context
* @param xmlSerializer
* @param schema
* @throws SQLException
* @throws SAXException
* @throws RegistryExportException
*/
public static void saveSchema(Context context, XMLSerializer xmlSerializer, String schema)
throws SQLException, SAXException, RegistryExportException {
if (schema != null && !"".equals(schema)) {
public static void saveSchema(Context context, XMLSerializer xmlSerializer, String schema) throws SQLException, SAXException, RegistryExportException
{
if (schema != null && !"".equals(schema))
{
// Find a single named schema
MetadataSchema mdSchema = metadataSchemaService.find(context, schema);
MetadataSchema mdSchema = MetadataSchema.find(context, schema);
saveSchema(xmlSerializer, mdSchema);
} else {
}
else
{
// Find all schemas
List<MetadataSchema> mdSchemas = metadataSchemaService.findAll(context);
for (MetadataSchema mdSchema : mdSchemas) {
MetadataSchema[] mdSchemas = MetadataSchema.findAll(context);
for (MetadataSchema mdSchema : mdSchemas)
{
saveSchema(xmlSerializer, mdSchema);
}
}
}
/**
* Serialize a single schema (namespace) registry entry
*
* @param xmlSerializer XML serializer
* @param mdSchema DSpace metadata schema
* @throws SAXException if XML error
* @throws RegistryExportException if export error
*
* @param xmlSerializer
* @param mdSchema
* @throws SAXException
* @throws RegistryExportException
*/
private static void saveSchema(XMLSerializer xmlSerializer, MetadataSchema mdSchema)
throws SAXException, RegistryExportException {
private static void saveSchema(XMLSerializer xmlSerializer, MetadataSchema mdSchema) throws SAXException, RegistryExportException
{
// If we haven't got a schema, it's an error
if (mdSchema == null) {
if (mdSchema == null)
{
throw new RegistryExportException("no schema to export");
}
String name = mdSchema.getName();
String name = mdSchema.getName();
String namespace = mdSchema.getNamespace();
if (name == null || "".equals(name)) {
if (name == null || "".equals(name))
{
System.out.println("name is null, skipping");
return;
}
if (namespace == null || "".equals(namespace)) {
if (namespace == null || "".equals(namespace))
{
System.out.println("namespace is null, skipping");
return;
}
// Output the parent tag
xmlSerializer.startElement("dc-schema", null);
// Output the schema name
xmlSerializer.startElement("name", null);
xmlSerializer.characters(name.toCharArray(), 0, name.length());
@@ -221,25 +212,26 @@ public class MetadataExporter {
xmlSerializer.endElement("dc-schema");
}
/**
* Serialize a single metadata field registry entry to xml
*
* @param context DSpace context
* @param xmlSerializer xml serializer
* @param mdField DSpace metadata field
* @throws SAXException if XML error
* @throws RegistryExportException if export error
* @throws SQLException if database error
* @throws IOException if IO error
*
* @param context
* @param xmlSerializer
* @param mdField
* @throws SAXException
* @throws RegistryExportException
* @throws SQLException
* @throws IOException
*/
private static void saveType(Context context, XMLSerializer xmlSerializer, MetadataField mdField)
throws SAXException, RegistryExportException, SQLException, IOException {
private static void saveType(Context context, XMLSerializer xmlSerializer, MetadataField mdField) throws SAXException, RegistryExportException, SQLException, IOException
{
// If we haven't been given a field, it's an error
if (mdField == null) {
if (mdField == null)
{
throw new RegistryExportException("no field to export");
}
// Get the data from the metadata field
String schemaName = getSchemaName(context, mdField);
String element = mdField.getElement();
@@ -247,7 +239,8 @@ public class MetadataExporter {
String scopeNote = mdField.getScopeNote();
// We must have a schema and element
if (schemaName == null || element == null) {
if (schemaName == null || element == null)
{
throw new RegistryExportException("incomplete field information");
}
@@ -265,64 +258,68 @@ public class MetadataExporter {
xmlSerializer.endElement("element");
// Output the qualifier, if present
if (qualifier != null) {
if (qualifier != null)
{
xmlSerializer.startElement("qualifier", null);
xmlSerializer.characters(qualifier.toCharArray(), 0, qualifier.length());
xmlSerializer.endElement("qualifier");
} else {
}
else
{
xmlSerializer.comment("unqualified");
}
// Output the scope note, if present
if (scopeNote != null) {
if (scopeNote != null)
{
xmlSerializer.startElement("scope_note", null);
xmlSerializer.characters(scopeNote.toCharArray(), 0, scopeNote.length());
xmlSerializer.endElement("scope_note");
} else {
}
else
{
xmlSerializer.comment("no scope note");
}
xmlSerializer.endElement("dc-type");
}
static Map<Integer, String> schemaMap = new HashMap<Integer, String>();
/**
* Helper method to retrieve a schema name for the field.
* Caches the name after looking up the id.
*
* @param context DSpace Context
* @param mdField DSpace metadata field
* @return name of schema
* @throws SQLException if database error
* @throws RegistryExportException if export error
*/
private static String getSchemaName(Context context, MetadataField mdField)
throws SQLException, RegistryExportException {
static Map<Integer, String> schemaMap = new HashMap<Integer, String>();
private static String getSchemaName(Context context, MetadataField mdField) throws SQLException, RegistryExportException
{
// Get name from cache
String name = schemaMap.get(mdField.getMetadataSchema().getID());
String name = schemaMap.get(Integer.valueOf(mdField.getSchemaID()));
if (name == null) {
if (name == null)
{
// Name not retrieved before, so get the schema now
MetadataSchema mdSchema = metadataSchemaService.find(context, mdField.getMetadataSchema().getID());
if (mdSchema != null) {
MetadataSchema mdSchema = MetadataSchema.find(context, mdField.getSchemaID());
if (mdSchema != null)
{
name = mdSchema.getName();
schemaMap.put(mdSchema.getID(), name);
} else {
schemaMap.put(Integer.valueOf(mdSchema.getSchemaID()), name);
}
else
{
// Can't find the schema
throw new RegistryExportException("Can't get schema name for field");
}
}
return name;
}
/**
* Print the usage message to stdout
*/
public static void usage() {
public static void usage()
{
String usage = "Use this class with the following options:\n" +
" -f <xml output file> : specify the output file for the schemas\n" +
" -s <schema> : name of the schema to export\n";
" -f <xml output file> : specify the output file for the schemas\n" +
" -s <schema> : name of the schema to export\n";
System.out.println(usage);
}
}

View File

@@ -9,6 +9,7 @@ package org.dspace.administer;
import java.io.IOException;
import java.sql.SQLException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
@@ -17,92 +18,73 @@ import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.NonUniqueMetadataException;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.core.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* @author Richard Jones
*
* This class takes an xml document as passed in the arguments and
* uses it to create metadata elements in the Metadata Registry if
* uses it to create metadata elements in the Metadata Registry if
* they do not already exist
*
*
* The format of the XML file is as follows:
*
* {@code
*
* <dspace-dc-types>
* <dc-type>
* <schema>icadmin</schema>
* <element>status</element>
* <qualifier>dateset</qualifier>
* <scope_note>the workflow status of an item</scope_note>
* </dc-type>
*
* [....]
*
* <dc-type>
* <schema>icadmin</schema>
* <element>status</element>
* <qualifier>dateset</qualifier>
* <scope_note>the workflow status of an item</scope_note>
* </dc-type>
*
* [....]
*
* </dspace-dc-types>
* }
*/
public class MetadataImporter {
protected static MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance()
.getMetadataSchemaService();
protected static MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance()
.getMetadataFieldService();
/**
* logging category
*/
public class MetadataImporter
{
/** logging category */
private static final Logger log = LoggerFactory.getLogger(MetadataImporter.class);
/**
* Default constructor
*/
private MetadataImporter() { }
/**
* main method for reading user input from the command line
*
* @param args the command line arguments given
* @throws ParseException if parse error
* @throws SQLException if database error
* @throws IOException if IO error
* @throws TransformerException if transformer error
* @throws ParserConfigurationException if config error
* @throws AuthorizeException if authorization error
* @throws SAXException if parser error
* @throws NonUniqueMetadataException if duplicate metadata
* @throws RegistryImportException if import fails
**/
/**
* main method for reading user input from the command line
*/
public static void main(String[] args)
throws ParseException, SQLException, IOException, TransformerException,
ParserConfigurationException, AuthorizeException, SAXException,
NonUniqueMetadataException, RegistryImportException {
throws ParseException, SQLException, IOException, TransformerException,
ParserConfigurationException, AuthorizeException, SAXException,
NonUniqueMetadataException, RegistryImportException
{
boolean forceUpdate = false;
// create an options object and populate it
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("f", "file", true, "source xml file for DC fields");
options.addOption("u", "update", false, "update an existing schema");
CommandLine line = parser.parse(options, args);
String file = null;
if (line.hasOption('f')) {
if (line.hasOption('f'))
{
file = line.getOptionValue('f');
} else {
}
else
{
usage();
System.exit(0);
}
@@ -110,27 +92,20 @@ public class MetadataImporter {
forceUpdate = line.hasOption('u');
loadRegistry(file, forceUpdate);
}
/**
* Load the data from the specified file path into the database
*
* @param file the file path containing the source data
* @param forceUpdate whether to force update
* @throws SQLException if database error
* @throws IOException if IO error
* @throws TransformerException if transformer error
* @throws ParserConfigurationException if config error
* @throws AuthorizeException if authorization error
* @throws SAXException if parser error
* @throws NonUniqueMetadataException if duplicate metadata
* @throws RegistryImportException if import fails
*
* @param file the file path containing the source data
*/
public static void loadRegistry(String file, boolean forceUpdate)
throws SQLException, IOException, TransformerException, ParserConfigurationException,
AuthorizeException, SAXException, NonUniqueMetadataException, RegistryImportException {
throws SQLException, IOException, TransformerException, ParserConfigurationException,
AuthorizeException, SAXException, NonUniqueMetadataException, RegistryImportException
{
Context context = null;
try {
try
{
// create a context
context = new Context();
context.turnOffAuthorisationSystem();
@@ -142,7 +117,8 @@ public class MetadataImporter {
NodeList schemaNodes = XPathAPI.selectNodeList(document, "/dspace-dc-types/dc-schema");
// Add each one as a new format to the registry
for (int i = 0; i < schemaNodes.getLength(); i++) {
for (int i = 0; i < schemaNodes.getLength(); i++)
{
Node n = schemaNodes.item(i);
loadSchema(context, n, forceUpdate);
}
@@ -151,95 +127,101 @@ public class MetadataImporter {
NodeList typeNodes = XPathAPI.selectNodeList(document, "/dspace-dc-types/dc-type");
// Add each one as a new format to the registry
for (int i = 0; i < typeNodes.getLength(); i++) {
for (int i = 0; i < typeNodes.getLength(); i++)
{
Node n = typeNodes.item(i);
loadType(context, n);
}
context.restoreAuthSystemState();
context.complete();
} finally {
// Clean up our context, if it still exists & it was never completed
if (context != null && context.isValid()) {
}
finally
{
// Clean up our context, if it still exists & it was never completed
if(context!=null && context.isValid())
context.abort();
}
}
}
/**
* Process a node in the metadata registry XML file. If the
* schema already exists, it will not be recreated
*
* @param context DSpace context object
* @param node the node in the DOM tree
* @throws SQLException if database error
* @throws IOException if IO error
* @throws TransformerException if transformer error
* @throws AuthorizeException if authorization error
* @throws NonUniqueMetadataException if duplicate metadata
* @throws RegistryImportException if import fails
*
* @param context
* DSpace context object
* @param node
* the node in the DOM tree
* @throws NonUniqueMetadataException
*/
private static void loadSchema(Context context, Node node, boolean updateExisting)
throws SQLException, IOException, TransformerException,
AuthorizeException, NonUniqueMetadataException, RegistryImportException {
AuthorizeException, NonUniqueMetadataException, RegistryImportException
{
// Get the values
String name = RegistryImporter.getElementData(node, "name");
String namespace = RegistryImporter.getElementData(node, "namespace");
if (name == null || "".equals(name)) {
if (name == null || "".equals(name))
{
throw new RegistryImportException("Name of schema must be supplied");
}
if (namespace == null || "".equals(namespace)) {
if (namespace == null || "".equals(namespace))
{
throw new RegistryImportException("Namespace of schema must be supplied");
}
// check to see if the schema already exists
MetadataSchema s = metadataSchemaService.find(context, name);
if (s == null) {
MetadataSchema s = MetadataSchema.find(context, name);
if (s == null)
{
// Schema does not exist - create
log.info("Registering Schema " + name + " (" + namespace + ")");
metadataSchemaService.create(context, name, namespace);
} else {
MetadataSchema schema = new MetadataSchema(namespace, name);
schema.create(context);
}
else
{
// Schema exists - if it's the same namespace, allow the type imports to continue
if (s.getNamespace().equals(namespace)) {
if (s.getNamespace().equals(namespace))
{
// This schema already exists with this namespace, skipping it
return;
}
// It's a different namespace - have we been told to update?
if (updateExisting) {
if (updateExisting)
{
// Update the existing schema namespace and continue to type import
log.info("Updating Schema " + name + ": New namespace " + namespace);
s.setNamespace(namespace);
metadataSchemaService.update(context, s);
} else {
throw new RegistryImportException(
"Schema " + name + " already registered with different namespace " + namespace + ". Rerun with " +
"'update' option enabled if you wish to update this schema.");
s.update(context);
}
else
{
throw new RegistryImportException("Schema " + name + " already registered with different namespace " + namespace + ". Rerun with 'update' option enabled if you wish to update this schema.");
}
}
}
/**
* Process a node in the metadata registry XML file. The node must
* be a "dc-type" node. If the type already exists, then it
* will not be reimported
*
* @param context DSpace context object
* @param node the node in the DOM tree
* @throws SQLException if database error
* @throws IOException if IO error
* @throws TransformerException if transformer error
* @throws AuthorizeException if authorization error
* @throws NonUniqueMetadataException if duplicate metadata
* @throws RegistryImportException if import fails
*
* @param context
* DSpace context object
* @param node
* the node in the DOM tree
* @throws NonUniqueMetadataException
*/
private static void loadType(Context context, Node node)
throws SQLException, IOException, TransformerException,
AuthorizeException, NonUniqueMetadataException, RegistryImportException {
throws SQLException, IOException, TransformerException,
AuthorizeException, NonUniqueMetadataException, RegistryImportException
{
// Get the values
String schema = RegistryImporter.getElementData(node, "schema");
String element = RegistryImporter.getElementData(node, "element");
@@ -247,41 +229,48 @@ public class MetadataImporter {
String scopeNote = RegistryImporter.getElementData(node, "scope_note");
// If the schema is not provided default to DC
if (schema == null) {
if (schema == null)
{
schema = MetadataSchema.DC_SCHEMA;
}
// Find the matching schema object
MetadataSchema schemaObj = metadataSchemaService.find(context, schema);
if (schemaObj == null) {
MetadataSchema schemaObj = MetadataSchema.find(context, schema);
if (schemaObj == null)
{
throw new RegistryImportException("Schema '" + schema + "' is not registered and does not exist.");
}
MetadataField mf = metadataFieldService.findByElement(context, schemaObj, element, qualifier);
if (mf != null) {
MetadataField mf = MetadataField.findByElement(context, schemaObj.getSchemaID(), element, qualifier);
if (mf != null)
{
// Metadata field already exists, skipping it
return;
}
// Actually create this metadata field as it doesn't yet exist
String fieldName = schema + "." + element + "." + qualifier;
if (qualifier == null) {
if(qualifier==null)
fieldName = schema + "." + element;
}
log.info("Registering metadata field " + fieldName);
MetadataField field = metadataFieldService.create(context, schemaObj, element, qualifier, scopeNote);
metadataFieldService.update(context, field);
MetadataField field = new MetadataField();
field.setSchemaID(schemaObj.getSchemaID());
field.setElement(element);
field.setQualifier(qualifier);
field.setScopeNote(scopeNote);
field.create(context);
}
/**
* Print the usage message to stdout
*/
public static void usage() {
public static void usage()
{
String usage = "Use this class with the following option:\n" +
" -f <xml source file> : specify which xml source file " +
"contains the DC fields to import.\n";
" -f <xml source file> : specify which xml source file " +
"contains the DC fields to import.\n";
System.out.println(usage);
}
}

View File

@@ -12,40 +12,45 @@ package org.dspace.administer;
*
* An exception to report any problems with registry exports
*/
public class RegistryExportException extends Exception {
public class RegistryExportException extends Exception
{
/**
* Create an empty authorize exception
*/
public RegistryExportException() {
public RegistryExportException()
{
super();
}
/**
* create an exception with only a message
*
* @param message exception message
*
* @param message
*/
public RegistryExportException(String message) {
public RegistryExportException(String message)
{
super(message);
}
/**
* create an exception with an inner exception and a message
*
* @param message exception message
* @param e reference to Throwable
*
* @param message
* @param e
*/
public RegistryExportException(String message, Throwable e) {
public RegistryExportException(String message, Throwable e)
{
super(message, e);
}
/**
* create an exception with an inner exception
*
* @param e reference to Throwable
*
* @param e
*/
public RegistryExportException(Throwable e) {
public RegistryExportException(Throwable e)
{
super(e);
}
}

View File

@@ -12,40 +12,45 @@ package org.dspace.administer;
*
* An exception to report any problems with registry imports
*/
public class RegistryImportException extends Exception {
public class RegistryImportException extends Exception
{
/**
* Create an empty authorize exception
*/
public RegistryImportException() {
public RegistryImportException()
{
super();
}
/**
* create an exception with only a message
*
* @param message error message
*
* @param message
*/
public RegistryImportException(String message) {
public RegistryImportException(String message)
{
super(message);
}
/**
* create an exception with an inner exception and a message
*
* @param message error message
* @param e throwable
*
* @param message
* @param e
*/
public RegistryImportException(String message, Throwable e) {
super(message, e);
public RegistryImportException(String message, Throwable e)
{
super(message, e);
}
/**
* create an exception with an inner exception
*
* @param e throwable
*
* @param e
*/
public RegistryImportException(Throwable e) {
super(e);
public RegistryImportException(Throwable e)
{
super(e);
}
}

View File

@@ -9,15 +9,18 @@ package org.dspace.administer;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.apache.xpath.XPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
@@ -28,32 +31,27 @@ import org.xml.sax.SAXException;
* I am the author, really I ripped these methods off from other
* classes
*/
public class RegistryImporter {
/**
* Default constructor
*/
private RegistryImporter() { }
public class RegistryImporter
{
/**
* Load in the XML from file.
*
* @param filename the filename to load from
*
* @param filename
* the filename to load from
*
* @return the DOM representation of the XML file
* @throws IOException if IO error
* @throws ParserConfigurationException if configuration parse error
* @throws SAXException if XML parse error
*/
public static Document loadXML(String filename)
throws IOException, ParserConfigurationException, SAXException {
public static Document loadXML(String filename)
throws IOException, ParserConfigurationException, SAXException
{
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
.newDocumentBuilder();
Document document = builder.parse(new File(filename));
return document;
}
/**
* Get the CDATA of a particular element. For example, if the XML document
* contains:
@@ -65,18 +63,22 @@ public class RegistryImporter {
* return <code>application/pdf</code>.
* </P>
* Why this isn't a core part of the XML API I do not know...
*
* @param parentElement the element, whose child element you want the CDATA from
* @param childName the name of the element you want the CDATA from
*
* @param parentElement
* the element, whose child element you want the CDATA from
* @param childName
* the name of the element you want the CDATA from
*
* @return the CDATA as a <code>String</code>
* @throws TransformerException if error
*/
public static String getElementData(Node parentElement, String childName)
throws TransformerException {
throws TransformerException
{
// Grab the child node
Node childNode = XPathAPI.selectSingleNode(parentElement, childName);
if (childNode == null) {
if (childNode == null)
{
// No child node, so no values
return null;
}
@@ -84,7 +86,8 @@ public class RegistryImporter {
// Get the #text
Node dataNode = childNode.getFirstChild();
if (dataNode == null) {
if (dataNode == null)
{
return null;
}
@@ -100,28 +103,32 @@ public class RegistryImporter {
* <P>
* <code>
* &lt;foo&gt;
* &lt;bar&gt;val1&lt;/bar&gt;
* &lt;bar&gt;val2&lt;/bar&gt;
* &lt;bar&gt;val1&lt;/bar&gt;
* &lt;bar&gt;val2&lt;/bar&gt;
* &lt;/foo&gt;
* </code>
* passing this the <code>foo</code> node and <code>bar</code> will
* return <code>val1</code> and <code>val2</code>.
* </P>
* Why this also isn't a core part of the XML API I do not know...
*
* @param parentElement the element, whose child element you want the CDATA from
* @param childName the name of the element you want the CDATA from
*
* @param parentElement
* the element, whose child element you want the CDATA from
* @param childName
* the name of the element you want the CDATA from
*
* @return the CDATA as a <code>String</code>
* @throws TransformerException if error
*/
public static String[] getRepeatedElementData(Node parentElement,
String childName) throws TransformerException {
String childName) throws TransformerException
{
// Grab the child node
NodeList childNodes = XPathAPI.selectNodeList(parentElement, childName);
String[] data = new String[childNodes.getLength()];
for (int i = 0; i < childNodes.getLength(); i++) {
for (int i = 0; i < childNodes.getLength(); i++)
{
// Get the #text node
Node dataNode = childNodes.item(i).getFirstChild();

View File

@@ -10,8 +10,7 @@ package org.dspace.administer;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -21,8 +20,9 @@ import org.apache.log4j.Logger;
import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.BitstreamFormat;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.NonUniqueMetadataException;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.w3c.dom.Document;
@@ -39,37 +39,30 @@ import org.xml.sax.SAXException;
* <code>RegistryLoader -bitstream bitstream-formats.xml</code>
* <P>
* <code>RegistryLoader -dc dc-types.xml</code>
*
*
* @author Robert Tansley
* @version $Revision$
*/
public class RegistryLoader {
/**
* log4j category
*/
public class RegistryLoader
{
/** log4j category */
private static Logger log = Logger.getLogger(RegistryLoader.class);
protected static BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance()
.getBitstreamFormatService();
/**
* Default constructor
*/
private RegistryLoader() { }
/**
* For invoking via the command line
*
* @param argv the command line arguments given
* @throws Exception if error
*
* @param argv
* command-line arguments
*/
public static void main(String[] argv) throws Exception {
public static void main(String[] argv) throws Exception
{
String usage = "Usage: " + RegistryLoader.class.getName()
+ " (-bitstream | -metadata) registry-file.xml";
+ " (-bitstream | -metadata) registry-file.xml";
Context context = null;
try {
try
{
context = new Context();
// Can't update registries anonymously, so we need to turn off
@@ -77,12 +70,17 @@ public class RegistryLoader {
context.turnOffAuthorisationSystem();
// Work out what we're loading
if (argv[0].equalsIgnoreCase("-bitstream")) {
if (argv[0].equalsIgnoreCase("-bitstream"))
{
RegistryLoader.loadBitstreamFormats(context, argv[1]);
} else if (argv[0].equalsIgnoreCase("-metadata")) {
}
else if (argv[0].equalsIgnoreCase("-metadata"))
{
// Call MetadataImporter, as it handles Metadata schema updates
MetadataImporter.loadRegistry(argv[1], true);
} else {
}
else
{
System.err.println(usage);
}
@@ -90,69 +88,71 @@ public class RegistryLoader {
context.complete();
System.exit(0);
} catch (ArrayIndexOutOfBoundsException ae) {
}
catch (ArrayIndexOutOfBoundsException ae)
{
System.err.println(usage);
System.exit(1);
} catch (Exception e) {
}
catch (Exception e)
{
log.fatal(LogManager.getHeader(context, "error_loading_registries",
""), e);
""), e);
System.err.println("Error: \n - " + e.getMessage());
System.exit(1);
} finally {
}
finally
{
// Clean up our context, if it still exists & it was never completed
if (context != null && context.isValid()) {
if(context!=null && context.isValid())
context.abort();
}
}
}
/**
* Load Bitstream Format metadata
*
* @param context DSpace context object
* @param filename the filename of the XML file to load
* @throws SQLException if database error
* @throws IOException if IO error
* @throws TransformerException if transformer error
* @throws ParserConfigurationException if config error
* @throws AuthorizeException if authorization error
* @throws SAXException if parser error
*
* @param context
* DSpace context object
* @param filename
* the filename of the XML file to load
*/
public static void loadBitstreamFormats(Context context, String filename)
throws SQLException, IOException, ParserConfigurationException,
SAXException, TransformerException, AuthorizeException {
throws SQLException, IOException, ParserConfigurationException,
SAXException, TransformerException, AuthorizeException
{
Document document = loadXML(filename);
// Get the nodes corresponding to formats
NodeList typeNodes = XPathAPI.selectNodeList(document,
"dspace-bitstream-types/bitstream-type");
"dspace-bitstream-types/bitstream-type");
// Add each one as a new format to the registry
for (int i = 0; i < typeNodes.getLength(); i++) {
for (int i = 0; i < typeNodes.getLength(); i++)
{
Node n = typeNodes.item(i);
loadFormat(context, n);
}
log.info(LogManager.getHeader(context, "load_bitstream_formats",
"number_loaded=" + typeNodes.getLength()));
"number_loaded=" + typeNodes.getLength()));
}
/**
* Process a node in the bitstream format registry XML file. The node must
* be a "bitstream-type" node
*
* @param context DSpace context object
* @param node the node in the DOM tree
* @throws SQLException if database error
* @throws IOException if IO error
* @throws TransformerException if transformer error
* @throws AuthorizeException if authorization error
*
* @param context
* DSpace context object
* @param node
* the node in the DOM tree
*/
private static void loadFormat(Context context, Node node)
throws SQLException, IOException, TransformerException,
AuthorizeException {
throws SQLException, IOException, TransformerException,
AuthorizeException
{
// Get the values
String mimeType = getElementData(node, "mimetype");
String shortDesc = getElementData(node, "short_description");
@@ -167,30 +167,30 @@ public class RegistryLoader {
String[] extensions = getRepeatedElementData(node, "extension");
// Check if this format already exists in our registry (by mime type)
BitstreamFormat exists = bitstreamFormatService.findByMIMEType(context, mimeType);
BitstreamFormat exists = BitstreamFormat.findByMIMEType(context, mimeType);
// If not found by mimeType, check by short description (since this must also be unique)
if (exists == null) {
exists = bitstreamFormatService.findByShortDescription(context, shortDesc);
if(exists==null)
{
exists = BitstreamFormat.findByShortDescription(context, shortDesc);
}
// If it doesn't exist, create it..otherwise skip it.
if (exists == null) {
if(exists==null)
{
// Create the format object
BitstreamFormat format = bitstreamFormatService.create(context);
BitstreamFormat format = BitstreamFormat.create(context);
// Fill it out with the values
format.setMIMEType(mimeType);
bitstreamFormatService.setShortDescription(context, format, shortDesc);
format.setShortDescription(shortDesc);
format.setDescription(desc);
format.setSupportLevel(supportLevel);
format.setInternal(internal);
ArrayList<String> extensionList = new ArrayList<>();
extensionList.addAll(Arrays.asList(extensions));
format.setExtensions(extensionList);
format.setExtensions(extensions);
// Write to database
bitstreamFormatService.update(context, format);
format.update();
}
}
@@ -198,17 +198,17 @@ public class RegistryLoader {
/**
* Load in the XML from file.
*
* @param filename the filename to load from
*
* @param filename
* the filename to load from
*
* @return the DOM representation of the XML file
* @throws IOException if IO error
* @throws ParserConfigurationException if config error
* @throws SAXException if parser error
*/
private static Document loadXML(String filename) throws IOException,
ParserConfigurationException, SAXException {
ParserConfigurationException, SAXException
{
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
.newDocumentBuilder();
return builder.parse(new File(filename));
}
@@ -224,18 +224,22 @@ public class RegistryLoader {
* return <code>application/pdf</code>.
* </P>
* Why this isn't a core part of the XML API I do not know...
*
* @param parentElement the element, whose child element you want the CDATA from
* @param childName the name of the element you want the CDATA from
*
* @param parentElement
* the element, whose child element you want the CDATA from
* @param childName
* the name of the element you want the CDATA from
*
* @return the CDATA as a <code>String</code>
* @throws TransformerException if transformer error
*/
private static String getElementData(Node parentElement, String childName)
throws TransformerException {
throws TransformerException
{
// Grab the child node
Node childNode = XPathAPI.selectSingleNode(parentElement, childName);
if (childNode == null) {
if (childNode == null)
{
// No child node, so no values
return null;
}
@@ -243,7 +247,8 @@ public class RegistryLoader {
// Get the #text
Node dataNode = childNode.getFirstChild();
if (dataNode == null) {
if (dataNode == null)
{
return null;
}
@@ -259,28 +264,32 @@ public class RegistryLoader {
* <P>
* <code>
* &lt;foo&gt;
* &lt;bar&gt;val1&lt;/bar&gt;
* &lt;bar&gt;val2&lt;/bar&gt;
* &lt;bar&gt;val1&lt;/bar&gt;
* &lt;bar&gt;val2&lt;/bar&gt;
* &lt;/foo&gt;
* </code>
* passing this the <code>foo</code> node and <code>bar</code> will
* return <code>val1</code> and <code>val2</code>.
* </P>
* Why this also isn't a core part of the XML API I do not know...
*
* @param parentElement the element, whose child element you want the CDATA from
* @param childName the name of the element you want the CDATA from
*
* @param parentElement
* the element, whose child element you want the CDATA from
* @param childName
* the name of the element you want the CDATA from
*
* @return the CDATA as a <code>String</code>
* @throws TransformerException if transformer error
*/
private static String[] getRepeatedElementData(Node parentElement,
String childName) throws TransformerException {
String childName) throws TransformerException
{
// Grab the child node
NodeList childNodes = XPathAPI.selectNodeList(parentElement, childName);
String[] data = new String[childNodes.getLength()];
for (int i = 0; i < childNodes.getLength(); i++) {
for (int i = 0; i < childNodes.getLength(); i++)
{
// Get the #text node
Node dataNode = childNodes.item(i).getFirstChild();

View File

@@ -14,6 +14,7 @@ import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -27,12 +28,8 @@ import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.EPerson;
import org.jdom.Element;
import org.jdom.output.XMLOutputter;
import org.w3c.dom.Document;
@@ -43,119 +40,109 @@ import org.xml.sax.SAXException;
/**
* This class deals with importing community and collection structures from
* an XML file.
*
*
* The XML file structure needs to be:
* {@code
*
* <import_structure>
* <community>
* <name>....</name>
* <community>...</community>
* <collection>
* <name>....</name>
* </collection>
* </community>
* <community>
* <name>....</name>
* <community>...</community>
* <collection>
* <name>....</name>
* </collection>
* </community>
* </import_structure>
* }
*
* it can be arbitrarily deep, and supports all the metadata elements
* that make up the community and collection metadata. See the system
* documentation for more details
*
*
* @author Richard Jones
*
*/
public class StructBuilder {
/**
* the output xml document which will contain updated information about the
public class StructBuilder
{
/** the output xml document which will contain updated information about the
* imported structure
*/
private static org.jdom.Document xmlOutput = new org.jdom.Document(new Element("imported_structure"));
/**
* a hashtable to hold metadata for the collection being worked on
*/
/** a hashtable to hold metadata for the collection being worked on */
private static Map<String, String> collectionMap = new HashMap<String, String>();
/**
* a hashtable to hold metadata for the community being worked on
*/
/** a hashtable to hold metadata for the community being worked on */
private static Map<String, String> communityMap = new HashMap<String, String>();
protected static CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
protected static CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected static EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
/**
* Default constructor
*/
private StructBuilder() { }
/**
* Main method to be run from the command line to import a structure into
* DSpace
*
*
* This is of the form:
*
* {@code StructBuilder -f [xml source] -e [administrator email] -o [output file]}
*
*
* StructBuilder -f [xml source] -e [administrator email] -o [output file]
*
* The output file will contain exactly the same as the source xml document, but
* with the handle for each imported item added as an attribute.
*
* @param argv the command line arguments given
* @throws Exception if an error occurs
*/
public static void main(String[] argv)
throws Exception {
public static void main(String[] argv)
throws Exception
{
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("f", "file", true, "file");
options.addOption("e", "eperson", true, "eperson");
options.addOption("o", "output", true, "output");
CommandLine line = parser.parse(options, argv);
String file = null;
String eperson = null;
String output = null;
if (line.hasOption('f')) {
file = line.getOptionValue('f');
}
if (line.hasOption('e')) {
eperson = line.getOptionValue('e');
}
if (line.hasOption('o')) {
output = line.getOptionValue('o');
}
if (output == null || eperson == null || file == null) {
usage();
System.exit(0);
}
Options options = new Options();
options.addOption( "f", "file", true, "file");
options.addOption( "e", "eperson", true, "eperson");
options.addOption("o", "output", true, "output");
CommandLine line = parser.parse( options, argv );
String file = null;
String eperson = null;
String output = null;
if (line.hasOption('f'))
{
file = line.getOptionValue('f');
}
if (line.hasOption('e'))
{
eperson = line.getOptionValue('e');
}
if (line.hasOption('o'))
{
output = line.getOptionValue('o');
}
if (output == null || eperson == null || file == null)
{
usage();
System.exit(0);
}
// create a context
Context context = new Context();
// set the context
context.setCurrentUser(ePersonService.findByEmail(context, eperson));
context.setCurrentUser(EPerson.findByEmail(context, eperson));
// load the XML
Document document = loadXML(file);
// run the preliminary validation, to be sure that the the XML document
// is properly structured
validate(document);
// load the mappings into the member variable hashmaps
communityMap.put("name", "name");
communityMap.put("description", "short_description");
communityMap.put("intro", "introductory_text");
communityMap.put("copyright", "copyright_text");
communityMap.put("sidebar", "side_bar_text");
collectionMap.put("name", "name");
collectionMap.put("description", "short_description");
collectionMap.put("intro", "introductory_text");
@@ -163,232 +150,267 @@ public class StructBuilder {
collectionMap.put("sidebar", "side_bar_text");
collectionMap.put("license", "license");
collectionMap.put("provenance", "provenance_description");
// get the top level community list
NodeList first = XPathAPI.selectNodeList(document, "/import_structure/community");
// run the import starting with the top level communities
Element[] elements = handleCommunities(context, first, null);
// generate the output
Element root = xmlOutput.getRootElement();
for (int i = 0; i < elements.length; i++) {
for (int i = 0; i < elements.length; i++)
{
root.addContent(elements[i]);
}
// finally write the string into the output file
try {
try
{
BufferedWriter out = new BufferedWriter(new FileWriter(output));
out.write(new XMLOutputter().outputString(xmlOutput));
out.close();
} catch (IOException e) {
}
catch (IOException e)
{
System.out.println("Unable to write to output file " + output);
System.exit(0);
}
context.complete();
}
/**
* Output the usage information
*/
private static void usage() {
private static void usage()
{
System.out.println("Usage: java StructBuilder -f <source XML file> -o <output file> -e <eperson email>");
System.out.println(
"Communities will be created from the top level, and a map of communities to handles will be returned in " +
"the output file");
System.out.println("Communities will be created from the top level, and a map of communities to handles will be returned in the output file");
return;
}
/**
* Validate the XML document. This method does not return, but if validation
* fails it generates an error and ceases execution
*
* @param document the XML document object
* @throws TransformerException if transformer error
*
* @param document the XML document object
* @throws TransformerException
*
*/
private static void validate(org.w3c.dom.Document document)
throws TransformerException {
throws TransformerException
{
StringBuffer err = new StringBuffer();
boolean trip = false;
err.append("The following errors were encountered parsing the source XML\n");
err.append("No changes have been made to the DSpace instance\n\n");
NodeList first = XPathAPI.selectNodeList(document, "/import_structure/community");
if (first.getLength() == 0) {
if (first.getLength() == 0)
{
err.append("-There are no top level communities in the source document");
System.out.println(err.toString());
System.exit(0);
}
String errs = validateCommunities(first, 1);
if (errs != null) {
if (errs != null)
{
err.append(errs);
trip = true;
}
if (trip) {
if (trip)
{
System.out.println(err.toString());
System.exit(0);
}
}
/**
* Validate the communities section of the XML document. This returns a string
* containing any errors encountered, or null if there were no errors
*
*
* @param communities the NodeList of communities to validate
* @param level the level in the XML document that we are at, for the purposes
* of error reporting
* @param level the level in the XML document that we are at, for the purposes
* of error reporting
*
* @return the errors that need to be generated by the calling method, or null if
* no errors.
* no errors.
*/
private static String validateCommunities(NodeList communities, int level)
throws TransformerException {
throws TransformerException
{
StringBuffer err = new StringBuffer();
boolean trip = false;
String errs = null;
for (int i = 0; i < communities.getLength(); i++) {
for (int i = 0; i < communities.getLength(); i++)
{
Node n = communities.item(i);
NodeList name = XPathAPI.selectNodeList(n, "name");
if (name.getLength() != 1) {
String pos = Integer.toString(i + 1);
err.append("-The level " + level + " community in position " + pos);
err.append(" does not contain exactly one name field\n");
trip = true;
}
// validate sub communities
NodeList subCommunities = XPathAPI.selectNodeList(n, "community");
String comErrs = validateCommunities(subCommunities, level + 1);
if (comErrs != null) {
err.append(comErrs);
trip = true;
}
// validate collections
NodeList collections = XPathAPI.selectNodeList(n, "collection");
String colErrs = validateCollections(collections, level + 1);
if (colErrs != null) {
err.append(colErrs);
trip = true;
}
NodeList name = XPathAPI.selectNodeList(n, "name");
if (name.getLength() != 1)
{
String pos = Integer.toString(i + 1);
err.append("-The level " + level + " community in position " + pos);
err.append(" does not contain exactly one name field\n");
trip = true;
}
// validate sub communities
NodeList subCommunities = XPathAPI.selectNodeList(n, "community");
String comErrs = validateCommunities(subCommunities, level + 1);
if (comErrs != null)
{
err.append(comErrs);
trip = true;
}
// validate collections
NodeList collections = XPathAPI.selectNodeList(n, "collection");
String colErrs = validateCollections(collections, level + 1);
if (colErrs != null)
{
err.append(colErrs);
trip = true;
}
}
if (trip) {
if (trip)
{
errs = err.toString();
}
return errs;
}
/**
* validate the collection section of the XML document. This generates a
* string containing any errors encountered, or returns null if no errors
*
*
* @param collections a NodeList of collections to validate
* @param level the level in the XML document for the purposes of error reporting
* @param level the level in the XML document for the purposes of error reporting
*
* @return the errors to be generated by the calling method, or null if none
*/
private static String validateCollections(NodeList collections, int level)
throws TransformerException {
throws TransformerException
{
StringBuffer err = new StringBuffer();
boolean trip = false;
String errs = null;
for (int i = 0; i < collections.getLength(); i++) {
for (int i = 0; i < collections.getLength(); i++)
{
Node n = collections.item(i);
NodeList name = XPathAPI.selectNodeList(n, "name");
if (name.getLength() != 1) {
String pos = Integer.toString(i + 1);
err.append("-The level " + level + " collection in position " + pos);
err.append(" does not contain exactly one name field\n");
trip = true;
}
NodeList name = XPathAPI.selectNodeList(n, "name");
if (name.getLength() != 1)
{
String pos = Integer.toString(i + 1);
err.append("-The level " + level + " collection in position " + pos);
err.append(" does not contain exactly one name field\n");
trip = true;
}
}
if (trip) {
if (trip)
{
errs = err.toString();
}
return errs;
}
/**
* Load in the XML from file.
*
* @param filename the filename to load from
*
* @param filename
* the filename to load from
*
* @return the DOM representation of the XML file
*/
private static org.w3c.dom.Document loadXML(String filename)
throws IOException, ParserConfigurationException, SAXException {
private static org.w3c.dom.Document loadXML(String filename)
throws IOException, ParserConfigurationException, SAXException
{
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
.newDocumentBuilder();
org.w3c.dom.Document document = builder.parse(new File(filename));
return document;
}
/**
* Return the String value of a Node
*
*
* @param node the node from which we want to extract the string value
*
* @return the string value of the node
*/
public static String getStringValue(Node node) {
public static String getStringValue(Node node)
{
String value = node.getNodeValue();
if (node.hasChildNodes()) {
if (node.hasChildNodes())
{
Node first = node.getFirstChild();
if (first.getNodeType() == Node.TEXT_NODE) {
if (first.getNodeType() == Node.TEXT_NODE)
{
return first.getNodeValue().trim();
}
}
return value;
}
/**
* Take a node list of communities and build the structure from them, delegating
* to the relevant methods in this class for sub-communities and collections
*
* @param context the context of the request
*
* @param context the context of the request
* @param communities a nodelist of communities to create along with their sub-structures
* @param parent the parent community of the nodelist of communities to create
* @return an element array containing additional information regarding the
* created communities (e.g. the handles they have been assigned)
* @param parent the parent community of the nodelist of communities to create
*
* @return an element array containing additional information regarding the
* created communities (e.g. the handles they have been assigned)
*/
private static Element[] handleCommunities(Context context, NodeList communities, Community parent)
throws TransformerException, SQLException, Exception {
throws TransformerException, SQLException, Exception
{
Element[] elements = new Element[communities.getLength()];
for (int i = 0; i < communities.getLength(); i++) {
for (int i = 0; i < communities.getLength(); i++)
{
Community community;
Element element = new Element("community");
// create the community or sub community
if (parent != null) {
community = communityService.create(parent, context);
} else {
community = communityService.create(null, context);
if (parent != null)
{
community = parent.createSubcommunity();
}
else
{
community = Community.create(null, context);
}
// default the short description to be an empty string
communityService.setMetadata(context, community, "short_description", " ");
community.setMetadata("short_description", " ");
// now update the metadata
Node tn = communities.item(i);
for (Map.Entry<String, String> entry : communityMap.entrySet()) {
for (Map.Entry<String, String> entry : communityMap.entrySet())
{
NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey());
if (nl.getLength() == 1) {
communityService.setMetadata(context, community, entry.getValue(), getStringValue(nl.item(0)));
if (nl.getLength() == 1)
{
community.setMetadata(entry.getValue(), getStringValue(nl.item(0)));
}
}
// FIXME: at the moment, if the community already exists by name
// then this will throw a PSQLException on a duplicate key
// violation
@@ -398,8 +420,8 @@ public class StructBuilder {
// difficult
// to isolate the community that already exists without hitting
// the database directly.
communityService.update(context, community);
community.update();
// build the element with the handle that identifies the new
// community
// along with all the information that we imported here
@@ -409,134 +431,151 @@ public class StructBuilder {
// case
// we want to move it or make it switchable later
element.setAttribute("identifier", community.getHandle());
Element nameElement = new Element("name");
nameElement.setText(communityService.getMetadata(community, "name"));
nameElement.setText(community.getMetadata("name"));
element.addContent(nameElement);
if (communityService.getMetadata(community, "short_description") != null) {
if (community.getMetadata("short_description") != null)
{
Element descriptionElement = new Element("description");
descriptionElement.setText(communityService.getMetadata(community, "short_description"));
descriptionElement.setText(community.getMetadata("short_description"));
element.addContent(descriptionElement);
}
if (communityService.getMetadata(community, "introductory_text") != null) {
if (community.getMetadata("introductory_text") != null)
{
Element introElement = new Element("intro");
introElement.setText(communityService.getMetadata(community, "introductory_text"));
introElement.setText(community.getMetadata("introductory_text"));
element.addContent(introElement);
}
if (communityService.getMetadata(community, "copyright_text") != null) {
if (community.getMetadata("copyright_text") != null)
{
Element copyrightElement = new Element("copyright");
copyrightElement.setText(communityService.getMetadata(community, "copyright_text"));
copyrightElement.setText(community.getMetadata("copyright_text"));
element.addContent(copyrightElement);
}
if (communityService.getMetadata(community, "side_bar_text") != null) {
if (community.getMetadata("side_bar_text") != null)
{
Element sidebarElement = new Element("sidebar");
sidebarElement.setText(communityService.getMetadata(community, "side_bar_text"));
sidebarElement.setText(community.getMetadata("side_bar_text"));
element.addContent(sidebarElement);
}
// handle sub communities
NodeList subCommunities = XPathAPI.selectNodeList(tn, "community");
Element[] subCommunityElements = handleCommunities(context, subCommunities, community);
// handle collections
NodeList collections = XPathAPI.selectNodeList(tn, "collection");
Element[] collectionElements = handleCollections(context, collections, community);
int j;
for (j = 0; j < subCommunityElements.length; j++) {
for (j = 0; j < subCommunityElements.length; j++)
{
element.addContent(subCommunityElements[j]);
}
for (j = 0; j < collectionElements.length; j++) {
for (j = 0; j < collectionElements.length; j++)
{
element.addContent(collectionElements[j]);
}
elements[i] = element;
}
return elements;
}
/**
* Take a node list of collections and create the structure from them
*
* @param context the context of the request
* Take a node list of collections and create the structure from them
*
* @param context the context of the request
* @param collections the node list of collections to be created
* @param parent the parent community to whom the collections belong
* @param parent the parent community to whom the collections belong
*
* @return an Element array containing additional information about the
* created collections (e.g. the handle)
* created collections (e.g. the handle)
*/
private static Element[] handleCollections(Context context, NodeList collections, Community parent)
throws TransformerException, SQLException, AuthorizeException, IOException, Exception {
throws TransformerException, SQLException, AuthorizeException, IOException, Exception
{
Element[] elements = new Element[collections.getLength()];
for (int i = 0; i < collections.getLength(); i++) {
for (int i = 0; i < collections.getLength(); i++)
{
Element element = new Element("collection");
Collection collection = collectionService.create(context, parent);
Collection collection = parent.createCollection();
// default the short description to the empty string
collectionService.setMetadata(context, collection, "short_description", " ");
collection.setMetadata("short_description", " ");
// import the rest of the metadata
Node tn = collections.item(i);
for (Map.Entry<String, String> entry : collectionMap.entrySet()) {
for (Map.Entry<String, String> entry : collectionMap.entrySet())
{
NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey());
if (nl.getLength() == 1) {
collectionService.setMetadata(context, collection, entry.getValue(), getStringValue(nl.item(0)));
if (nl.getLength() == 1)
{
collection.setMetadata(entry.getValue(), getStringValue(nl.item(0)));
}
}
collectionService.update(context, collection);
collection.update();
element.setAttribute("identifier", collection.getHandle());
Element nameElement = new Element("name");
nameElement.setText(collectionService.getMetadata(collection, "name"));
nameElement.setText(collection.getMetadata("name"));
element.addContent(nameElement);
if (collectionService.getMetadata(collection, "short_description") != null) {
if (collection.getMetadata("short_description") != null)
{
Element descriptionElement = new Element("description");
descriptionElement.setText(collectionService.getMetadata(collection, "short_description"));
descriptionElement.setText(collection.getMetadata("short_description"));
element.addContent(descriptionElement);
}
if (collectionService.getMetadata(collection, "introductory_text") != null) {
if (collection.getMetadata("introductory_text") != null)
{
Element introElement = new Element("intro");
introElement.setText(collectionService.getMetadata(collection, "introductory_text"));
introElement.setText(collection.getMetadata("introductory_text"));
element.addContent(introElement);
}
if (collectionService.getMetadata(collection, "copyright_text") != null) {
if (collection.getMetadata("copyright_text") != null)
{
Element copyrightElement = new Element("copyright");
copyrightElement.setText(collectionService.getMetadata(collection, "copyright_text"));
copyrightElement.setText(collection.getMetadata("copyright_text"));
element.addContent(copyrightElement);
}
if (collectionService.getMetadata(collection, "side_bar_text") != null) {
if (collection.getMetadata("side_bar_text") != null)
{
Element sidebarElement = new Element("sidebar");
sidebarElement.setText(collectionService.getMetadata(collection, "side_bar_text"));
sidebarElement.setText(collection.getMetadata("side_bar_text"));
element.addContent(sidebarElement);
}
if (collectionService.getMetadata(collection, "license") != null) {
if (collection.getMetadata("license") != null)
{
Element sidebarElement = new Element("license");
sidebarElement.setText(collectionService.getMetadata(collection, "license"));
sidebarElement.setText(collection.getMetadata("license"));
element.addContent(sidebarElement);
}
if (collectionService.getMetadata(collection, "provenance_description") != null) {
if (collection.getMetadata("provenance_description") != null)
{
Element sidebarElement = new Element("provenance");
sidebarElement.setText(collectionService.getMetadata(collection, "provenance_description"));
sidebarElement.setText(collection.getMetadata("provenance_description"));
element.addContent(sidebarElement);
}
elements[i] = element;
}
return elements;
}
}

View File

@@ -7,93 +7,68 @@
*/
package org.dspace.app.bulkedit;
import org.dspace.content.Item;
import org.dspace.content.Metadatum;
import org.dspace.content.Collection;
import java.util.ArrayList;
import java.util.List;
import org.dspace.content.Collection;
import org.dspace.content.Item;
/**
* Utility class to store changes to item that may occur during a batch edit.
*
* @author Stuart Lewis
*/
public class BulkEditChange {
/**
* The item these changes relate to
*/
public class BulkEditChange
{
/** The item these changes relate to */
private Item item;
/**
* The List of hashtables with the new elements
*/
private List<BulkEditMetadataValue> adds;
/** The List of hashtables with the new elements */
private List<Metadatum> adds;
/**
* The List of hashtables with the removed elements
*/
private List<BulkEditMetadataValue> removes;
/** The List of hashtables with the removed elements */
private List<Metadatum> removes;
/**
* The List of hashtables with the unchanged elements
*/
private List<BulkEditMetadataValue> constant;
/** The List of hashtables with the unchanged elements */
private List<Metadatum> constant;
/**
* The List of the complete set of new values (constant + adds)
*/
private List<BulkEditMetadataValue> complete;
/** The List of the complete set of new values (constant + adds) */
private List<Metadatum> complete;
/**
* The list of old collections the item used to be mapped to
*/
/** The list of old collections the item used to be mapped to */
private List<Collection> oldMappedCollections;
/**
* The list of new collections the item has been mapped into
*/
/** The list of new collections the item has been mapped into */
private List<Collection> newMappedCollections;
/**
* The old owning collection
*/
/** The old owning collection */
private Collection oldOwningCollection;
/**
* The new owning collection
*/
/** The new owning collection */
private Collection newOwningCollection;
/**
* Is this a new item
*/
/** Is this a new item */
private boolean newItem;
/**
* Has this item been deleted?
*/
/** Has this item been deleted? */
private boolean deleted;
/**
* Has this item been withdrawn?
*/
/** Has this item been withdrawn? */
private boolean withdrawn;
/**
* Has this item been reinstated?
*/
/** Has this item been reinstated? */
private boolean reinstated;
/**
* Have any changes actually been made?
*/
/** Have any changes actually been made? */
private boolean empty;
/**
* Initialise a change holder for a new item
* Initialise a change holder for a new item
*/
public BulkEditChange() {
public BulkEditChange()
{
// Set the item to be null
item = null;
newItem = true;
@@ -102,12 +77,12 @@ public class BulkEditChange {
newOwningCollection = null;
// Initialise the arrays
adds = new ArrayList<>();
removes = new ArrayList<>();
constant = new ArrayList<>();
complete = new ArrayList<>();
oldMappedCollections = new ArrayList<>();
newMappedCollections = new ArrayList<>();
adds = new ArrayList<Metadatum>();
removes = new ArrayList<Metadatum>();
constant = new ArrayList<Metadatum>();
complete = new ArrayList<Metadatum>();
oldMappedCollections = new ArrayList<Collection>();
newMappedCollections = new ArrayList<Collection>();
}
/**
@@ -115,19 +90,20 @@ public class BulkEditChange {
*
* @param i The Item to store
*/
public BulkEditChange(Item i) {
public BulkEditChange(Item i)
{
// Store the item
item = i;
newItem = false;
empty = true;
// Initialise the arrays
adds = new ArrayList<>();
removes = new ArrayList<>();
constant = new ArrayList<>();
complete = new ArrayList<>();
oldMappedCollections = new ArrayList<>();
newMappedCollections = new ArrayList<>();
adds = new ArrayList<Metadatum>();
removes = new ArrayList<Metadatum>();
constant = new ArrayList<Metadatum>();
complete = new ArrayList<Metadatum>();
oldMappedCollections = new ArrayList<Collection>();
newMappedCollections = new ArrayList<Collection>();
}
/**
@@ -135,7 +111,8 @@ public class BulkEditChange {
*
* @param i The item
*/
public void setItem(Item i) {
public void setItem(Item i)
{
// Store the item
item = i;
}
@@ -145,7 +122,8 @@ public class BulkEditChange {
*
* @param dcv The value to add
*/
public void registerAdd(BulkEditMetadataValue dcv) {
public void registerAdd(Metadatum dcv)
{
// Add the added value
adds.add(dcv);
complete.add(dcv);
@@ -157,7 +135,8 @@ public class BulkEditChange {
*
* @param dcv The value to remove
*/
public void registerRemove(BulkEditMetadataValue dcv) {
public void registerRemove(Metadatum dcv)
{
// Add the removed value
removes.add(dcv);
empty = false;
@@ -168,7 +147,8 @@ public class BulkEditChange {
*
* @param dcv The value to keep unchanged
*/
public void registerConstant(BulkEditMetadataValue dcv) {
public void registerConstant(Metadatum dcv)
{
// Add the removed value
constant.add(dcv);
complete.add(dcv);
@@ -179,7 +159,8 @@ public class BulkEditChange {
*
* @param c The new mapped Collection
*/
public void registerNewMappedCollection(Collection c) {
public void registerNewMappedCollection(Collection c)
{
// Add the new owning Collection
newMappedCollections.add(c);
empty = false;
@@ -190,22 +171,27 @@ public class BulkEditChange {
*
* @param c The old mapped Collection
*/
public void registerOldMappedCollection(Collection c) {
public void registerOldMappedCollection(Collection c)
{
// Add the old owning Collection (if it isn't there already, or is an old collection)
boolean found = false;
if ((this.getOldOwningCollection() != null) &&
(this.getOldOwningCollection().getHandle().equals(c.getHandle()))) {
(this.getOldOwningCollection().getHandle().equals(c.getHandle())))
{
found = true;
}
for (Collection collection : oldMappedCollections) {
if (collection.getHandle().equals(c.getHandle())) {
for (Collection collection : oldMappedCollections)
{
if (collection.getHandle().equals(c.getHandle()))
{
found = true;
}
}
if (!found) {
if (!found)
{
oldMappedCollections.add(c);
empty = false;
}
@@ -217,7 +203,8 @@ public class BulkEditChange {
* @param oldC The old owning collection
* @param newC The new owning collection
*/
public void changeOwningCollection(Collection oldC, Collection newC) {
public void changeOwningCollection(Collection oldC, Collection newC)
{
// Store the old owning collection
oldOwningCollection = oldC;
@@ -231,7 +218,8 @@ public class BulkEditChange {
*
* @param newC The new owning collection
*/
public void setOwningCollection(Collection newC) {
public void setOwningCollection(Collection newC)
{
// Store the new owning collection
newOwningCollection = newC;
//empty = false;
@@ -242,7 +230,8 @@ public class BulkEditChange {
*
* @return The item
*/
public Item getItem() {
public Item getItem()
{
// Return the item
return item;
}
@@ -252,7 +241,8 @@ public class BulkEditChange {
*
* @return the list of elements and their values that have been added.
*/
public List<BulkEditMetadataValue> getAdds() {
public List<Metadatum> getAdds()
{
// Return the array
return adds;
}
@@ -262,7 +252,8 @@ public class BulkEditChange {
*
* @return the list of elements and their values that have been removed.
*/
public List<BulkEditMetadataValue> getRemoves() {
public List<Metadatum> getRemoves()
{
// Return the array
return removes;
}
@@ -272,7 +263,8 @@ public class BulkEditChange {
*
* @return the list of unchanged values
*/
public List<BulkEditMetadataValue> getConstant() {
public List<Metadatum> getConstant()
{
// Return the array
return constant;
}
@@ -282,7 +274,8 @@ public class BulkEditChange {
*
* @return the list of all values
*/
public List<BulkEditMetadataValue> getComplete() {
public List<Metadatum> getComplete()
{
// Return the array
return complete;
}
@@ -292,7 +285,8 @@ public class BulkEditChange {
*
* @return the list of new mapped collections
*/
public List<Collection> getNewMappedCollections() {
public List<Collection> getNewMappedCollections()
{
// Return the array
return newMappedCollections;
}
@@ -302,7 +296,8 @@ public class BulkEditChange {
*
* @return the list of old mapped collections
*/
public List<Collection> getOldMappedCollections() {
public List<Collection> getOldMappedCollections()
{
// Return the array
return oldMappedCollections;
}
@@ -312,7 +307,8 @@ public class BulkEditChange {
*
* @return the old owning collection
*/
public Collection getOldOwningCollection() {
public Collection getOldOwningCollection()
{
// Return the old owning collection
return oldOwningCollection;
}
@@ -322,7 +318,8 @@ public class BulkEditChange {
*
* @return the new owning collection
*/
public Collection getNewOwningCollection() {
public Collection getNewOwningCollection()
{
// Return the new owning collection
return newOwningCollection;
}
@@ -332,7 +329,8 @@ public class BulkEditChange {
*
* @return Whether or not this is for a new item
*/
public boolean isNewItem() {
public boolean isNewItem()
{
// Return the new item status
return newItem;
}
@@ -342,7 +340,8 @@ public class BulkEditChange {
*
* @return Whether or not this is for a deleted item
*/
public boolean isDeleted() {
public boolean isDeleted()
{
// Return the new item status
return deleted;
}
@@ -361,7 +360,8 @@ public class BulkEditChange {
*
* @return Whether or not this is for a withdrawn item
*/
public boolean isWithdrawn() {
public boolean isWithdrawn()
{
// Return the new item status
return withdrawn;
}
@@ -380,7 +380,8 @@ public class BulkEditChange {
*
* @return Whether or not this is for a reinstated item
*/
public boolean isReinstated() {
public boolean isReinstated()
{
// Return the new item status
return reinstated;
}
@@ -399,7 +400,8 @@ public class BulkEditChange {
*
* @return Whether or not changes have been made
*/
public boolean hasChanges() {
public boolean hasChanges()
{
return !empty;
}
}
}

View File

@@ -1,83 +0,0 @@
/**
* 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.app.bulkedit;
/**
* Value class used for metadata value edits used by the bulk edit.
*
* @author kevinvandevelde at atmire.com
*/
public class BulkEditMetadataValue {
private String schema;
private String element;
private String qualifier;
private String language;
private String value;
private String authority;
private int confidence;
public BulkEditMetadataValue() {
}
public void setSchema(String schema) {
this.schema = schema;
}
public void setElement(String element) {
this.element = element;
}
public void setQualifier(String qualifier) {
this.qualifier = qualifier;
}
public void setLanguage(String language) {
this.language = language;
}
public void setValue(String value) {
this.value = value;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public void setConfidence(int confidence) {
this.confidence = confidence;
}
public String getSchema() {
return schema;
}
public String getElement() {
return element;
}
public String getQualifier() {
return qualifier;
}
public String getLanguage() {
return language;
}
public String getValue() {
return value;
}
public String getAuthority() {
return authority;
}
public int getConfidence() {
return confidence;
}
}

View File

@@ -7,41 +7,22 @@
*/
package org.dspace.app.bulkedit;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.dspace.authority.AuthorityValue;
import org.dspace.authority.factory.AuthorityServiceFactory;
import org.dspace.authority.service.AuthorityValueService;
import org.dspace.app.bulkedit.DSpaceCSVLine;
import org.dspace.app.bulkedit.MetadataImport;
import org.dspace.app.bulkedit.MetadataImportInvalidHeadingException;
import org.dspace.content.Collection;
import org.dspace.content.*;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
import org.dspace.content.authority.Choices;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.services.factory.DSpaceServicesFactory;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.io.*;
/**
* Utility class to read and write CSV files
@@ -52,75 +33,46 @@ import org.dspace.services.factory.DSpaceServicesFactory;
*
* This class has been made serializable, as it is stored in a Session.
* Is it wise to:
* a) be putting this into a user's session?
* b) holding an entire CSV upload in memory?
* a) be putting this into a user's session?
* b) holding an entire CSV upload in memory?
*
* @author Stuart Lewis
*/
public class DSpaceCSV implements Serializable {
/**
* The headings of the CSV file
*/
protected List<String> headings;
public class DSpaceCSV implements Serializable
{
/** The headings of the CSV file */
private List<String> headings;
/**
* An array list of CSV lines
*/
protected List<DSpaceCSVLine> lines;
/** An array list of CSV lines */
private List<DSpaceCSVLine> lines;
/**
* A counter of how many CSV lines this object holds
*/
protected int counter;
/** A counter of how many CSV lines this object holds */
private int counter;
/**
* The value separator (defaults to double pipe '||')
*/
protected String valueSeparator;
/** The value separator (defaults to double pipe '||') */
protected static String valueSeparator;
/**
* The value separator in an escaped form for using in regexes
*/
protected String escapedValueSeparator;
/** The value separator in an escaped form for using in regexes */
protected static String escapedValueSeparator;
/**
* The field separator (defaults to comma)
*/
protected String fieldSeparator;
/** The field separator (defaults to comma) */
protected static String fieldSeparator;
/**
* The field separator in an escaped form for using in regexes
*/
protected String escapedFieldSeparator;
/** The field separator in an escaped form for using in regexes */
protected static String escapedFieldSeparator;
/**
* The authority separator (defaults to double colon '::')
*/
protected String authoritySeparator;
/** The authority separator (defaults to double colon '::') */
protected static String authoritySeparator;
/**
* The authority separator in an escaped form for using in regexes
*/
protected String escapedAuthoritySeparator;
protected transient final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected transient final MetadataSchemaService metadataSchemaService =
ContentServiceFactory.getInstance().getMetadataSchemaService();
protected transient final MetadataFieldService metadataFieldService =
ContentServiceFactory.getInstance().getMetadataFieldService();
protected transient final AuthorityValueService authorityValueService =
AuthorityServiceFactory.getInstance().getAuthorityValueService();
/** The authority separator in an escaped form for using in regexes */
protected static String escapedAuthoritySeparator;
/**
* Whether to export all metadata such as handles and provenance information
*/
protected boolean exportAll;
/** Whether to export all metadata such as handles and provenance information */
private boolean exportAll;
/**
* A list of metadata elements to ignore
*/
protected Map<String, String> ignore;
/** A list of metadata elements to ignore */
private Map<String, String> ignore;
/**
@@ -128,7 +80,8 @@ public class DSpaceCSV implements Serializable {
*
* @param exportAll Whether to export all metadata such as handles and provenance information
*/
public DSpaceCSV(boolean exportAll) {
public DSpaceCSV(boolean exportAll)
{
// Initialise the class
init();
@@ -141,39 +94,50 @@ public class DSpaceCSV implements Serializable {
*
* @param f The file to read from
* @param c The DSpace Context
*
* @throws Exception thrown if there is an error reading or processing the file
*/
public DSpaceCSV(File f, Context c) throws Exception {
public DSpaceCSV(File f, Context c) throws Exception
{
// Initialise the class
init();
// Open the CSV file
BufferedReader input = null;
try {
input = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
try
{
input = new BufferedReader(new InputStreamReader(new FileInputStream(f),"UTF-8"));
// Read the heading line
String head = input.readLine();
String[] headingElements = head.split(escapedFieldSeparator);
int columnCounter = 0;
for (String element : headingElements) {
for (String element : headingElements)
{
columnCounter++;
// Remove surrounding quotes if there are any
if ((element.startsWith("\"")) && (element.endsWith("\""))) {
if ((element.startsWith("\"")) && (element.endsWith("\"")))
{
element = element.substring(1, element.length() - 1);
}
// Store the heading
if ("collection".equals(element)) {
if ("collection".equals(element))
{
// Store the heading
headings.add(element);
} else if ("action".equals(element)) { // Store the action
}
// Store the action
else if ("action".equals(element))
{
// Store the heading
headings.add(element);
} else if (!"id".equals(element)) {
}
else if (!"id".equals(element))
{
String authorityPrefix = "";
AuthorityValue authorityValueType = authorityValueService.getAuthorityValueType(element);
AuthorityValue authorityValueType = MetadataImport.getAuthorityValueType(element);
if (authorityValueType != null) {
String authorityType = authorityValueType.getAuthorityType();
authorityPrefix = element.substring(0, authorityType.length() + 1);
@@ -198,7 +162,7 @@ public class DSpaceCSV implements Serializable {
}
// Check that the scheme exists
MetadataSchema foundSchema = metadataSchemaService.find(c, metadataSchema);
MetadataSchema foundSchema = MetadataSchema.find(c, metadataSchema);
if (foundSchema == null) {
throw new MetadataImportInvalidHeadingException(clean[0],
MetadataImportInvalidHeadingException.SCHEMA,
@@ -206,8 +170,8 @@ public class DSpaceCSV implements Serializable {
}
// Check that the metadata element exists in the schema
MetadataField foundField = metadataFieldService
.findByElement(c, foundSchema, metadataElement, metadataQualifier);
int schemaID = foundSchema.getSchemaID();
MetadataField foundField = MetadataField.findByElement(c, schemaID, metadataElement, metadataQualifier);
if (foundField == null) {
throw new MetadataImportInvalidHeadingException(clean[0],
MetadataImportInvalidHeadingException.ELEMENT,
@@ -223,7 +187,8 @@ public class DSpaceCSV implements Serializable {
StringBuilder lineBuilder = new StringBuilder();
String lineRead;
while ((lineRead = input.readLine()) != null) {
while ((lineRead = input.readLine()) != null)
{
if (lineBuilder.length() > 0) {
// Already have a previously read value - add this line
lineBuilder.append("\n").append(lineRead);
@@ -262,8 +227,11 @@ public class DSpaceCSV implements Serializable {
addItem(lineRead);
}
}
} finally {
if (input != null) {
}
finally
{
if (input != null)
{
input.close();
}
}
@@ -272,7 +240,8 @@ public class DSpaceCSV implements Serializable {
/**
* Initialise this class with values from dspace.cfg
*/
protected void init() {
private void init()
{
// Set the value separator
setValueSeparator();
@@ -283,28 +252,28 @@ public class DSpaceCSV implements Serializable {
setAuthoritySeparator();
// Create the headings
headings = new ArrayList<>();
headings = new ArrayList<String>();
// Create the blank list of items
lines = new ArrayList<>();
lines = new ArrayList<DSpaceCSVLine>();
// Initialise the counter
counter = 0;
// Set the metadata fields to ignore
ignore = new HashMap<>();
// Specify default values
String[] defaultValues =
new String[] {
"dc.date.accessioned, dc.date.available, dc.date.updated, dc.description.provenance"
};
String[] toIgnoreArray =
DSpaceServicesFactory.getInstance()
.getConfigurationService()
.getArrayProperty("bulkedit.ignore-on-export", defaultValues);
for (String toIgnoreString : toIgnoreArray) {
if (!"".equals(toIgnoreString.trim())) {
ignore = new HashMap<String, String>();
String toIgnore = ConfigurationManager.getProperty("bulkedit", "ignore-on-export");
if ((toIgnore == null) || ("".equals(toIgnore.trim())))
{
// Set a default value
toIgnore = "dc.date.accessioned, dc.date.available, " +
"dc.date.updated, dc.description.provenance";
}
String[] toIgnoreArray = toIgnore.split(",");
for (String toIgnoreString : toIgnoreArray)
{
if (!"".equals(toIgnoreString.trim()))
{
ignore.put(toIgnoreString.trim(), toIgnoreString.trim());
}
}
@@ -332,13 +301,16 @@ public class DSpaceCSV implements Serializable {
*
* If not set, defaults to double pipe '||'
*/
private void setValueSeparator() {
private void setValueSeparator()
{
// Get the value separator
valueSeparator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("bulkedit.valueseparator");
if ((valueSeparator != null) && (!"".equals(valueSeparator.trim()))) {
valueSeparator = ConfigurationManager.getProperty("bulkedit", "valueseparator");
if ((valueSeparator != null) && (!"".equals(valueSeparator.trim())))
{
valueSeparator = valueSeparator.trim();
} else {
}
else
{
valueSeparator = "||";
}
@@ -358,22 +330,32 @@ public class DSpaceCSV implements Serializable {
* Special values are 'tab', 'hash' and 'semicolon' which will
* get substituted from the text to the value.
*/
private void setFieldSeparator() {
private void setFieldSeparator()
{
// Get the value separator
fieldSeparator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("bulkedit.fieldseparator");
if ((fieldSeparator != null) && (!"".equals(fieldSeparator.trim()))) {
fieldSeparator = ConfigurationManager.getProperty("bulkedit", "fieldseparator");
if ((fieldSeparator != null) && (!"".equals(fieldSeparator.trim())))
{
fieldSeparator = fieldSeparator.trim();
if ("tab".equals(fieldSeparator)) {
if ("tab".equals(fieldSeparator))
{
fieldSeparator = "\t";
} else if ("semicolon".equals(fieldSeparator)) {
}
else if ("semicolon".equals(fieldSeparator))
{
fieldSeparator = ";";
} else if ("hash".equals(fieldSeparator)) {
}
else if ("hash".equals(fieldSeparator))
{
fieldSeparator = "#";
} else {
}
else
{
fieldSeparator = fieldSeparator.trim();
}
} else {
}
else
{
fieldSeparator = ",";
}
@@ -383,20 +365,23 @@ public class DSpaceCSV implements Serializable {
escapedFieldSeparator = match.replaceAll("\\\\$1");
}
/**
/**
* Set the authority separator for value with authority data.
*
* Is set in dspace.cfg as bulkedit.authorityseparator
*
* If not set, defaults to double colon '::'
*/
private void setAuthoritySeparator() {
private void setAuthoritySeparator()
{
// Get the value separator
authoritySeparator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("bulkedit.authorityseparator");
if ((authoritySeparator != null) && (!"".equals(authoritySeparator.trim()))) {
authoritySeparator = ConfigurationManager.getProperty("bulkedit", "authorityseparator");
if ((authoritySeparator != null) && (!"".equals(authoritySeparator.trim())))
{
authoritySeparator = authoritySeparator.trim();
} else {
}
else
{
authoritySeparator = "::";
}
@@ -410,9 +395,11 @@ public class DSpaceCSV implements Serializable {
* Add a DSpace item to the CSV file
*
* @param i The DSpace item
*
* @throws Exception if something goes wrong with adding the Item
*/
public final void addItem(Item i) throws Exception {
public final void addItem(Item i) throws Exception
{
// If the item does not have an "owningCollection" the the below "getHandle()" call will fail
// This should not happen but is here for safety.
if (i.getOwningCollection() == null) {
@@ -427,43 +414,48 @@ public class DSpaceCSV implements Serializable {
line.add("collection", owningCollectionHandle);
// Add in any mapped collections
List<Collection> collections = i.getCollections();
for (Collection c : collections) {
Collection[] collections = i.getCollections();
for (Collection c : collections)
{
// Only add if it is not the owning collection
if (!c.getHandle().equals(owningCollectionHandle)) {
if (!c.getHandle().equals(owningCollectionHandle))
{
line.add("collection", c.getHandle());
}
}
// Populate it
List<MetadataValue> md = itemService.getMetadata(i, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
for (MetadataValue value : md) {
MetadataField metadataField = value.getMetadataField();
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
Metadatum md[] = i.getMetadata(Item.ANY, Item.ANY, Item.ANY, Item.ANY);
for (Metadatum value : md)
{
// Get the key (schema.element)
String key = metadataSchema.getName() + "." + metadataField.getElement();
String key = value.schema + "." + value.element;
// Add the qualifier if there is one (schema.element.qualifier)
if (metadataField.getQualifier() != null) {
key = key + "." + metadataField.getQualifier();
if (value.qualifier != null)
{
key = key + "." + value.qualifier;
}
// Add the language if there is one (schema.element.qualifier[langauge])
//if ((value.language != null) && (!"".equals(value.language)))
if (value.getLanguage() != null) {
key = key + "[" + value.getLanguage() + "]";
if (value.language != null)
{
key = key + "[" + value.language + "]";
}
// Store the item
if (exportAll || okToExport(metadataField)) {
if (exportAll || okToExport(value))
{
// Add authority and confidence if authority is not null
String mdValue = value.getValue();
if (value.getAuthority() != null && !"".equals(value.getAuthority())) {
mdValue += authoritySeparator + value.getAuthority() + authoritySeparator + (value
.getConfidence() != -1 ? value.getConfidence() : Choices.CF_ACCEPTED);
String mdValue = value.value;
if (value.authority != null && !"".equals(value.authority))
{
mdValue += authoritySeparator + value.authority + authoritySeparator + (value.confidence != -1 ? value.confidence : Choices.CF_ACCEPTED);
}
line.add(key, mdValue);
if (!headings.contains(key)) {
if (!headings.contains(key))
{
headings.add(key);
}
}
@@ -478,10 +470,12 @@ public class DSpaceCSV implements Serializable {
* @param line The line of elements
* @throws Exception Thrown if an error occurs when adding the item
*/
public final void addItem(String line) throws Exception {
public final void addItem(String line) throws Exception
{
// Check to see if the last character is a field separator, which hides the last empty column
boolean last = false;
if (line.endsWith(fieldSeparator)) {
if (line.endsWith(fieldSeparator))
{
// Add a space to the end, then remove it later
last = true;
line += " ";
@@ -489,17 +483,20 @@ public class DSpaceCSV implements Serializable {
// Split up on field separator
String[] parts = line.split(escapedFieldSeparator);
ArrayList<String> bits = new ArrayList<>();
ArrayList<String> bits = new ArrayList<String>();
bits.addAll(Arrays.asList(parts));
// Merge parts with embedded separators
boolean alldone = false;
while (!alldone) {
while (!alldone)
{
boolean found = false;
int i = 0;
for (String part : bits) {
for (String part : bits)
{
int bitcounter = part.length() - part.replaceAll("\"", "").length();
if ((part.startsWith("\"")) && ((!part.endsWith("\"")) || ((bitcounter & 1) == 1))) {
if ((part.startsWith("\"")) && ((!part.endsWith("\"")) || ((bitcounter & 1) == 1)))
{
found = true;
String add = bits.get(i) + fieldSeparator + bits.get(i + 1);
bits.remove(i);
@@ -514,8 +511,10 @@ public class DSpaceCSV implements Serializable {
// Deal with quotes around the elements
int i = 0;
for (String part : bits) {
if ((part.startsWith("\"")) && (part.endsWith("\""))) {
for (String part : bits)
{
if ((part.startsWith("\"")) && (part.endsWith("\"")))
{
part = part.substring(1, part.length() - 1);
bits.set(i, part);
}
@@ -524,8 +523,10 @@ public class DSpaceCSV implements Serializable {
// Remove embedded quotes
i = 0;
for (String part : bits) {
if (part.contains("\"\"")) {
for (String part : bits)
{
if (part.contains("\"\""))
{
part = part.replaceAll("\"\"", "\"");
bits.set(i, part);
}
@@ -537,25 +538,34 @@ public class DSpaceCSV implements Serializable {
DSpaceCSVLine csvLine;
// Is this an existing item, or a new item (where id = '+')
if ("+".equals(id)) {
if ("+".equals(id))
{
csvLine = new DSpaceCSVLine();
} else {
try {
csvLine = new DSpaceCSVLine(UUID.fromString(id));
} catch (NumberFormatException nfe) {
}
else
{
try
{
csvLine = new DSpaceCSVLine(Integer.parseInt(id));
}
catch (NumberFormatException nfe)
{
System.err.println("Invalid item identifier: " + id);
System.err.println("Please check your CSV file for information. " +
"Item id must be numeric, or a '+' to add a new item");
throw (nfe);
"Item id must be numeric, or a '+' to add a new item");
throw(nfe);
}
}
// Add the rest of the parts
i = 0;
for (String part : bits) {
if (i > 0) {
for (String part : bits)
{
if (i > 0)
{
// Is this a last empty item?
if ((last) && (i == headings.size())) {
if ((last) && (i == headings.size()))
{
part = "";
}
@@ -567,8 +577,10 @@ public class DSpaceCSV implements Serializable {
}
csvLine.add(headings.get(i - 1), null);
String[] elements = part.split(escapedValueSeparator);
for (String element : elements) {
if ((element != null) && (!"".equals(element))) {
for (String element : elements)
{
if ((element != null) && (!"".equals(element)))
{
csvLine.add(headings.get(i - 1), element);
}
}
@@ -584,7 +596,8 @@ public class DSpaceCSV implements Serializable {
*
* @return The lines
*/
public final List<DSpaceCSVLine> getCSVLines() {
public final List<DSpaceCSVLine> getCSVLines()
{
// Return the lines
return lines;
}
@@ -594,20 +607,23 @@ public class DSpaceCSV implements Serializable {
*
* @return the array of CSV formatted Strings
*/
public final String[] getCSVLinesAsStringArray() {
public final String[] getCSVLinesAsStringArray()
{
// Create the headings line
String[] csvLines = new String[counter + 1];
csvLines[0] = "id" + fieldSeparator + "collection";
List<String> headingsCopy = new ArrayList<>(headings);
List<String> headingsCopy = new ArrayList<String>(headings);
Collections.sort(headingsCopy);
for (String value : headingsCopy) {
for (String value : headingsCopy)
{
csvLines[0] = csvLines[0] + fieldSeparator + value;
}
Iterator<DSpaceCSVLine> i = lines.iterator();
int c = 1;
while (i.hasNext()) {
csvLines[c++] = i.next().toCSV(headingsCopy, fieldSeparator, valueSeparator);
while (i.hasNext())
{
csvLines[c++] = i.next().toCSV(headingsCopy);
}
return csvLines;
@@ -617,13 +633,15 @@ public class DSpaceCSV implements Serializable {
* Save the CSV file to the given filename
*
* @param filename The filename to save the CSV file to
*
* @throws IOException Thrown if an error occurs when writing the file
*/
public final void save(String filename) throws IOException {
public final void save(String filename) throws IOException
{
// Save the file
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(filename), "UTF-8"));
new OutputStreamWriter(
new FileOutputStream(filename), "UTF-8"));
for (String csvLine : getCSVLinesAsStringArray()) {
out.write(csvLine + "\n");
}
@@ -640,11 +658,13 @@ public class DSpaceCSV implements Serializable {
* @param md The Metadatum to examine
* @return Whether or not it is OK to export this element
*/
protected boolean okToExport(MetadataField md) {
private final boolean okToExport(Metadatum md)
{
// Now compare with the list to ignore
String key = md.getMetadataSchema().getName() + "." + md.getElement();
if (md.getQualifier() != null) {
key += "." + md.getQualifier();
String key = md.schema + "." + md.element;
if (md.qualifier != null)
{
key += "." + md.qualifier;
}
if (ignore.get(key) != null) {
return false;
@@ -659,7 +679,8 @@ public class DSpaceCSV implements Serializable {
*
* @return The headings
*/
public List<String> getHeadings() {
public List<String> getHeadings()
{
return headings;
}
@@ -668,22 +689,15 @@ public class DSpaceCSV implements Serializable {
*
* @return The formatted String as a csv
*/
@Override
public final String toString() {
public final String toString()
{
// Return the csv as one long string
StringBuilder csvLines = new StringBuilder();
StringBuffer csvLines = new StringBuffer();
String[] lines = this.getCSVLinesAsStringArray();
for (String line : lines) {
for (String line : lines)
{
csvLines.append(line).append("\n");
}
return csvLines.toString();
}
public String getAuthoritySeparator() {
return authoritySeparator;
}
public String getEscapedAuthoritySeparator() {
return escapedAuthoritySeparator;
}
}

View File

@@ -7,52 +7,38 @@
*/
package org.dspace.app.bulkedit;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import org.dspace.authority.AuthorityValue;
import org.dspace.authority.factory.AuthorityServiceFactory;
import org.dspace.authority.service.AuthorityValueService;
import java.io.Serializable;
import java.util.*;
/**
* Utility class to store a line from a CSV file
*
* @author Stuart Lewis
*/
public class DSpaceCSVLine implements Serializable {
/**
* The item id of the item represented by this line. -1 is for a new item
*/
private final UUID id;
public class DSpaceCSVLine implements Serializable
{
/**
* The elements in this line in a hashtable, keyed by the metadata type
*/
private final Map<String, ArrayList> items;
/** The item id of the item represented by this line. -1 is for a new item */
private int id;
protected transient final AuthorityValueService authorityValueService
= AuthorityServiceFactory.getInstance().getAuthorityValueService();
/** The elements in this line in a hashtable, keyed by the metadata type */
private Map<String, ArrayList> items;
/**
* ensuring that the order-sensible columns of the csv are processed in the correct order
*/
private transient final Comparator<? super String> headerComparator = new Comparator<String>() {
/** ensuring that the order-sensible columns of the csv are processed in the correct order */
private final Comparator<? super String> headerComparator = new Comparator<String>() {
@Override
public int compare(String md1, String md2) {
// The metadata coming from an external source should be processed after the others
AuthorityValue source1 = authorityValueService.getAuthorityValueType(md1);
AuthorityValue source2 = authorityValueService.getAuthorityValueType(md2);
AuthorityValue source1 = MetadataImport.getAuthorityValueType(md1);
AuthorityValue source2 = MetadataImport.getAuthorityValueType(md2);
int compare;
if (source1 == null && source2 != null) {
compare = -1;
} else if (source1 != null && source2 == null) {
}
else if (source1 != null && source2 == null) {
compare = 1;
} else {
// the order of the rest does not matter
@@ -67,20 +53,23 @@ public class DSpaceCSVLine implements Serializable {
*
* @param itemId The item ID of the line
*/
public DSpaceCSVLine(UUID itemId) {
public DSpaceCSVLine(int itemId)
{
// Store the ID + separator, and initialise the hashtable
this.id = itemId;
items = new TreeMap<>(headerComparator);
items = new TreeMap<String, ArrayList>(headerComparator);
// this.items = new HashMap<String, ArrayList>();
}
/**
* Create a new CSV line for a new item
*/
public DSpaceCSVLine() {
// Set the ID to be null, and initialise the hashtable
this.id = null;
this.items = new TreeMap<>(headerComparator);
public DSpaceCSVLine()
{
// Set the ID to be -1, and initialise the hashtable
this.id = -1;
this.items = new TreeMap<String, ArrayList>(headerComparator);
// this.items = new HashMap<String, ArrayList>();
}
/**
@@ -88,7 +77,8 @@ public class DSpaceCSVLine implements Serializable {
*
* @return The item ID
*/
public UUID getID() {
public int getID()
{
// Return the ID
return id;
}
@@ -96,17 +86,20 @@ public class DSpaceCSVLine implements Serializable {
/**
* Add a new metadata value to this line
*
* @param key The metadata key (e.g. dc.contributor.author)
* @param key The metadata key (e.g. dc.contributor.author)
* @param value The metadata value
*/
public void add(String key, String value) {
public void add(String key, String value)
{
// Create the array list if we need to
if (items.get(key) == null) {
if (items.get(key) == null)
{
items.put(key, new ArrayList<String>());
}
// Store the item if it is not null
if (value != null) {
if (value != null)
{
items.get(key).add(value);
}
}
@@ -117,7 +110,8 @@ public class DSpaceCSVLine implements Serializable {
* @param key The metadata key
* @return All the elements that match
*/
public List<String> get(String key) {
public List<String> get(String key)
{
// Return any relevant values
return items.get(key);
}
@@ -127,11 +121,12 @@ public class DSpaceCSVLine implements Serializable {
*
* @return The action (may be blank, 'withdraw', 'reinstate' or 'delete')
*/
public String getAction() {
public String getAction()
{
if (items.containsKey("action")) {
ArrayList actions = items.get("action");
if (actions.size() > 0) {
return ((String) actions.get(0)).trim();
return ((String)actions.get(0)).trim();
}
}
return "";
@@ -142,7 +137,8 @@ public class DSpaceCSVLine implements Serializable {
*
* @return An enumeration of all the keys
*/
public Set<String> keys() {
public Set<String> keys()
{
// Return the keys
return items.keySet();
}
@@ -150,24 +146,25 @@ public class DSpaceCSVLine implements Serializable {
/**
* Write this line out as a CSV formatted string, in the order given by the headings provided
*
* @param headings The headings which define the order the elements must be presented in
* @param fieldSeparator separator between metadata fields
* @param valueSeparator separator between metadata values (within a field)
* @param headings The headings which define the order the elements must be presented in
* @return The CSV formatted String
*/
protected String toCSV(List<String> headings, String fieldSeparator, String valueSeparator) {
protected String toCSV(List<String> headings)
{
StringBuilder bits = new StringBuilder();
// Add the id
bits.append("\"").append(id).append("\"").append(fieldSeparator);
bits.append(valueToCSV(items.get("collection"), valueSeparator));
bits.append("\"").append(id).append("\"").append(DSpaceCSV.fieldSeparator);
bits.append(valueToCSV(items.get("collection")));
// Add the rest of the elements
for (String heading : headings) {
bits.append(fieldSeparator);
for (String heading : headings)
{
bits.append(DSpaceCSV.fieldSeparator);
List<String> values = items.get(heading);
if (values != null && !"collection".equals(heading)) {
bits.append(valueToCSV(values, valueSeparator));
if (values != null && !"collection".equals(heading))
{
bits.append(valueToCSV(values));
}
}
@@ -177,27 +174,33 @@ public class DSpaceCSVLine implements Serializable {
/**
* Internal method to create a CSV formatted String joining a given set of elements
*
* @param values The values to create the string from
* @param valueSeparator value separator
* @param values The values to create the string from
* @return The line as a CSV formatted String
*/
protected String valueToCSV(List<String> values, String valueSeparator) {
protected String valueToCSV(List<String> values)
{
// Check there is some content
if (values == null) {
if (values == null)
{
return "";
}
// Get on with the work
String s;
if (values.size() == 1) {
if (values.size() == 1)
{
s = values.get(0);
} else {
}
else
{
// Concatenate any fields together
StringBuilder str = new StringBuilder();
for (String value : values) {
if (str.length() > 0) {
str.append(valueSeparator);
for (String value : values)
{
if (str.length() > 0)
{
str.append(DSpaceCSV.valueSeparator);
}
str.append(value);

View File

@@ -7,84 +7,61 @@
*/
package org.dspace.app.bulkedit;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.cli.*;
import com.google.common.collect.Iterators;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.content.*;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.HandleManager;
import java.util.ArrayList;
import java.sql.SQLException;
import java.util.List;
/**
* Metadata exporter to allow the batch export of metadata into a file
*
* @author Stuart Lewis
*/
public class MetadataExport {
/**
* The items to export
*/
protected Iterator<Item> toExport;
public class MetadataExport
{
/** The items to export */
private ItemIterator toExport;
protected ItemService itemService;
protected Context context;
/**
* Whether to export all metadata, or just normally edited metadata
*/
protected boolean exportAll;
protected MetadataExport() {
itemService = ContentServiceFactory.getInstance().getItemService();
}
/** Whether to export all metadata, or just normally edited metadata */
private boolean exportAll;
/**
* Set up a new metadata export
*
* @param c The Context
* @param toExport The ItemIterator of items to export
* @param c The Context
* @param toExport The ItemIterator of items to export
* @param exportAll whether to export all metadata or not (include handle, provenance etc)
*/
public MetadataExport(Context c, Iterator<Item> toExport, boolean exportAll) {
itemService = ContentServiceFactory.getInstance().getItemService();
public MetadataExport(Context c, ItemIterator toExport, boolean exportAll)
{
// Store the export settings
this.toExport = toExport;
this.exportAll = exportAll;
this.context = c;
}
/**
* Method to export a community (and sub-communities and collections)
*
* @param c The Context
* @param toExport The Community to export
* @param c The Context
* @param toExport The Community to export
* @param exportAll whether to export all metadata or not (include handle, provenance etc)
*/
public MetadataExport(Context c, Community toExport, boolean exportAll) {
itemService = ContentServiceFactory.getInstance().getItemService();
try {
public MetadataExport(Context c, Community toExport, boolean exportAll)
{
try
{
// Try to export the community
this.toExport = buildFromCommunity(c, toExport, 0);
this.toExport = new ItemIterator(c, buildFromCommunity(toExport, new ArrayList<Integer>(), 0));
this.exportAll = exportAll;
this.context = c;
} catch (SQLException sqle) {
}
catch (SQLException sqle)
{
// Something went wrong...
System.err.println("Error running exporter:");
sqle.printStackTrace(System.err);
@@ -95,47 +72,48 @@ public class MetadataExport {
/**
* Build an array list of item ids that are in a community (include sub-communities and collections)
*
* @param context DSpace context
* @param community The community to build from
* @param indent How many spaces to use when writing out the names of items added
* @param itemIDs The itemID (used for recursion - use an empty ArrayList)
* @param indent How many spaces to use when writing out the names of items added
* @return The list of item ids
* @throws SQLException if database error
* @throws SQLException
*/
protected Iterator<Item> buildFromCommunity(Context context, Community community, int indent)
throws SQLException {
private List<Integer> buildFromCommunity(Community community, List<Integer> itemIDs, int indent)
throws SQLException
{
// Add all the collections
List<Collection> collections = community.getCollections();
Iterator<Item> result = null;
for (Collection collection : collections) {
for (int i = 0; i < indent; i++) {
Collection[] collections = community.getCollections();
for (Collection collection : collections)
{
for (int i = 0; i < indent; i++)
{
System.out.print(" ");
}
Iterator<Item> items = itemService.findByCollection(context, collection);
result = addItemsToResult(result, items);
ItemIterator items = collection.getAllItems();
while (items.hasNext())
{
int id = items.next().getID();
// Only add if not already included (so mapped items only appear once)
if (!itemIDs.contains(id))
{
itemIDs.add(id);
}
}
}
// Add all the sub-communities
List<Community> communities = community.getSubcommunities();
for (Community subCommunity : communities) {
for (int i = 0; i < indent; i++) {
Community[] communities = community.getSubcommunities();
for (Community subCommunity : communities)
{
for (int i = 0; i < indent; i++)
{
System.out.print(" ");
}
Iterator<Item> items = buildFromCommunity(context, subCommunity, indent + 1);
result = addItemsToResult(result, items);
buildFromCommunity(subCommunity, itemIDs, indent + 1);
}
return result;
}
private Iterator<Item> addItemsToResult(Iterator<Item> result, Iterator<Item> items) {
if (result == null) {
result = items;
} else {
result = Iterators.concat(result, items);
}
return result;
return itemIDs;
}
/**
@@ -143,23 +121,22 @@ public class MetadataExport {
*
* @return the exported CSV lines
*/
public DSpaceCSV export() {
try {
Context.Mode originalMode = context.getCurrentMode();
context.setMode(Context.Mode.READ_ONLY);
public DSpaceCSV export()
{
try
{
// Process each item
DSpaceCSV csv = new DSpaceCSV(exportAll);
while (toExport.hasNext()) {
Item item = toExport.next();
csv.addItem(item);
context.uncacheEntity(item);
while (toExport.hasNext())
{
csv.addItem(toExport.next());
}
context.setMode(originalMode);
// Return the results
return csv;
} catch (Exception e) {
}
catch (Exception e)
{
// Something went wrong...
System.err.println("Error exporting to CSV:");
e.printStackTrace();
@@ -170,10 +147,11 @@ public class MetadataExport {
/**
* Print the help message
*
* @param options The command line options the user gave
* @param options The command line options the user gave
* @param exitCode the system exit code to use
*/
private static void printHelp(Options options, int exitCode) {
private static void printHelp(Options options, int exitCode)
{
// print the help message
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("MetadataExport\n", options);
@@ -183,12 +161,12 @@ public class MetadataExport {
}
/**
* main method to run the metadata exporter
*
* @param argv the command line arguments given
* @throws Exception if error occurs
*/
public static void main(String[] argv) throws Exception {
* main method to run the metadata exporter
*
* @param argv the command line arguments given
*/
public static void main(String[] argv) throws Exception
{
// Create an options object and populate it
CommandLineParser parser = new PosixParser();
@@ -196,70 +174,83 @@ public class MetadataExport {
options.addOption("i", "id", true, "ID or handle of thing to export (item, collection, or community)");
options.addOption("f", "file", true, "destination where you want file written");
options.addOption("a", "all", false,
"include all metadata fields that are not normally changed (e.g. provenance)");
options.addOption("a", "all", false, "include all metadata fields that are not normally changed (e.g. provenance)");
options.addOption("h", "help", false, "help");
CommandLine line = null;
try {
try
{
line = parser.parse(options, argv);
} catch (ParseException pe) {
}
catch (ParseException pe)
{
System.err.println("Error with commands.");
printHelp(options, 1);
System.exit(0);
}
if (line.hasOption('h')) {
if (line.hasOption('h'))
{
printHelp(options, 0);
}
// Check a filename is given
if (!line.hasOption('f')) {
if (!line.hasOption('f'))
{
System.err.println("Required parameter -f missing!");
printHelp(options, 1);
}
String filename = line.getOptionValue('f');
// Create a context
Context c = new Context(Context.Mode.READ_ONLY);
Context c = new Context();
c.turnOffAuthorisationSystem();
// The things we'll export
Iterator<Item> toExport = null;
ItemIterator toExport = null;
MetadataExport exporter = null;
// Export everything?
boolean exportAll = line.hasOption('a');
ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance();
// Check we have an item OK
ItemService itemService = contentServiceFactory.getItemService();
if (!line.hasOption('i')) {
if (!line.hasOption('i'))
{
System.out.println("Exporting whole repository WARNING: May take some time!");
exporter = new MetadataExport(c, itemService.findAll(c), exportAll);
} else {
exporter = new MetadataExport(c, Item.findAll(c), exportAll);
}
else
{
String handle = line.getOptionValue('i');
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(c, handle);
if (dso == null) {
DSpaceObject dso = HandleManager.resolveToObject(c, handle);
if (dso == null)
{
System.err.println("Item '" + handle + "' does not resolve to an item in your repository!");
printHelp(options, 1);
}
if (dso.getType() == Constants.ITEM) {
if (dso.getType() == Constants.ITEM)
{
System.out.println("Exporting item '" + dso.getName() + "' (" + handle + ")");
List<Item> item = new ArrayList<>();
item.add((Item) dso);
exporter = new MetadataExport(c, item.iterator(), exportAll);
} else if (dso.getType() == Constants.COLLECTION) {
List<Integer> item = new ArrayList<Integer>();
item.add(dso.getID());
exporter = new MetadataExport(c, new ItemIterator(c, item), exportAll);
}
else if (dso.getType() == Constants.COLLECTION)
{
System.out.println("Exporting collection '" + dso.getName() + "' (" + handle + ")");
Collection collection = (Collection) dso;
toExport = itemService.findByCollection(c, collection);
Collection collection = (Collection)dso;
toExport = collection.getAllItems();
exporter = new MetadataExport(c, toExport, exportAll);
} else if (dso.getType() == Constants.COMMUNITY) {
}
else if (dso.getType() == Constants.COMMUNITY)
{
System.out.println("Exporting community '" + dso.getName() + "' (" + handle + ")");
exporter = new MetadataExport(c, (Community) dso, exportAll);
} else {
exporter = new MetadataExport(c, (Community)dso, exportAll);
}
else
{
System.err.println("Error identifying '" + handle + "'");
System.exit(1);
}
@@ -269,7 +260,7 @@ public class MetadataExport {
DSpaceCSV csv = exporter.export();
// Save the files to the file
csv.save(filename);
csv.save(filename);
// Finish off and tidy up
c.restoreAuthSystemState();

View File

@@ -12,23 +12,26 @@ package org.dspace.app.bulkedit;
*
* @author Stuart Lewis
*/
public class MetadataImportException extends Exception {
public class MetadataImportException extends Exception
{
/**
* Instantiate a new MetadataImportException
*
* @param message the error message
*/
public MetadataImportException(String message) {
super(message);
public MetadataImportException(String message)
{
super(message);
}
/**
* Instantiate a new MetadataImportException
*
* @param message the error message
* @param message the error message
* @param exception the root cause
*/
public MetadataImportException(String message, Exception exception) {
super(message, exception);
public MetadataImportException(String message, Exception exception)
{
super(message, exception);
}
}
}

View File

@@ -12,51 +12,38 @@ package org.dspace.app.bulkedit;
*
* @author Stuart Lewis
*/
public class MetadataImportInvalidHeadingException extends Exception {
/**
* The type of error (schema or element)
*/
public class MetadataImportInvalidHeadingException extends Exception
{
/** The type of error (schema or element) */
private int type;
/**
* The bad heading
*/
/** The bad heading */
private String badHeading;
/**
* The column number
*/
/** The column number */
private int column;
/**
* Error with the schema
*/
/** Error with the schema */
public static final int SCHEMA = 0;
/**
* Error with the element
*/
/** Error with the element */
public static final int ELEMENT = 1;
/**
* Error with a missing header
*/
/** Error with a missing header */
public static final int MISSING = 98;
/**
* Error with the whole entry
*/
/** Error with the whole entry */
public static final int ENTRY = 99;
/**
* Instantiate a new MetadataImportInvalidHeadingException
*
* @param message the error message
* @param theType the type of the error
* @param theColumn column number
* @param message the error message
* @param theType the type of the error
*/
public MetadataImportInvalidHeadingException(String message, int theType, int theColumn) {
public MetadataImportInvalidHeadingException(String message, int theType, int theColumn)
{
super(message);
badHeading = message;
type = theType;
@@ -66,9 +53,10 @@ public class MetadataImportInvalidHeadingException extends Exception {
/**
* Get the type of the exception
*
* @return the type of the exception
* @return the type of the exception
*/
public String getType() {
public String getType()
{
return "" + type;
}
@@ -77,7 +65,8 @@ public class MetadataImportInvalidHeadingException extends Exception {
*
* @return the invalid heading
*/
public String getBadHeader() {
public String getBadHeader()
{
return badHeading;
}
@@ -86,7 +75,8 @@ public class MetadataImportInvalidHeadingException extends Exception {
*
* @return the invalid column number
*/
public int getColumn() {
public int getColumn()
{
return column;
}
@@ -95,15 +85,19 @@ public class MetadataImportInvalidHeadingException extends Exception {
*
* @return The exception message
*/
@Override
public String getMessage() {
if (type == SCHEMA) {
public String getMessage()
{
if (type == SCHEMA)
{
return "Unknown metadata schema in column " + column + ": " + badHeading;
} else if (type == ELEMENT) {
} else if (type == ELEMENT)
{
return "Unknown metadata element in column " + column + ": " + badHeading;
} else if (type == MISSING) {
} else if (type == MISSING)
{
return "Row with missing header: column " + column;
} else {
} else
{
return "Bad metadata declaration in column" + column + ": " + badHeading;
}
}

View File

@@ -9,6 +9,7 @@
/**
* <p>The DSpace Batch Metadata Editor, which uses a CSV file to export/import
* item metadata.</p>
* <p>
* <ul>
* <li>works on items, communities, collections or the whole site</li>
* <li>can also create new items, delete items and withdraw/restore them</li>

View File

@@ -13,7 +13,6 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
@@ -25,64 +24,61 @@ import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.Logger;
import org.dspace.checker.BitstreamDispatcher;
import org.dspace.checker.BitstreamInfoDAO;
import org.dspace.checker.CheckerCommand;
import org.dspace.checker.HandleDispatcher;
import org.dspace.checker.IteratorDispatcher;
import org.dspace.checker.LimitedCountDispatcher;
import org.dspace.checker.LimitedDurationDispatcher;
import org.dspace.checker.ListDispatcher;
import org.dspace.checker.ResultsLogger;
import org.dspace.checker.ResultsPruner;
import org.dspace.checker.SimpleDispatcher;
import org.dspace.content.Bitstream;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.core.Context;
import org.dspace.core.Utils;
/**
* Command line access to the checksum checker. Options are listed in the
* documentation for the main method.
*
* Command line access to the checksum checker. Options are listed in the
* documentation for the main method.</p>
*
* @author Jim Downing
* @author Grace Carpenter
* @author Nathan Sarr
*/
public final class ChecksumChecker {
public final class ChecksumChecker
{
private static final Logger LOG = Logger.getLogger(ChecksumChecker.class);
private static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
/**
* Blanked off constructor, this class should be used as a command line
* tool.
*
*/
private ChecksumChecker() {
private ChecksumChecker()
{
}
/**
* Command line access to the checksum package.
*
* <dl>
* <dt>-h</dt>
* <dd>Print help on command line options</dd>
* <dt>-l</dt>
* <dd>loop through bitstreams once</dd>
* <dt>-L</dt>
* <dd>loop continuously through bitstreams</dd>
* <dt>-d</dt>
* <dd>specify duration of process run</dd>
* <dt>-b</dt>
* <dd>specify bitstream IDs</dd>
* <dt>-a [handle_id]</dt>
* <dd>check anything by handle</dd>
* <dt>-e</dt>
* <dd>Report only errors in the logs</dd>
* <dt>-p</dt>
* <dd>Don't prune results before running checker</dd>
* </dl>
*
* @param args the command line arguments given
* @throws SQLException if error
*
* @param args
* <dl>
* <dt>-h</dt>
* <dd>Print help on command line options</dd>
* <dt>-l</dt>
* <dd>loop through bitstreams once</dd>
* <dt>-L</dt>
* <dd>loop continuously through bitstreams</dd>
* <dt>-d</dt>
* <dd>specify duration of process run</dd>
* <dt>-b</dt>
* <dd>specify bitstream IDs</dd>
* <dt>-a [handle_id]</dt>
* <dd>check anything by handle</dd>
* <dt>-e</dt>
* <dd>Report only errors in the logs</dd>
* <dt>-p</dt>
* <dd>Don't prune results before running checker</dd>
* </dl>
*/
public static void main(String[] args) throws SQLException {
// set up command line parser
@@ -94,7 +90,7 @@ public final class ChecksumChecker {
options.addOption("l", "looping", false, "Loop once through bitstreams");
options.addOption("L", "continuous", false,
"Loop continuously through bitstreams");
"Loop continuously through bitstreams");
options.addOption("h", "help", false, "Help");
options.addOption("d", "duration", true, "Checking duration");
options.addOption("c", "count", true, "Check count");
@@ -102,140 +98,172 @@ public final class ChecksumChecker {
options.addOption("v", "verbose", false, "Report all processing");
OptionBuilder.withArgName("bitstream-ids").hasArgs().withDescription(
"Space separated list of bitstream ids");
"Space separated list of bitstream ids");
Option useBitstreamIds = OptionBuilder.create('b');
options.addOption(useBitstreamIds);
options.addOption("p", "prune", false, "Prune configuration file");
options.addOption(OptionBuilder
.withArgName("prune")
.hasOptionalArgs(1)
.withDescription(
"Prune old results (optionally using specified properties file for configuration)")
.create('p'));
options
.addOption(OptionBuilder
.withArgName("prune")
.hasOptionalArgs(1)
.withDescription(
"Prune old results (optionally using specified properties file for configuration)")
.create('p'));
try {
try
{
line = parser.parse(options, args);
} catch (ParseException e) {
}
catch (ParseException e)
{
LOG.fatal(e);
System.exit(1);
}
// user asks for help
if (line.hasOption('h')) {
if (line.hasOption('h'))
{
printHelp(options);
}
Context context = null;
try {
context = new Context();
// Prune stage
if (line.hasOption('p')) {
ResultsPruner rp = null;
try {
rp = (line.getOptionValue('p') != null) ? ResultsPruner
.getPruner(context, line.getOptionValue('p')) : ResultsPruner
.getDefaultPruner(context);
} catch (FileNotFoundException e) {
LOG.error("File not found", e);
System.exit(1);
}
int count = rp.prune();
System.out.println("Pruned " + count
+ " old results from the database.");
// Prune stage
if (line.hasOption('p'))
{
ResultsPruner rp = null;
try
{
rp = (line.getOptionValue('p') != null) ? ResultsPruner
.getPruner(line.getOptionValue('p')) : ResultsPruner
.getDefaultPruner();
}
catch (FileNotFoundException e)
{
LOG.error("File not found", e);
System.exit(1);
}
int count = rp.prune();
System.out.println("Pruned " + count
+ " old results from the database.");
}
Date processStart = Calendar.getInstance().getTime();
Date processStart = Calendar.getInstance().getTime();
BitstreamDispatcher dispatcher = null;
BitstreamDispatcher dispatcher = null;
// process should loop infinitely through
// most_recent_checksum table
if (line.hasOption('l'))
{
dispatcher = new SimpleDispatcher(new BitstreamInfoDAO(), processStart, false);
}
else if (line.hasOption('L'))
{
dispatcher = new SimpleDispatcher(new BitstreamInfoDAO(), processStart, true);
}
else if (line.hasOption('b'))
{
// check only specified bitstream(s)
String[] ids = line.getOptionValues('b');
List<Integer> idList = new ArrayList<Integer>(ids.length);
// process should loop infinitely through
// most_recent_checksum table
if (line.hasOption('l')) {
dispatcher = new SimpleDispatcher(context, processStart, false);
} else if (line.hasOption('L')) {
dispatcher = new SimpleDispatcher(context, processStart, true);
} else if (line.hasOption('b')) {
// check only specified bitstream(s)
String[] ids = line.getOptionValues('b');
List<Bitstream> bitstreams = new ArrayList<>(ids.length);
for (int i = 0; i < ids.length; i++) {
try {
bitstreams.add(bitstreamService.find(context, UUID.fromString(ids[i])));
} catch (NumberFormatException nfe) {
System.err.println("The following argument: " + ids[i]
+ " is not an integer");
System.exit(0);
}
for (int i = 0; i < ids.length; i++)
{
try
{
idList.add(Integer.valueOf(ids[i]));
}
dispatcher = new IteratorDispatcher(bitstreams.iterator());
} else if (line.hasOption('a')) {
dispatcher = new HandleDispatcher(context, line.getOptionValue('a'));
} else if (line.hasOption('d')) {
// run checker process for specified duration
try {
dispatcher = new LimitedDurationDispatcher(
new SimpleDispatcher(context, processStart, true), new Date(
System.currentTimeMillis()
+ Utils.parseDuration(line
.getOptionValue('d'))));
} catch (Exception e) {
LOG.fatal("Couldn't parse " + line.getOptionValue('d')
+ " as a duration: ", e);
catch (NumberFormatException nfe)
{
System.err.println("The following argument: " + ids[i]
+ " is not an integer");
System.exit(0);
}
} else if (line.hasOption('c')) {
int count = Integer.valueOf(line.getOptionValue('c'));
// run checker process for specified number of bitstreams
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher(
context, processStart, false), count);
} else {
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher(
context, processStart, false), 1);
}
dispatcher = new ListDispatcher(idList);
}
ResultsLogger logger = new ResultsLogger(processStart);
CheckerCommand checker = new CheckerCommand(context);
// verbose reporting
if (line.hasOption('v')) {
checker.setReportVerbose(true);
else if (line.hasOption('a'))
{
dispatcher = new HandleDispatcher(new BitstreamInfoDAO(), line.getOptionValue('a'));
}
else if (line.hasOption('d'))
{
// run checker process for specified duration
try
{
dispatcher = new LimitedDurationDispatcher(
new SimpleDispatcher(new BitstreamInfoDAO(), processStart, true), new Date(
System.currentTimeMillis()
+ Utils.parseDuration(line
.getOptionValue('d'))));
}
checker.setProcessStartDate(processStart);
checker.setDispatcher(dispatcher);
checker.setCollector(logger);
checker.process();
context.complete();
context = null;
} finally {
if (context != null) {
context.abort();
catch (Exception e)
{
LOG.fatal("Couldn't parse " + line.getOptionValue('d')
+ " as a duration: ", e);
System.exit(0);
}
}
else if (line.hasOption('c'))
{
int count = Integer.valueOf(line.getOptionValue('c')).intValue();
// run checker process for specified number of bitstreams
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher(
new BitstreamInfoDAO(), processStart, false), count);
}
else
{
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher(
new BitstreamInfoDAO(), processStart, false), 1);
}
ResultsLogger logger = new ResultsLogger(processStart);
CheckerCommand checker = new CheckerCommand();
// verbose reporting
if (line.hasOption('v'))
{
checker.setReportVerbose(true);
}
checker.setProcessStartDate(processStart);
checker.setDispatcher(dispatcher);
checker.setCollector(logger);
Context context = new Context();
try {
checker.process(context);
} finally {
context.commit();
context.complete();
}
System.exit(0);
}
/**
* Print the help options for the user
*
*
* @param options that are available for the user
*/
private static void printHelp(Options options) {
private static void printHelp(Options options)
{
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("Checksum Checker\n", options);
System.out.println("\nSpecify a duration for checker process, using s(seconds),"
+ "m(minutes), or h(hours): ChecksumChecker -d 30s"
+ " OR ChecksumChecker -d 30m"
+ " OR ChecksumChecker -d 2h");
System.out.println("\nSpecify bitstream IDs: ChecksumChecker -b 13 15 17 20");
System.out
.println("\nSpecify a duration for checker process, using s(seconds),"
+ "m(minutes), or h(hours): ChecksumChecker -d 30s"
+ " OR ChecksumChecker -d 30m"
+ " OR ChecksumChecker -d 2h");
System.out
.println("\nSpecify bitstream IDs: ChecksumChecker -b 13 15 17 20");
System.out.println("\nLoop once through all bitstreams: "
+ "ChecksumChecker -l");
System.out.println("\nLoop continuously through all bitstreams: ChecksumChecker -L");
System.out.println("\nCheck a defined number of bitstreams: ChecksumChecker -c 10");
+ "ChecksumChecker -l");
System.out
.println("\nLoop continuously through all bitstreams: ChecksumChecker -L");
System.out
.println("\nCheck a defined number of bitstreams: ChecksumChecker -c 10");
System.out.println("\nReport all processing (verbose)(default reports only errors): ChecksumChecker -v");
System.out.println("\nDefault (no arguments) is equivalent to '-c 1'");
System.exit(0);

View File

@@ -7,12 +7,12 @@
*/
package org.dspace.app.configuration;
import java.io.File;
import java.net.MalformedURLException;
import org.dspace.kernel.config.SpringLoader;
import org.dspace.services.ConfigurationService;
import java.io.File;
import java.net.MalformedURLException;
/**
* @author Kevin Van de Velde (kevin at atmire dot com)
*/
@@ -32,7 +32,7 @@ public class APISpringLoader implements SpringLoader {
try {
return new String[] {new File(filePath.toString()).toURI().toURL().toString() + XML_SUFFIX};
return new String[]{new File(filePath.toString()).toURI().toURL().toString() + XML_SUFFIX};
} catch (MalformedURLException e) {
return new String[0];
}

View File

@@ -9,9 +9,7 @@ package org.dspace.app.harvest;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
@@ -19,39 +17,30 @@ import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.dspace.authorize.AuthorizeException;
import org.dspace.browse.IndexBrowse;
import org.dspace.content.Collection;
import org.dspace.content.DSpaceObject;
import org.dspace.harvest.HarvestedCollection;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.ItemService;
import org.dspace.content.ItemIterator;
import org.dspace.harvest.OAIHarvester;
import org.dspace.harvest.OAIHarvester.HarvestingException;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.harvest.HarvestedCollection;
import org.dspace.harvest.HarvestingException;
import org.dspace.harvest.OAIHarvester;
import org.dspace.harvest.factory.HarvestServiceFactory;
import org.dspace.harvest.service.HarvestedCollectionService;
import org.dspace.handle.HandleManager;
/**
* Test class for harvested collections.
* Test class for harvested collections.
*
* @author Alexey Maslov
*/
public class Harvest {
public class Harvest
{
private static Context context;
private static final HarvestedCollectionService harvestedCollectionService =
HarvestServiceFactory.getInstance().getHarvestedCollectionService();
private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
private static final CollectionService collectionService =
ContentServiceFactory.getInstance().getCollectionService();
public static void main(String[] argv) throws Exception {
public static void main(String[] argv) throws Exception
{
// create an options object and populate it
CommandLineParser parser = new PosixParser();
@@ -65,50 +54,49 @@ public class Harvest {
options.addOption("S", "start", false, "start the harvest loop");
options.addOption("R", "reset", false, "reset harvest status on all collections");
options.addOption("P", "purge", false, "purge all harvestable collections");
options.addOption("e", "eperson", true,
"eperson");
options.addOption("c", "collection", true,
"harvesting collection (handle or id)");
options.addOption("t", "type", true,
"type of harvesting (0 for none)");
options.addOption("a", "address", true,
"address of the OAI-PMH server");
options.addOption("i", "oai_set_id", true,
"id of the PMH set representing the harvested collection");
options.addOption("m", "metadata_format", true,
"the name of the desired metadata format for harvesting, resolved to namespace and " +
"crosswalk in dspace.cfg");
options.addOption("e", "eperson", true, "eperson");
options.addOption("c", "collection", true, "harvesting collection (handle or id)");
options.addOption("t", "type", true, "type of harvesting (0 for none)");
options.addOption("a", "address", true, "address of the OAI-PMH server");
options.addOption("i", "oai_set_id", true, "id of the PMH set representing the harvested collection");
options.addOption("m", "metadata_format", true, "the name of the desired metadata format for harvesting, resolved to namespace and crosswalk in dspace.cfg");
options.addOption("h", "help", false, "help");
CommandLine line = parser.parse(options, argv);
String command = null;
String command = null;
String eperson = null;
String collection = null;
String oaiSource = null;
String oaiSetID = null;
String metadataKey = null;
int harvestType = 0;
if (line.hasOption('h')) {
if (line.hasOption('h'))
{
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("Harvest\n", options);
System.out.println("\nPING OAI server: Harvest -g -a oai_source -i oai_set_id");
System.out.println(
"RUNONCE harvest with arbitrary options: Harvest -o -e eperson -c collection -t harvest_type -a " +
"oai_source -i oai_set_id -m metadata_format");
System.out.println(
"SETUP a collection for harvesting: Harvest -s -c collection -t harvest_type -a oai_source -i " +
"oai_set_id -m metadata_format");
System.out.println("RUN harvest once: Harvest -r -e eperson -c collection");
System.out.println("START harvest scheduler: Harvest -S");
System.out.println("RESET all harvest status: Harvest -R");
System.out.println("PURGE a collection of items and settings: Harvest -p -e eperson -c collection");
System.out.println("PURGE all harvestable collections: Harvest -P -e eperson");
System.out
.println("\nPING OAI server: Harvest -g -s oai_source -i oai_set_id");
System.out
.println("RUNONCE harvest with arbitrary options: Harvest -o -e eperson -c collection -t harvest_type -a oai_source -i oai_set_id -m metadata_format");
System.out
.println("SETUP a collection for harvesting: Harvest -s -c collection -t harvest_type -a oai_source -i oai_set_id -m metadata_format");
System.out
.println("RUN harvest once: Harvest -r -e eperson -c collection");
System.out
.println("START harvest scheduler: Harvest -S");
System.out
.println("RESET all harvest status: Harvest -R");
System.out
.println("PURGE a collection of items and settings: Harvest -p -e eperson -c collection");
System.out
.println("PURGE all harvestable collections: Harvest -P -e eperson");
System.exit(0);
}
@@ -138,7 +126,7 @@ public class Harvest {
command = "purgeAll";
}
if (line.hasOption('e')) {
eperson = line.getOptionValue('e');
}
@@ -148,7 +136,7 @@ public class Harvest {
if (line.hasOption('t')) {
harvestType = Integer.parseInt(line.getOptionValue('t'));
} else {
harvestType = 0;
harvestType = 0;
}
if (line.hasOption('a')) {
oaiSource = line.getOptionValue('a');
@@ -159,87 +147,106 @@ public class Harvest {
if (line.hasOption('m')) {
metadataKey = line.getOptionValue('m');
}
// Instantiate our class
Harvest harvester = new Harvest();
harvester.context = new Context(Context.Mode.BATCH_EDIT);
harvester.context = new Context();
// Check our options
if (command == null) {
if (command == null)
{
System.out
.println("Error - no parameters specified (run with -h flag for details)");
.println("Error - no parameters specified (run with -h flag for details)");
System.exit(1);
} else if ("run".equals(command)) {
// Run a single harvest cycle on a collection using saved settings.
if (collection == null || eperson == null) {
}
// Run a single harvest cycle on a collection using saved settings.
else if ("run".equals(command))
{
if (collection == null || eperson == null)
{
System.out
.println("Error - a target collection and eperson must be provided");
.println("Error - a target collection and eperson must be provided");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
harvester.runHarvest(collection, eperson);
} else if ("start".equals(command)) {
// start the harvest loop
startHarvester();
} else if ("reset".equals(command)) {
// reset harvesting status
resetHarvesting();
} else if ("purgeAll".equals(command)) {
// purge all collections that are set up for harvesting (obviously for testing purposes only)
if (eperson == null) {
}
// start the harvest loop
else if ("start".equals(command))
{
startHarvester();
}
// reset harvesting status
else if ("reset".equals(command))
{
resetHarvesting();
}
// purge all collections that are set up for harvesting (obviously for testing purposes only)
else if ("purgeAll".equals(command))
{
if (eperson == null)
{
System.out
.println("Error - an eperson must be provided");
.println("Error - an eperson must be provided");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
List<HarvestedCollection> harvestedCollections = harvestedCollectionService.findAll(context);
for (HarvestedCollection harvestedCollection : harvestedCollections) {
System.out.println(
"Purging the following collections (deleting items and resetting harvest status): " +
harvestedCollection
.getCollection().getID().toString());
harvester.purgeCollection(harvestedCollection.getCollection().getID().toString(), eperson);
}
context.complete();
} else if ("purge".equals(command)) {
// Delete all items in a collection. Useful for testing fresh harvests.
if (collection == null || eperson == null) {
List<Integer> cids = HarvestedCollection.findAll(context);
System.out.println("Purging the following collections (deleting items and resetting harvest status): " + cids.toString());
for (Integer cid : cids)
{
harvester.purgeCollection(cid.toString(), eperson);
}
context.complete();
}
// Delete all items in a collection. Useful for testing fresh harvests.
else if ("purge".equals(command))
{
if (collection == null || eperson == null)
{
System.out
.println("Error - a target collection and eperson must be provided");
.println("Error - a target collection and eperson must be provided");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
harvester.purgeCollection(collection, eperson);
context.complete();
//TODO: implement this... remove all items and remember to unset "last-harvested" settings
} else if ("config".equals(command)) {
// Configure a collection with the three main settings
if (collection == null) {
}
// Configure a collection with the three main settings
else if ("config".equals(command))
{
if (collection == null)
{
System.out.println("Error - a target collection must be provided");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
if (oaiSource == null || oaiSetID == null) {
if (oaiSource == null || oaiSetID == null)
{
System.out.println("Error - both the OAI server address and OAI set id must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
if (metadataKey == null) {
System.out
.println("Error - a metadata key (commonly the prefix) must be specified for this collection");
if (metadataKey == null)
{
System.out.println("Error - a metadata key (commonly the prefix) must be specified for this collection");
System.out.println(" (run with -h flag for details)");
System.exit(1);
System.exit(1);
}
harvester.configureCollection(collection, harvestType, oaiSource, oaiSetID, metadataKey);
} else if ("ping".equals(command)) {
if (oaiSource == null || oaiSetID == null) {
}
else if ("ping".equals(command))
{
if (oaiSource == null || oaiSetID == null)
{
System.out.println("Error - both the OAI server address and OAI set id must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
@@ -248,166 +255,183 @@ public class Harvest {
pingResponder(oaiSource, oaiSetID, metadataKey);
}
}
/*
* Resolve the ID into a collection and check to see if its harvesting options are set. If so, return
* the collection, if not, bail out.
* the collection, if not, bail out.
*/
private Collection resolveCollection(String collectionID) {
DSpaceObject dso;
Collection targetCollection = null;
try {
// is the ID a handle?
if (collectionID != null) {
if (collectionID.indexOf('/') != -1) {
DSpaceObject dso;
Collection targetCollection = null;
try {
// is the ID a handle?
if (collectionID != null)
{
if (collectionID.indexOf('/') != -1)
{
// string has a / so it must be a handle - try and resolve it
dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, collectionID);
dso = HandleManager.resolveToObject(context, collectionID);
// resolved, now make sure it's a collection
if (dso == null || dso.getType() != Constants.COLLECTION) {
if (dso == null || dso.getType() != Constants.COLLECTION)
{
targetCollection = null;
} else {
}
else
{
targetCollection = (Collection) dso;
}
} else {
// not a handle, try and treat it as an integer collection database ID
System.out.println("Looking up by id: " + collectionID + ", parsed as '" + Integer
.parseInt(collectionID) + "', " + "in context: " + context);
targetCollection = collectionService.find(context, UUID.fromString(collectionID));
}
// not a handle, try and treat it as an integer collection
// database ID
else
{
System.out.println("Looking up by id: " + collectionID + ", parsed as '" + Integer.parseInt(collectionID) + "', " + "in context: " + context);
targetCollection = Collection.find(context, Integer.parseInt(collectionID));
}
}
// was the collection valid?
if (targetCollection == null) {
if (targetCollection == null)
{
System.out.println("Cannot resolve " + collectionID + " to collection");
System.exit(1);
}
} catch (SQLException se) {
se.printStackTrace();
}
return targetCollection;
}
catch (SQLException se) {
se.printStackTrace();
}
return targetCollection;
}
private void configureCollection(String collectionID, int type, String oaiSource, String oaiSetId,
String mdConfigId) {
System.out.println("Running: configure collection");
Collection collection = resolveCollection(collectionID);
System.out.println(collection.getID());
try {
HarvestedCollection hc = harvestedCollectionService.find(context, collection);
if (hc == null) {
hc = harvestedCollectionService.create(context, collection);
private void configureCollection(String collectionID, int type, String oaiSource, String oaiSetId, String mdConfigId) {
System.out.println("Running: configure collection");
Collection collection = resolveCollection(collectionID);
System.out.println(collection.getID());
try {
HarvestedCollection hc = HarvestedCollection.find(context, collection.getID());
if (hc == null) {
hc = HarvestedCollection.create(context, collection.getID());
}
context.turnOffAuthorisationSystem();
hc.setHarvestParams(type, oaiSource, oaiSetId, mdConfigId);
hc.setHarvestStatus(HarvestedCollection.STATUS_READY);
hc.update();
context.restoreAuthSystemState();
context.complete();
}
catch (Exception e) {
System.out.println("Changes could not be committed");
e.printStackTrace();
System.exit(1);
}
finally {
if (context != null)
{
context.restoreAuthSystemState();
}
context.turnOffAuthorisationSystem();
hc.setHarvestParams(type, oaiSource, oaiSetId, mdConfigId);
hc.setHarvestStatus(HarvestedCollection.STATUS_READY);
harvestedCollectionService.update(context, hc);
context.restoreAuthSystemState();
context.complete();
} catch (Exception e) {
System.out.println("Changes could not be committed");
e.printStackTrace();
System.exit(1);
} finally {
if (context != null) {
context.restoreAuthSystemState();
}
}
}
}
/**
* Purges a collection of all harvest-related data and settings. All items in the collection will be deleted.
*
*
* @param collectionID
* @param email
*/
private void purgeCollection(String collectionID, String email) {
System.out.println(
"Purging collection of all items and resetting last_harvested and harvest_message: " + collectionID);
Collection collection = resolveCollection(collectionID);
try {
EPerson eperson = ePersonService.findByEmail(context, email);
context.setCurrentUser(eperson);
context.turnOffAuthorisationSystem();
ItemService itemService = ContentServiceFactory.getInstance().getItemService();
Iterator<Item> it = itemService.findByCollection(context, collection);
int i = 0;
while (it.hasNext()) {
i++;
Item item = it.next();
System.out.println("Deleting: " + item.getHandle());
collectionService.removeItem(context, collection, item);
context.uncacheEntity(item);// Dispatch events every 50 items
if (i % 50 == 0) {
context.dispatchEvents();
i = 0;
}
}
HarvestedCollection hc = harvestedCollectionService.find(context, collection);
if (hc != null) {
hc.setLastHarvested(null);
hc.setHarvestMessage("");
hc.setHarvestStatus(HarvestedCollection.STATUS_READY);
hc.setHarvestStartTime(null);
harvestedCollectionService.update(context, hc);
}
context.restoreAuthSystemState();
context.dispatchEvents();
} catch (Exception e) {
System.out.println("Changes could not be committed");
e.printStackTrace();
System.exit(1);
} finally {
context.restoreAuthSystemState();
}
System.out.println("Purging collection of all items and resetting last_harvested and harvest_message: " + collectionID);
Collection collection = resolveCollection(collectionID);
try
{
EPerson eperson = EPerson.findByEmail(context, email);
context.setCurrentUser(eperson);
context.turnOffAuthorisationSystem();
ItemIterator it = collection.getAllItems();
IndexBrowse ib = new IndexBrowse(context);
int i=0;
while (it.hasNext()) {
i++;
Item item = it.next();
System.out.println("Deleting: " + item.getHandle());
ib.itemRemoved(item);
collection.removeItem(item);
// commit every 50 items
if (i%50 == 0) {
context.commit();
i=0;
}
}
HarvestedCollection hc = HarvestedCollection.find(context, collection.getID());
if (hc != null) {
hc.setHarvestResult(null,"");
hc.setHarvestStatus(HarvestedCollection.STATUS_READY);
hc.setHarvestStartTime(null);
hc.update();
}
context.restoreAuthSystemState();
context.commit();
}
catch (Exception e) {
System.out.println("Changes could not be committed");
e.printStackTrace();
System.exit(1);
}
finally {
context.restoreAuthSystemState();
}
}
/**
* Run a single harvest cycle on the specified collection under the authorization of the supplied EPerson
* Run a single harvest cycle on the specified collection under the authorization of the supplied EPerson
*/
private void runHarvest(String collectionID, String email) {
System.out.println("Running: a harvest cycle on " + collectionID);
System.out.print("Initializing the harvester... ");
OAIHarvester harvester = null;
try {
Collection collection = resolveCollection(collectionID);
HarvestedCollection hc = harvestedCollectionService.find(context, collection);
harvester = new OAIHarvester(context, collection, hc);
System.out.println("success. ");
} catch (HarvestingException hex) {
System.out.print("failed. ");
System.out.println(hex.getMessage());
throw new IllegalStateException("Unable to harvest", hex);
} catch (SQLException se) {
System.out.println("Running: a harvest cycle on " + collectionID);
System.out.print("Initializing the harvester... ");
OAIHarvester harvester = null;
try {
Collection collection = resolveCollection(collectionID);
HarvestedCollection hc = HarvestedCollection.find(context, collection.getID());
harvester = new OAIHarvester(context, collection, hc);
System.out.println("success. ");
}
catch (HarvestingException hex) {
System.out.print("failed. ");
System.out.println(hex.getMessage());
throw new IllegalStateException("Unable to harvest", hex);
} catch (SQLException se) {
System.out.print("failed. ");
System.out.println(se.getMessage());
throw new IllegalStateException("Unable to access database", se);
}
try {
// Harvest will not work for an anonymous user
EPerson eperson = EPerson.findByEmail(context, email);
System.out.println("Harvest started... ");
context.setCurrentUser(eperson);
harvester.runHarvest();
context.complete();
}
catch (SQLException e) {
throw new IllegalStateException("Failed to run harvester", e);
}
try {
// Harvest will not work for an anonymous user
EPerson eperson = ePersonService.findByEmail(context, email);
System.out.println("Harvest started... ");
context.setCurrentUser(eperson);
harvester.runHarvest();
context.complete();
} catch (SQLException e) {
catch (AuthorizeException e) {
throw new IllegalStateException("Failed to run harvester", e);
} catch (AuthorizeException e) {
throw new IllegalStateException("Failed to run harvester", e);
} catch (IOException e) {
}
catch (IOException e) {
throw new IllegalStateException("Failed to run harvester", e);
}
@@ -415,70 +439,78 @@ public class Harvest {
}
/**
* Resets harvest_status and harvest_start_time flags for all collections that have a row in the
* harvested_collections table
* Resets harvest_status and harvest_start_time flags for all collections that have a row in the harvested_collections table
*/
private static void resetHarvesting() {
System.out.print("Resetting harvest status flag on all collections... ");
System.out.print("Resetting harvest status flag on all collections... ");
try {
List<HarvestedCollection> harvestedCollections = harvestedCollectionService.findAll(context);
for (HarvestedCollection harvestedCollection : harvestedCollections) {
try
{
List<Integer> cids = HarvestedCollection.findAll(context);
for (Integer cid : cids)
{
HarvestedCollection hc = HarvestedCollection.find(context, cid);
//hc.setHarvestResult(null,"");
harvestedCollection.setHarvestStartTime(null);
harvestedCollection.setHarvestStatus(HarvestedCollection.STATUS_READY);
harvestedCollectionService.update(context, harvestedCollection);
hc.setHarvestStartTime(null);
hc.setHarvestStatus(HarvestedCollection.STATUS_READY);
hc.update();
}
context.commit();
System.out.println("success. ");
} catch (Exception ex) {
}
catch (Exception ex) {
System.out.println("failed. ");
ex.printStackTrace();
}
}
}
/**
* Starts up the harvest scheduler. Terminating this process will stop the scheduler.
*/
private static void startHarvester() {
try {
private static void startHarvester()
{
try
{
System.out.print("Starting harvest loop... ");
HarvestServiceFactory.getInstance().getHarvestSchedulingService().startNewScheduler();
OAIHarvester.startNewScheduler();
System.out.println("running. ");
} catch (Exception ex) {
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
/**
* See if the responder is alive and working.
*
* @param server address of the responder's host.
* @param set name of an item set.
* @param server address of the responder's host.
* @param set name of an item set.
* @param metadataFormat local prefix name, or null for "dc".
*/
private static void pingResponder(String server, String set, String metadataFormat) {
private static void pingResponder(String server, String set, String metadataFormat)
{
List<String> errors;
System.out.print("Testing basic PMH access: ");
errors = OAIHarvester.verifyOAIharvester(server, set,
(null != metadataFormat) ? metadataFormat : "dc", false);
if (errors.isEmpty()) {
(null != metadataFormat) ? metadataFormat : "dc", false);
if (errors.isEmpty())
System.out.println("OK");
} else {
for (String error : errors) {
else
{
for (String error : errors)
System.err.println(error);
}
}
System.out.print("Testing ORE support: ");
errors = OAIHarvester.verifyOAIharvester(server, set,
(null != metadataFormat) ? metadataFormat : "dc", true);
if (errors.isEmpty()) {
(null != metadataFormat) ? metadataFormat : "dc", true);
if (errors.isEmpty())
System.out.println("OK");
} else {
for (String error : errors) {
else
{
for (String error : errors)
System.err.println(error);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,246 +0,0 @@
/**
* 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.app.itemexport;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.dspace.app.itemexport.factory.ItemExportServiceFactory;
import org.dspace.app.itemexport.service.ItemExportService;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
/**
* Item exporter to create simple AIPs for DSpace content. Currently exports
* individual items, or entire collections. For instructions on use, see
* printUsage() method.
* <P>
* ItemExport creates the simple AIP package that the importer also uses. It
* consists of:
* <P>
* /exportdir/42/ (one directory per item) / dublin_core.xml - qualified dublin
* core in RDF schema / contents - text file, listing one file per line / file1
* - files contained in the item / file2 / ...
* <P>
* issues -doesn't handle special characters in metadata (needs to turn {@code &'s} into
* {@code &amp;}, etc.)
* <P>
* Modified by David Little, UCSD Libraries 12/21/04 to allow the registration
* of files (bitstreams) into DSpace.
*
* @author David Little
* @author Jay Paz
*/
public class ItemExportCLITool {
protected static ItemExportService itemExportService = ItemExportServiceFactory.getInstance()
.getItemExportService();
protected static HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
protected static ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected static CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
/**
* Default constructor
*/
private ItemExportCLITool() { }
/*
*
*/
public static void main(String[] argv) throws Exception {
// create an options object and populate it
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("t", "type", true, "type: COLLECTION or ITEM");
options.addOption("i", "id", true, "ID or handle of thing to export");
options.addOption("d", "dest", true,
"destination where you want items to go");
options.addOption("m", "migrate", false,
"export for migration (remove handle and metadata that will be re-created in new system)");
options.addOption("n", "number", true,
"sequence number to begin exporting items with");
options.addOption("z", "zip", true, "export as zip file (specify filename e.g. export.zip)");
options.addOption("h", "help", false, "help");
// as pointed out by Peter Dietz this provides similar functionality to export metadata
// but it is needed since it directly exports to Simple Archive Format (SAF)
options.addOption("x", "exclude-bitstreams", false, "do not export bitstreams");
CommandLine line = parser.parse(options, argv);
String typeString = null;
String destDirName = null;
String myIDString = null;
int seqStart = -1;
int myType = -1;
Item myItem = null;
Collection mycollection = null;
if (line.hasOption('h')) {
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("ItemExport\n", options);
System.out
.println("\nfull collection: ItemExport -t COLLECTION -i ID -d dest -n number");
System.out
.println("singleitem: ItemExport -t ITEM -i ID -d dest -n number");
System.exit(0);
}
if (line.hasOption('t')) { // type
typeString = line.getOptionValue('t');
if ("ITEM".equals(typeString)) {
myType = Constants.ITEM;
} else if ("COLLECTION".equals(typeString)) {
myType = Constants.COLLECTION;
}
}
if (line.hasOption('i')) { // id
myIDString = line.getOptionValue('i');
}
if (line.hasOption('d')) { // dest
destDirName = line.getOptionValue('d');
}
if (line.hasOption('n')) { // number
seqStart = Integer.parseInt(line.getOptionValue('n'));
}
boolean migrate = false;
if (line.hasOption('m')) { // number
migrate = true;
}
boolean zip = false;
String zipFileName = "";
if (line.hasOption('z')) {
zip = true;
zipFileName = line.getOptionValue('z');
}
boolean excludeBitstreams = false;
if (line.hasOption('x')) {
excludeBitstreams = true;
}
// now validate the args
if (myType == -1) {
System.out
.println("type must be either COLLECTION or ITEM (-h for help)");
System.exit(1);
}
if (destDirName == null) {
System.out
.println("destination directory must be set (-h for help)");
System.exit(1);
}
if (seqStart == -1) {
System.out
.println("sequence start number must be set (-h for help)");
System.exit(1);
}
if (myIDString == null) {
System.out
.println("ID must be set to either a database ID or a handle (-h for help)");
System.exit(1);
}
Context c = new Context(Context.Mode.READ_ONLY);
c.turnOffAuthorisationSystem();
if (myType == Constants.ITEM) {
// first, is myIDString a handle?
if (myIDString.indexOf('/') != -1) {
myItem = (Item) handleService.resolveToObject(c, myIDString);
if ((myItem == null) || (myItem.getType() != Constants.ITEM)) {
myItem = null;
}
} else {
myItem = itemService.find(c, UUID.fromString(myIDString));
}
if (myItem == null) {
System.out
.println("Error, item cannot be found: " + myIDString);
}
} else {
if (myIDString.indexOf('/') != -1) {
// has a / must be a handle
mycollection = (Collection) handleService.resolveToObject(c,
myIDString);
// ensure it's a collection
if ((mycollection == null)
|| (mycollection.getType() != Constants.COLLECTION)) {
mycollection = null;
}
} else if (myIDString != null) {
mycollection = collectionService.find(c, UUID.fromString(myIDString));
}
if (mycollection == null) {
System.out.println("Error, collection cannot be found: "
+ myIDString);
System.exit(1);
}
}
if (zip) {
Iterator<Item> items;
if (myItem != null) {
List<Item> myItems = new ArrayList<>();
myItems.add(myItem);
items = myItems.iterator();
} else {
System.out.println("Exporting from collection: " + myIDString);
items = itemService.findByCollection(c, mycollection);
}
itemExportService.exportAsZip(c, items, destDirName, zipFileName, seqStart, migrate, excludeBitstreams);
} else {
if (myItem != null) {
// it's only a single item
itemExportService
.exportItem(c, Collections.singletonList(myItem).iterator(), destDirName, seqStart, migrate,
excludeBitstreams);
} else {
System.out.println("Exporting from collection: " + myIDString);
// it's a collection, so do a bunch of items
Iterator<Item> i = itemService.findByCollection(c, mycollection);
itemExportService.exportItem(c, i, destDirName, seqStart, migrate, excludeBitstreams);
}
}
c.complete();
}
}

View File

@@ -10,17 +10,20 @@ package org.dspace.app.itemexport;
/**
* An exception that can be thrown when error occur during item export
*/
public class ItemExportException extends Exception {
public class ItemExportException extends Exception
{
public static final int EXPORT_TOO_LARGE = 0;
private int reason;
public ItemExportException(int r, String message) {
public ItemExportException(int r, String message)
{
super(message);
reason = r;
}
public int getReason() {
public int getReason()
{
return reason;
}
}
}

View File

@@ -1,27 +0,0 @@
/**
* 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.app.itemexport.factory;
import org.dspace.app.itemexport.service.ItemExportService;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Abstract factory to get services for the itemexport package, use ItemExportServiceFactory.getInstance() to
* retrieve an implementation
*
* @author kevinvandevelde at atmire.com
*/
public abstract class ItemExportServiceFactory {
public abstract ItemExportService getItemExportService();
public static ItemExportServiceFactory getInstance() {
return DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName("itemExportServiceFactory", ItemExportServiceFactory.class);
}
}

View File

@@ -1,28 +0,0 @@
/**
* 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.app.itemexport.factory;
import org.dspace.app.itemexport.service.ItemExportService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Factory implementation to get services for the itemexport package, use ItemExportServiceFactory.getInstance() to
* retrieve an implementation
*
* @author kevinvandevelde at atmire.com
*/
public class ItemExportServiceFactoryImpl extends ItemExportServiceFactory {
@Autowired(required = true)
private ItemExportService itemExportService;
@Override
public ItemExportService getItemExportService() {
return itemExportService;
}
}

View File

@@ -1,270 +0,0 @@
/**
* 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.app.itemexport.service;
import java.io.InputStream;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.mail.MessagingException;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
/**
* Item exporter to create simple AIPs for DSpace content. Currently exports
* individual items, or entire collections. For instructions on use, see
* printUsage() method.
* <P>
* ItemExport creates the simple AIP package that the importer also uses. It
* consists of:
* <P>
* /exportdir/42/ (one directory per item) / dublin_core.xml - qualified dublin
* core in RDF schema / contents - text file, listing one file per line / file1
* - files contained in the item / file2 / ...
* <P>
* issues -doesn't handle special characters in metadata (needs to turn {@code &'s} into
* {@code &amp;}, etc.)
* <P>
* Modified by David Little, UCSD Libraries 12/21/04 to allow the registration
* of files (bitstreams) into DSpace.
*
* @author David Little
* @author Jay Paz
*/
public interface ItemExportService {
/**
* used for export download
*/
public static final String COMPRESSED_EXPORT_MIME_TYPE = "application/zip";
public void exportItem(Context c, Iterator<Item> i,
String destDirName, int seqStart, boolean migrate,
boolean excludeBitstreams) throws Exception;
/**
* Method to perform an export and save it as a zip file.
*
* @param context The DSpace Context
* @param items The items to export
* @param destDirName The directory to save the export in
* @param zipFileName The name to save the zip file as
* @param seqStart The first number in the sequence
* @param migrate Whether to use the migrate option or not
* @param excludeBitstreams Whether to exclude bitstreams or not
* @throws Exception if error
*/
public void exportAsZip(Context context, Iterator<Item> items,
String destDirName, String zipFileName,
int seqStart, boolean migrate,
boolean excludeBitstreams) throws Exception;
/**
* Convenience methot to create export a single Community, Collection, or
* Item
*
* @param dso - the dspace object to export
* @param context - the dspace context
* @param migrate Whether to use the migrate option or not
* @throws Exception if error
*/
public void createDownloadableExport(DSpaceObject dso,
Context context, boolean migrate) throws Exception;
/**
* Convenience method to export a List of dspace objects (Community,
* Collection or Item)
*
* @param dsObjects - List containing dspace objects
* @param context - the dspace context
* @param migrate Whether to use the migrate option or not
* @throws Exception if error
*/
public void createDownloadableExport(List<DSpaceObject> dsObjects,
Context context, boolean migrate) throws Exception;
/**
* Convenience methot to create export a single Community, Collection, or
* Item
*
* @param dso - the dspace object to export
* @param context - the dspace context
* @param additionalEmail - cc email to use
* @param migrate Whether to use the migrate option or not
* @throws Exception if error
*/
public void createDownloadableExport(DSpaceObject dso,
Context context, String additionalEmail, boolean migrate) throws Exception;
/**
* Convenience method to export a List of dspace objects (Community,
* Collection or Item)
*
* @param dsObjects - List containing dspace objects
* @param context - the dspace context
* @param additionalEmail - cc email to use
* @param migrate Whether to use the migrate option or not
* @throws Exception if error
*/
public void createDownloadableExport(List<DSpaceObject> dsObjects,
Context context, String additionalEmail, boolean migrate) throws Exception;
/**
* Create a file name based on the date and eperson
*
* @param type Type of object (as string)
* @param eperson - eperson who requested export and will be able to download it
* @param date - the date the export process was created
* @return String representing the file name in the form of
* 'export_yyy_MMM_dd_count_epersonID'
* @throws Exception if error
*/
public String assembleFileName(String type, EPerson eperson,
Date date) throws Exception;
/**
* Use config file entry for org.dspace.app.itemexport.download.dir and id
* of the eperson to create a download directory name
*
* @param ePerson - the eperson who requested export archive
* @return String representing a directory in the form of
* org.dspace.app.itemexport.download.dir/epersonID
* @throws Exception if error
*/
public String getExportDownloadDirectory(EPerson ePerson)
throws Exception;
/**
* Returns config file entry for org.dspace.app.itemexport.work.dir
*
* @return String representing config file entry for
* org.dspace.app.itemexport.work.dir
* @throws Exception if error
*/
public String getExportWorkDirectory() throws Exception;
/**
* Used to read the export archived. Inteded for download.
*
* @param fileName the name of the file to download
* @param eperson the eperson requesting the download
* @return an input stream of the file to be downloaded
* @throws Exception if error
*/
public InputStream getExportDownloadInputStream(String fileName,
EPerson eperson) throws Exception;
/**
* Get the file size of the export archive represented by the file name.
*
* @param context DSpace context
* @param fileName name of the file to get the size.
* @return size as long
* @throws Exception if error
*/
public long getExportFileSize(Context context, String fileName) throws Exception;
/**
* Get the last modified date of the export archive represented by the file name.
*
* @param context DSpace context
* @param fileName name of the file to get the size.
* @return date as long
* @throws Exception if error
* @see java.io.File#lastModified()
*/
public long getExportFileLastModified(Context context, String fileName)
throws Exception;
/**
* The file name of the export archive contains the eperson id of the person
* who created it When requested for download this method can check if the
* person requesting it is the same one that created it
*
* @param context dspace context
* @param fileName the file name to check auths for
* @return true if it is the same person false otherwise
*/
public boolean canDownload(Context context, String fileName);
/**
* Reads the download directory for the eperson to see if any export
* archives are available
*
* @param eperson EPerson object
* @return a list of file names representing export archives that have been
* processed
* @throws Exception if error
*/
public List<String> getExportsAvailable(EPerson eperson)
throws Exception;
/**
* A clean up method that is ran before a new export archive is created. It
* uses the config file entry 'org.dspace.app.itemexport.life.span.hours' to
* determine if the current exports are too old and need pruging
*
* @param eperson - the eperson to clean up
* @throws Exception if error
*/
public void deleteOldExportArchives(EPerson eperson) throws Exception;
/**
* A clean up method that is ran before a new export archive is created. It
* uses the config file entry 'org.dspace.app.itemexport.life.span.hours' to
* determine if the current exports are too old and need purgeing
* Removes all old exports, not just those for the person doing the export.
*
* @throws Exception if error
*/
public void deleteOldExportArchives() throws Exception;
/**
* Since the archive is created in a new thread we are unable to communicate
* with calling method about success or failure. We accomplis this
* communication with email instead. Send a success email once the export
* archive is complete and ready for download
*
* @param context - the current Context
* @param eperson - eperson to send the email to
* @param fileName - the file name to be downloaded. It is added to the url in
* the email
* @throws MessagingException if error
*/
public void emailSuccessMessage(Context context, EPerson eperson,
String fileName) throws MessagingException;
/**
* Since the archive is created in a new thread we are unable to communicate
* with calling method about success or failure. We accomplis this
* communication with email instead. Send an error email if the export
* archive fails
*
* @param eperson - EPerson to send the error message to
* @param error - the error message
* @throws MessagingException if error
*/
public void emailErrorMessage(EPerson eperson, String error)
throws MessagingException;
/**
* Zip source to target
*
* @param strSource source file
* @param target target file
* @throws Exception if error
*/
public void zip(String strSource, String target) throws Exception;
}

View File

@@ -7,100 +7,87 @@
*/
package org.dspace.app.itemimport;
import gr.ekt.bte.core.DataLoader;
import gr.ekt.bte.core.TransformationEngine;
import gr.ekt.bte.dataloader.FileDataLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import gr.ekt.bte.core.DataLoader;
import gr.ekt.bte.core.TransformationEngine;
import gr.ekt.bte.dataloader.FileDataLoader;
/**
* This class acts as a Service in the procedure to batch import using the Biblio-Transformation-Engine
* This class acts as a Service in the procedure ot batch import using the Biblio-Transformation-Engine
*/
public class BTEBatchImportService {
public class BTEBatchImportService
{
TransformationEngine transformationEngine;
TransformationEngine transformationEngine;
Map<String, DataLoader> dataLoaders = new HashMap<String, DataLoader>();
Map<String, String> outputMap = new HashMap<String, String>();
Map<String, String> outputMap = new HashMap<String,String>();
/**
* Default constructor
*/
public BTEBatchImportService() {
public BTEBatchImportService()
{
super();
}
/**
* Setter method for dataLoaders parameter
*
* @param dataLoaders map of data loaders
* @param dataLoaders
*/
public void setDataLoaders(Map<String, DataLoader> dataLoaders) {
public void setDataLoaders(Map<String, DataLoader> dataLoaders)
{
this.dataLoaders = dataLoaders;
}
/**
* Get data loaders
*
*
* @return the map of DataLoaders
*/
public Map<String, DataLoader> getDataLoaders() {
public Map<String, DataLoader> getDataLoaders()
{
return dataLoaders;
}
/**
* Get output map
*
*
* @return the outputMapping
*/
public Map<String, String> getOutputMap() {
return outputMap;
}
public Map<String, String> getOutputMap() {
return outputMap;
}
/**
* Setter method for the outputMapping
*
* @param outputMap the output mapping
*/
public void setOutputMap(Map<String, String> outputMap) {
this.outputMap = outputMap;
}
/**
* Setter method for the outputMapping
* @param outputMapping
*/
public void setOutputMap(Map<String, String> outputMap) {
this.outputMap = outputMap;
}
/**
* Get transformation engine
*
* @return transformation engine
*/
public TransformationEngine getTransformationEngine() {
return transformationEngine;
}
public TransformationEngine getTransformationEngine() {
return transformationEngine;
}
/**
* set transformation engine
*
* @param transformationEngine transformation engine
*/
public void setTransformationEngine(TransformationEngine transformationEngine) {
this.transformationEngine = transformationEngine;
}
/**
* Getter of file data loaders
*
* @return List of file data loaders
*/
public List<String> getFileDataLoaders() {
List<String> result = new ArrayList<String>();
for (String key : dataLoaders.keySet()) {
DataLoader dl = dataLoaders.get(key);
if (dl instanceof FileDataLoader) {
result.add(key);
}
}
return result;
}
}
public void setTransformationEngine(TransformationEngine transformationEngine) {
this.transformationEngine = transformationEngine;
}
public List<String> getFileDataLoaders(){
List<String> result = new ArrayList<String>();
for (String key : dataLoaders.keySet()){
DataLoader dl = dataLoaders.get(key);
if (dl instanceof FileDataLoader){
result.add(key);
}
}
return result;
}
}

View File

@@ -7,7 +7,9 @@
*/
package org.dspace.app.itemimport;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
@@ -17,213 +19,147 @@ import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Scanner;
/**
* @author kstamatis
*
*/
public class BatchUpload {
private Date date;
private File dir;
private boolean successful;
private int itemsImported;
private int totalItems = 0;
private List<String> handlesImported = new ArrayList<String>();
private String errorMsg = "";
private String errorMsgHTML = "";
private Date date;
private File dir;
private boolean successful;
private int itemsImported;
private int totalItems = 0;
private List<String> handlesImported = new ArrayList<String>();
private String errorMsg = "";
private String errorMsgHTML = "";
/**
*
*/
public BatchUpload(String dirPath) {
this.initializeWithFile(new File(dirPath));
}
/**
* Initialize with directory
*
* @param dirPath directory path
*/
public BatchUpload(String dirPath) {
public BatchUpload(File dir) {
this.initializeWithFile(dir);
}
this.initializeWithFile(new File(dirPath));
}
private void initializeWithFile(File dir){
this.dir = dir;
String dirName = dir.getName();
long timeMillis = Long.parseLong(dirName);
Calendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(timeMillis);
this.date = calendar.getTime();
try {
this.itemsImported = countLines(dir + File.separator + "mapfile");
} catch (IOException e) {
e.printStackTrace();
}
for (File file : dir.listFiles()){
if (file.isDirectory()){
this.totalItems = file.list().length;
}
}
this.successful = this.totalItems == this.itemsImported;
//Parse possible error message
File errorFile = new File(dir + File.separator + "error.txt");
if (errorFile.exists()){
try {
readFile(dir + File.separator + "error.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private int countLines(String filename) throws IOException {
LineNumberReader reader = new LineNumberReader(new FileReader(filename));
int cnt = 0;
String lineRead = "";
while ((lineRead = reader.readLine()) != null) {
String[] parts = lineRead.split(" ");
if (parts.length > 1)
handlesImported.add(parts[1].trim());
else
handlesImported.add(lineRead);
}
/**
* Initialize with directory
*
* @param dir directory path
*/
public BatchUpload(File dir) {
cnt = reader.getLineNumber();
reader.close();
return cnt;
}
private void readFile(String filename) throws IOException {
LineNumberReader reader = new LineNumberReader(new FileReader(filename));
String lineRead = "";
while ((lineRead = reader.readLine()) != null) {
this.errorMsg += lineRead + "\n";
if (lineRead.startsWith("\tat ")){
this.errorMsgHTML += "<span class=\"batchimport-error-tab\">" + lineRead + "</span><br/>";
}
else if (lineRead.startsWith("Caused by")){
this.errorMsgHTML += "<span class=\"batchimport-error-caused\">" + lineRead + "</span><br/>";
}
else {
this.errorMsgHTML += lineRead + "<br/>";
}
}
reader.close();
}
this.initializeWithFile(dir);
public Date getDate() {
return date;
}
}
public File getDir() {
return dir;
}
/**
* Initialize with directory
*
* @param dir directory path
*/
private void initializeWithFile(File dir) {
public boolean isSuccessful() {
return successful;
}
this.dir = dir;
public int getItemsImported() {
return itemsImported;
}
String dirName = dir.getName();
long timeMillis = Long.parseLong(dirName);
Calendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(timeMillis);
this.date = calendar.getTime();
public int getTotalItems() {
return totalItems;
}
public String getDateFormatted(){
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy - HH:mm");
return df.format(date);
}
try {
this.itemsImported = countLines(dir + File.separator + "mapfile");
} catch (IOException e) {
e.printStackTrace();
}
public List<String> getHandlesImported() {
return handlesImported;
}
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
this.totalItems = file.list().length;
}
}
public String getErrorMsg() {
return errorMsg;
}
this.successful = this.totalItems == this.itemsImported;
//Parse possible error message
File errorFile = new File(dir + File.separator + "error.txt");
if (errorFile.exists()) {
try {
readFile(dir + File.separator + "error.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* Count lines in file
*
* @param filename file name
* @return lines in file
* @throws IOException if IO error
*/
private int countLines(String filename) throws IOException {
LineNumberReader reader = new LineNumberReader(new FileReader(filename));
int cnt = 0;
String lineRead = "";
while ((lineRead = reader.readLine()) != null) {
String[] parts = lineRead.split(" ");
if (parts.length > 1) {
handlesImported.add(parts[1].trim());
} else {
handlesImported.add(lineRead);
}
}
cnt = reader.getLineNumber();
reader.close();
return cnt;
}
/**
* Read a file
*
* @param filename file name
* @throws IOException if IO error
*/
private void readFile(String filename) throws IOException {
LineNumberReader reader = new LineNumberReader(new FileReader(filename));
String lineRead = "";
while ((lineRead = reader.readLine()) != null) {
this.errorMsg += lineRead + "\n";
if (lineRead.startsWith("\tat ")) {
this.errorMsgHTML += "<span class=\"batchimport-error-tab\">" + lineRead + "</span><br/>";
} else if (lineRead.startsWith("Caused by")) {
this.errorMsgHTML += "<span class=\"batchimport-error-caused\">" + lineRead + "</span><br/>";
} else {
this.errorMsgHTML += lineRead + "<br/>";
}
}
reader.close();
}
/**
* Get date
*
* @return Date
*/
public Date getDate() {
return date;
}
/**
* Get path to directory
*
* @return directory
*/
public File getDir() {
return dir;
}
/**
* Whether successulf
*
* @return true or false
*/
public boolean isSuccessful() {
return successful;
}
/**
* Get items imported
*
* @return number of items
*/
public int getItemsImported() {
return itemsImported;
}
/**
* Get total items
*
* @return total
*/
public int getTotalItems() {
return totalItems;
}
/**
* Get formatted date (DD/MM/YY)
*
* @return date as string
*/
public String getDateFormatted() {
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy - HH:mm");
return df.format(date);
}
/**
* Get handles of imported files
*
* @return list of handles
*/
public List<String> getHandlesImported() {
return handlesImported;
}
/**
* Get error message
*
* @return error message
*/
public String getErrorMsg() {
return errorMsg;
}
/**
* Get error message as HTML
*
* @return error message string as HTML
*/
public String getErrorMsgHTML() {
return errorMsgHTML;
}
public String getErrorMsgHTML() {
return errorMsgHTML;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,431 +0,0 @@
/**
* 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.app.itemimport;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.dspace.app.itemimport.factory.ItemImportServiceFactory;
import org.dspace.app.itemimport.service.ItemImportService;
import org.dspace.content.Collection;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
/**
* Import items into DSpace. The conventional use is upload files by copying
* them. DSpace writes the item's bitstreams into its assetstore. Metadata is
* also loaded to the DSpace database.
* <P>
* A second use assumes the bitstream files already exist in a storage
* resource accessible to DSpace. In this case the bitstreams are 'registered'.
* That is, the metadata is loaded to the DSpace database and DSpace is given
* the location of the file which is subsumed into DSpace.
* <P>
* The distinction is controlled by the format of lines in the 'contents' file.
* See comments in processContentsFile() below.
* <P>
* Modified by David Little, UCSD Libraries 12/21/04 to
* allow the registration of files (bitstreams) into DSpace.
*/
public class ItemImportCLITool {
private static boolean template = false;
private static final CollectionService collectionService = ContentServiceFactory.getInstance()
.getCollectionService();
private static final EPersonService epersonService = EPersonServiceFactory.getInstance().getEPersonService();
private static final HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
/**
* Default constructor
*/
private ItemImportCLITool() { }
public static void main(String[] argv) throws Exception {
Date startTime = new Date();
int status = 0;
try {
// create an options object and populate it
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("a", "add", false, "add items to DSpace");
options.addOption("b", "add-bte", false, "add items to DSpace via Biblio-Transformation-Engine (BTE)");
options.addOption("r", "replace", false, "replace items in mapfile");
options.addOption("d", "delete", false,
"delete items listed in mapfile");
options.addOption("i", "inputtype", true, "input type in case of BTE import");
options.addOption("s", "source", true, "source of items (directory)");
options.addOption("z", "zip", true, "name of zip file");
options.addOption("c", "collection", true,
"destination collection(s) Handle or database ID");
options.addOption("m", "mapfile", true, "mapfile items in mapfile");
options.addOption("e", "eperson", true,
"email of eperson doing importing");
options.addOption("w", "workflow", false,
"send submission through collection's workflow");
options.addOption("n", "notify", false,
"if sending submissions through the workflow, send notification emails");
options.addOption("t", "test", false,
"test run - do not actually import items");
options.addOption("p", "template", false, "apply template");
options.addOption("R", "resume", false,
"resume a failed import (add only)");
options.addOption("q", "quiet", false, "don't display metadata");
options.addOption("h", "help", false, "help");
CommandLine line = parser.parse(options, argv);
String command = null; // add replace remove, etc
String bteInputType = null; //ris, endnote, tsv, csv, bibtex
String sourcedir = null;
String mapfile = null;
String eperson = null; // db ID or email
String[] collections = null; // db ID or handles
boolean isTest = false;
boolean isResume = false;
boolean useWorkflow = false;
boolean useWorkflowSendEmail = false;
boolean isQuiet = false;
if (line.hasOption('h')) {
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("ItemImport\n", options);
System.out
.println("\nadding items: ItemImport -a -e eperson -c collection -s sourcedir -m mapfile");
System.out
.println(
"\nadding items from zip file: ItemImport -a -e eperson -c collection -s sourcedir -z " +
"filename.zip -m mapfile");
System.out
.println("replacing items: ItemImport -r -e eperson -c collection -s sourcedir -m mapfile");
System.out
.println("deleting items: ItemImport -d -e eperson -m mapfile");
System.out
.println(
"If multiple collections are specified, the first collection will be the one that owns the " +
"item.");
System.exit(0);
}
if (line.hasOption('a')) {
command = "add";
}
if (line.hasOption('r')) {
command = "replace";
}
if (line.hasOption('d')) {
command = "delete";
}
if (line.hasOption('b')) {
command = "add-bte";
}
if (line.hasOption('i')) {
bteInputType = line.getOptionValue('i');
}
if (line.hasOption('w')) {
useWorkflow = true;
if (line.hasOption('n')) {
useWorkflowSendEmail = true;
}
}
if (line.hasOption('t')) {
isTest = true;
System.out.println("**Test Run** - not actually importing items.");
}
if (line.hasOption('p')) {
template = true;
}
if (line.hasOption('s')) { // source
sourcedir = line.getOptionValue('s');
}
if (line.hasOption('m')) { // mapfile
mapfile = line.getOptionValue('m');
}
if (line.hasOption('e')) { // eperson
eperson = line.getOptionValue('e');
}
if (line.hasOption('c')) { // collections
collections = line.getOptionValues('c');
}
if (line.hasOption('R')) {
isResume = true;
System.out
.println("**Resume import** - attempting to import items not already imported");
}
if (line.hasOption('q')) {
isQuiet = true;
}
boolean zip = false;
String zipfilename = "";
if (line.hasOption('z')) {
zip = true;
zipfilename = line.getOptionValue('z');
}
//By default assume collections will be given on the command line
boolean commandLineCollections = true;
// now validate
// must have a command set
if (command == null) {
System.out
.println("Error - must run with either add, replace, or remove (run with -h flag for details)");
System.exit(1);
} else if ("add".equals(command) || "replace".equals(command)) {
if (sourcedir == null) {
System.out
.println("Error - a source directory containing items must be set");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
if (mapfile == null) {
System.out
.println("Error - a map file to hold importing results must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
if (eperson == null) {
System.out
.println("Error - an eperson to do the importing must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
if (collections == null) {
System.out.println("No collections given. Assuming 'collections' file inside item directory");
commandLineCollections = false;
}
} else if ("add-bte".equals(command)) {
//Source dir can be null, the user can specify the parameters for his loader in the Spring XML
// configuration file
if (mapfile == null) {
System.out
.println("Error - a map file to hold importing results must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
if (eperson == null) {
System.out
.println("Error - an eperson to do the importing must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
if (collections == null) {
System.out.println("No collections given. Assuming 'collections' file inside item directory");
commandLineCollections = false;
}
if (bteInputType == null) {
System.out
.println(
"Error - an input type (tsv, csv, ris, endnote, bibtex or any other type you have " +
"specified in BTE Spring XML configuration file) must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
} else if ("delete".equals(command)) {
if (eperson == null) {
System.out
.println("Error - an eperson to do the importing must be specified");
System.exit(1);
}
if (mapfile == null) {
System.out.println("Error - a map file must be specified");
System.exit(1);
}
}
// can only resume for adds
if (isResume && !"add".equals(command) && !"add-bte".equals(command)) {
System.out
.println("Error - resume option only works with the --add or the --add-bte commands");
System.exit(1);
}
// do checks around mapfile - if mapfile exists and 'add' is selected,
// resume must be chosen
File myFile = new File(mapfile);
if (!isResume && "add".equals(command) && myFile.exists()) {
System.out.println("Error - the mapfile " + mapfile
+ " already exists.");
System.out
.println("Either delete it or use --resume if attempting to resume an aborted import.");
System.exit(1);
}
ItemImportService myloader = ItemImportServiceFactory.getInstance().getItemImportService();
myloader.setTest(isTest);
myloader.setResume(isResume);
myloader.setUseWorkflow(useWorkflow);
myloader.setUseWorkflowSendEmail(useWorkflowSendEmail);
myloader.setQuiet(isQuiet);
// create a context
Context c = new Context(Context.Mode.BATCH_EDIT);
// find the EPerson, assign to context
EPerson myEPerson = null;
if (eperson.indexOf('@') != -1) {
// @ sign, must be an email
myEPerson = epersonService.findByEmail(c, eperson);
} else {
myEPerson = epersonService.find(c, UUID.fromString(eperson));
}
if (myEPerson == null) {
System.out.println("Error, eperson cannot be found: " + eperson);
System.exit(1);
}
c.setCurrentUser(myEPerson);
// find collections
List<Collection> mycollections = null;
// don't need to validate collections set if command is "delete"
// also if no collections are given in the command line
if (!"delete".equals(command) && commandLineCollections) {
System.out.println("Destination collections:");
mycollections = new ArrayList<>();
// validate each collection arg to see if it's a real collection
for (int i = 0; i < collections.length; i++) {
// is the ID a handle?
if (collections[i].indexOf('/') != -1) {
// string has a / so it must be a handle - try and resolve
// it
mycollections.add((Collection) handleService
.resolveToObject(c, collections[i]));
// resolved, now make sure it's a collection
if ((mycollections.get(i) == null)
|| (mycollections.get(i).getType() != Constants.COLLECTION)) {
mycollections.set(i, null);
}
} else if (collections[i] != null) {
// not a handle, try and treat it as an integer collection database ID
mycollections.set(i, collectionService.find(c, UUID.fromString(collections[i])));
}
// was the collection valid?
if (mycollections.get(i) == null) {
throw new IllegalArgumentException("Cannot resolve "
+ collections[i] + " to collection");
}
// print progress info
String owningPrefix = "";
if (i == 0) {
owningPrefix = "Owning ";
}
System.out.println(owningPrefix + " Collection: "
+ mycollections.get(i).getName());
}
} // end of validating collections
try {
// If this is a zip archive, unzip it first
if (zip) {
sourcedir = myloader.unzip(sourcedir, zipfilename);
}
c.turnOffAuthorisationSystem();
if ("add".equals(command)) {
myloader.addItems(c, mycollections, sourcedir, mapfile, template);
} else if ("replace".equals(command)) {
myloader.replaceItems(c, mycollections, sourcedir, mapfile, template);
} else if ("delete".equals(command)) {
myloader.deleteItems(c, mapfile);
} else if ("add-bte".equals(command)) {
myloader.addBTEItems(c, mycollections, sourcedir, mapfile, template, bteInputType, null);
}
// complete all transactions
c.complete();
} catch (Exception e) {
c.abort();
e.printStackTrace();
System.out.println(e);
status = 1;
}
// Delete the unzipped file
try {
if (zip) {
System.gc();
System.out.println(
"Deleting temporary zip directory: " + myloader.getTempWorkDirFile().getAbsolutePath());
myloader.cleanupZipTemp();
}
} catch (Exception ex) {
System.out.println("Unable to delete temporary zip archive location: " + myloader.getTempWorkDirFile()
.getAbsolutePath());
}
if (isTest) {
System.out.println("***End of Test Run***");
}
} finally {
Date endTime = new Date();
System.out.println("Started: " + startTime.getTime());
System.out.println("Ended: " + endTime.getTime());
System.out.println(
"Elapsed time: " + ((endTime.getTime() - startTime.getTime()) / 1000) + " secs (" + (endTime
.getTime() - startTime.getTime()) + " msecs)");
}
System.exit(status);
}
}

View File

@@ -1,27 +0,0 @@
/**
* 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.app.itemimport.factory;
import org.dspace.app.itemimport.service.ItemImportService;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Abstract factory to get services for the itemimport package, use ItemImportService.getInstance() to retrieve an
* implementation
*
* @author kevinvandevelde at atmire.com
*/
public abstract class ItemImportServiceFactory {
public abstract ItemImportService getItemImportService();
public static ItemImportServiceFactory getInstance() {
return DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName("itemImportServiceFactory", ItemImportServiceFactory.class);
}
}

View File

@@ -1,28 +0,0 @@
/**
* 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.app.itemimport.factory;
import org.dspace.app.itemimport.service.ItemImportService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Factory implementation to get services for the itemimport package, use ItemImportService.getInstance() to retrieve
* an implementation
*
* @author kevinvandevelde at atmire.com
*/
public class ItemImportServiceFactoryImpl extends ItemImportServiceFactory {
@Autowired(required = true)
private ItemImportService itemImportService;
@Override
public ItemImportService getItemImportService() {
return itemImportService;
}
}

View File

@@ -1,253 +0,0 @@
/**
* 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.app.itemimport.service;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.mail.MessagingException;
import org.dspace.app.itemimport.BatchUpload;
import org.dspace.content.Collection;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
/**
* Import items into DSpace. The conventional use is upload files by copying
* them. DSpace writes the item's bitstreams into its assetstore. Metadata is
* also loaded to the DSpace database.
* <P>
* A second use assumes the bitstream files already exist in a storage
* resource accessible to DSpace. In this case the bitstreams are 'registered'.
* That is, the metadata is loaded to the DSpace database and DSpace is given
* the location of the file which is subsumed into DSpace.
* <P>
* The distinction is controlled by the format of lines in the 'contents' file.
* See comments in processContentsFile() below.
* <P>
* Modified by David Little, UCSD Libraries 12/21/04 to
* allow the registration of files (bitstreams) into DSpace.
*/
public interface ItemImportService {
/**
* @param c DSpace Context
* @param mycollections List of Collections
* @param sourceDir source location
* @param mapFile map file
* @param template whether to use template item
* @throws Exception if error
*/
public void addItemsAtomic(Context c, List<Collection> mycollections, String sourceDir, String mapFile,
boolean template) throws Exception;
/**
* Add items
*
* @param c DSpace Context
* @param mycollections List of Collections
* @param sourceDir source location
* @param mapFile map file
* @param template whether to use template item
* @throws Exception if error
*/
public void addItems(Context c, List<Collection> mycollections,
String sourceDir, String mapFile, boolean template) throws Exception;
/**
* Unzip a file
*
* @param zipfile file
* @return unzip location
* @throws IOException if error
*/
public String unzip(File zipfile) throws IOException;
/**
* Unzip a file to a destination
*
* @param zipfile file
* @param destDir destination directory
* @return unzip location
* @throws IOException if error
*/
public String unzip(File zipfile, String destDir) throws IOException;
/**
* Unzip a file in a specific source directory
*
* @param sourcedir source directory
* @param zipfilename file name
* @return unzip location
* @throws IOException if error
*/
public String unzip(String sourcedir, String zipfilename) throws IOException;
/**
* Given a public URL to a zip file that has the Simple Archive Format, this method imports the contents to DSpace
*
* @param url The public URL of the zip file
* @param owningCollection The owning collection the items will belong to
* @param collections The collections the created items will be inserted to, apart from the owning one
* @param resumeDir In case of a resume request, the directory that containsthe old mapfile and data
* @param inputType The input type of the data (bibtex, csv, etc.), in case of local file
* @param context The context
* @param template whether to use template item
* @throws Exception if error
*/
public void processUIImport(String url, Collection owningCollection, String[] collections, String resumeDir,
String inputType, Context context, boolean template) throws Exception;
/**
* Since the BTE batch import is done in a new thread we are unable to communicate
* with calling method about success or failure. We accomplish this
* communication with email instead. Send a success email once the batch
* import is complete
*
* @param context - the current Context
* @param eperson - eperson to send the email to
* @param fileName - the filepath to the mapfile created by the batch import
* @throws MessagingException if error
*/
public void emailSuccessMessage(Context context, EPerson eperson,
String fileName) throws MessagingException;
/**
* Since the BTE batch import is done in a new thread we are unable to communicate
* with calling method about success or failure. We accomplis this
* communication with email instead. Send an error email if the batch
* import fails
*
* @param eperson - EPerson to send the error message to
* @param error - the error message
* @throws MessagingException if error
*/
public void emailErrorMessage(EPerson eperson, String error)
throws MessagingException;
/**
* Get imports available for a person
*
* @param eperson EPerson object
* @return List of batch uploads
* @throws Exception if error
*/
public List<BatchUpload> getImportsAvailable(EPerson eperson)
throws Exception;
/**
* Get import upload directory
*
* @param ePerson EPerson object
* @return directory
* @throws Exception if error
*/
public String getImportUploadableDirectory(EPerson ePerson)
throws Exception;
/**
* Delete a batch by ID
*
* @param c DSpace Context
* @param uploadId identifier
* @throws Exception if error
*/
public void deleteBatchUpload(Context c, String uploadId) throws Exception;
/**
* Replace items
*
* @param c DSpace Context
* @param mycollections List of Collections
* @param sourcedir source directory
* @param mapfile map file
* @param template whether to use template item
* @throws Exception if error
*/
public void replaceItems(Context c, List<Collection> mycollections, String sourcedir, String mapfile,
boolean template) throws Exception;
/**
* Delete items via mapfile
*
* @param c DSpace Context
* @param mapfile map file
* @throws Exception if error
*/
public void deleteItems(Context c, String mapfile) throws Exception;
/**
* Add items
*
* @param c DSpace Context
* @param mycollections List of Collections
* @param sourcedir source directory
* @param mapfile map file
* @param template whether to use template item
* @param bteInputType The input type of the data (bibtex, csv, etc.), in case of local file
* @param workingDir working directory
* @throws Exception if error
*/
public void addBTEItems(Context c, List<Collection> mycollections, String sourcedir, String mapfile,
boolean template, String bteInputType, String workingDir) throws Exception;
/**
* Get temporary work directory
*
* @return directory as string
*/
public String getTempWorkDir();
/**
* Get temporary work directory (as File)
*
* @return directory as File
* @throws java.io.IOException if the directory cannot be created.
*/
public File getTempWorkDirFile() throws IOException;
/**
* Cleanup
*/
public void cleanupZipTemp();
/**
* Set test flag
*
* @param isTest true or false
*/
public void setTest(boolean isTest);
/**
* Set resume flag
*
* @param isResume true or false
*/
public void setResume(boolean isResume);
/**
* Set use workflow
*
* @param useWorkflow whether to enable workflow
*/
public void setUseWorkflow(boolean useWorkflow);
/**
* @param useWorkflowSendMail whether to send mail
*/
public void setUseWorkflowSendEmail(boolean useWorkflowSendMail);
/**
* Set quiet flag
*
* @param isQuiet true or false
*/
public void setQuiet(boolean isQuiet);
}

View File

@@ -9,85 +9,83 @@ package org.dspace.app.itemmarking;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.List;
import org.dspace.app.util.Util;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
/**
* This is an item marking Strategy class that tries to mark an item availability
* based on the existence of bitstreams within the ORIGINAL bundle.
*
*
* @author Kostas Stamatis
*
*/
public class ItemMarkingAvailabilityBitstreamStrategy implements ItemMarkingExtractor {
private String availableImageName;
private String nonAvailableImageName;
private String availableImageName;
private String nonAvailableImageName;
public ItemMarkingAvailabilityBitstreamStrategy() {
}
@Autowired(required = true)
protected ItemService itemService;
public ItemMarkingAvailabilityBitstreamStrategy() {
}
@Override
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
throws SQLException {
List<Bundle> bundles = itemService.getBundles(item, "ORIGINAL");
if (bundles.size() == 0) {
ItemMarkingInfo markInfo = new ItemMarkingInfo();
markInfo.setImageName(nonAvailableImageName);
return markInfo;
} else {
Bundle originalBundle = bundles.iterator().next();
if (originalBundle.getBitstreams().size() == 0) {
ItemMarkingInfo markInfo = new ItemMarkingInfo();
markInfo.setImageName(nonAvailableImageName);
return markInfo;
} else {
Bitstream bitstream = originalBundle.getBitstreams().get(0);
ItemMarkingInfo signInfo = new ItemMarkingInfo();
signInfo.setImageName(availableImageName);
signInfo.setTooltip(bitstream.getName());
String bsLink = "";
@Override
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
throws SQLException {
Bundle[] bundles = item.getBundles("ORIGINAL");
if (bundles.length == 0){
ItemMarkingInfo markInfo = new ItemMarkingInfo();
markInfo.setImageName(nonAvailableImageName);
return markInfo;
}
else {
Bundle originalBundle = bundles[0];
if (originalBundle.getBitstreams().length == 0){
ItemMarkingInfo markInfo = new ItemMarkingInfo();
markInfo.setImageName(nonAvailableImageName);
return markInfo;
}
else {
Bitstream bitstream = originalBundle.getBitstreams()[0];
ItemMarkingInfo signInfo = new ItemMarkingInfo();
signInfo.setImageName(availableImageName);
signInfo.setTooltip(bitstream.getName());
String bsLink = "";
bsLink = bsLink + "bitstream/"
+ item.getHandle() + "/"
+ bitstream.getSequenceID() + "/";
+ item.getHandle() + "/"
+ bitstream.getSequenceID() + "/";
try {
bsLink = bsLink + Util.encodeBitstreamName(bitstream.getName(), Constants.DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
bsLink = bsLink + Util.encodeBitstreamName(bitstream.getName(), Constants.DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
signInfo.setLink(bsLink);
return signInfo;
}
}
}
e.printStackTrace();
}
public void setAvailableImageName(String availableImageName) {
this.availableImageName = availableImageName;
}
signInfo.setLink(bsLink);
return signInfo;
}
}
}
public void setAvailableImageName(String availableImageName) {
this.availableImageName = availableImageName;
}
public void setNonAvailableImageName(String nonAvailableImageName) {
this.nonAvailableImageName = nonAvailableImageName;
}
}
public void setNonAvailableImageName(String nonAvailableImageName) {
this.nonAvailableImageName = nonAvailableImageName;
}
}

View File

@@ -18,32 +18,33 @@ import org.dspace.core.Context;
/**
* This is an item marking Strategy class that tries to mark an item
* based on the collection the items belong to
*
*
* @author Kostas Stamatis
*
*/
public class ItemMarkingCollectionStrategy implements ItemMarkingExtractor {
Map<String, ItemMarkingInfo> mapping = new HashMap<String, ItemMarkingInfo>();
Map<String, ItemMarkingInfo> mapping = new HashMap<String, ItemMarkingInfo>();
public ItemMarkingCollectionStrategy() {
}
public ItemMarkingCollectionStrategy() {
}
@Override
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
throws SQLException {
if (mapping!=null){
for (Collection collection : item.getCollections()){
if (mapping.containsKey(collection.getHandle())){
return mapping.get(collection.getHandle());
}
}
}
return null;
}
@Override
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
throws SQLException {
if (mapping != null) {
for (Collection collection : item.getCollections()) {
if (mapping.containsKey(collection.getHandle())) {
return mapping.get(collection.getHandle());
}
}
}
return null;
}
public void setMapping(Map<String, ItemMarkingInfo> mapping) {
this.mapping = mapping;
}
public void setMapping(Map<String, ItemMarkingInfo> mapping) {
this.mapping = mapping;
}
}

View File

@@ -14,10 +14,11 @@ import org.dspace.core.Context;
/**
* Interface to abstract the strategy for item signing
*
*
* @author Kostas Stamatis
*
*/
public interface ItemMarkingExtractor {
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
throws SQLException;
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
throws SQLException;
}

View File

@@ -9,48 +9,49 @@ package org.dspace.app.itemmarking;
/**
* Simple DTO to transfer data about the marking info for an item
*
*
* @author Kostas Stamatis
*
*/
public class ItemMarkingInfo {
private String imageName;
private String classInfo;
private String tooltip;
private String link;
private String imageName;
private String classInfo;
private String tooltip;
private String link;
public ItemMarkingInfo() {
super();
}
public ItemMarkingInfo() {
super();
}
public String getImageName() {
return imageName;
}
public String getImageName() {
return imageName;
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
public String getTooltip() {
return tooltip;
}
public String getTooltip() {
return tooltip;
}
public void setTooltip(String tooltip) {
this.tooltip = tooltip;
}
public void setTooltip(String tooltip) {
this.tooltip = tooltip;
}
public String getLink() {
return link;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getClassInfo() {
return classInfo;
}
public void setLink(String link) {
this.link = link;
}
public String getClassInfo() {
return classInfo;
}
public void setClassInfo(String classInfo) {
this.classInfo = classInfo;
}
public void setClassInfo(String classInfo) {
this.classInfo = classInfo;
}
}

View File

@@ -9,56 +9,53 @@ package org.dspace.app.itemmarking;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.service.ItemService;
import org.dspace.content.Metadatum;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
/**
* This is an item marking Strategy class that tries to mark an item
* based on the existence of a specific value within the values of a specific
* metadata field
*
*
* @author Kostas Stamatis
*
*/
public class ItemMarkingMetadataStrategy implements ItemMarkingExtractor {
@Autowired(required = true)
protected ItemService itemService;
private String metadataField;
Map<String, ItemMarkingInfo> mapping = new HashMap<String, ItemMarkingInfo>();
public ItemMarkingMetadataStrategy() {
}
private String metadataField;
Map<String, ItemMarkingInfo> mapping = new HashMap<String, ItemMarkingInfo>();
@Override
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
throws SQLException {
if (metadataField != null && mapping!=null)
{
Metadatum[] vals = item.getMetadataByMetadataString(metadataField);
if (vals.length > 0)
{
for (Metadatum value : vals){
String type = value.value;
if (mapping.containsKey(type)){
return mapping.get(type);
}
}
}
}
return null;
}
public ItemMarkingMetadataStrategy() {
}
public void setMetadataField(String metadataField) {
this.metadataField = metadataField;
}
@Override
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
throws SQLException {
if (metadataField != null && mapping != null) {
List<MetadataValue> vals = itemService.getMetadataByMetadataString(item, metadataField);
if (vals.size() > 0) {
for (MetadataValue value : vals) {
String type = value.getValue();
if (mapping.containsKey(type)) {
return mapping.get(type);
}
}
}
}
return null;
}
public void setMetadataField(String metadataField) {
this.metadataField = metadataField;
}
public void setMapping(Map<String, ItemMarkingInfo> mapping) {
this.mapping = mapping;
}
public void setMapping(Map<String, ItemMarkingInfo> mapping) {
this.mapping = mapping;
}
}

View File

@@ -12,70 +12,69 @@ import java.util.LinkedHashMap;
import java.util.Map;
/**
* Container for UpdateActions
* Order of actions is very import for correct processing. This implementation
* supports an iterator that returns the actions in the order in which they are
* put in. Adding the same action a second time has no effect on this order.
* Container for UpdateActions
* Order of actions is very import for correct processing. This implementation
* supports an iterator that returns the actions in the order in which they are
* put in. Adding the same action a second time has no effect on this order.
*
*
*/
public class ActionManager implements Iterable<UpdateAction> {
protected Map<Class<? extends UpdateAction>, UpdateAction> registry
= new LinkedHashMap<Class<? extends UpdateAction>, UpdateAction>();
/**
* Get update action
*
* @param actionClass UpdateAction class
* @return instantiation of UpdateAction class
* @throws InstantiationException if instantiation error
* @throws IllegalAccessException if illegal access error
*/
public UpdateAction getUpdateAction(Class<? extends UpdateAction> actionClass)
throws InstantiationException, IllegalAccessException {
UpdateAction action = registry.get(actionClass);
if (action == null) {
action = actionClass.newInstance();
registry.put(actionClass, action);
}
return action;
}
/**
* @return whether any actions have been registered with this manager
*/
public boolean hasActions() {
return !registry.isEmpty();
}
/**
* This implementation guarantees the iterator order is the same as the order
* in which updateActions have been added
*
* @return iterator for UpdateActions
*/
@Override
public Iterator<UpdateAction> iterator() {
return new Iterator<UpdateAction>() {
private Iterator<Class<? extends UpdateAction>> itr = registry.keySet().iterator();
@Override
public boolean hasNext() {
return itr.hasNext();
}
@Override
public UpdateAction next() {
return registry.get(itr.next());
}
//not supported
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
private Map<Class<? extends UpdateAction>, UpdateAction> registry
= new LinkedHashMap<Class<? extends UpdateAction>, UpdateAction>();
public UpdateAction getUpdateAction(Class<? extends UpdateAction> actionClass)
throws InstantiationException, IllegalAccessException
{
UpdateAction action = registry.get(actionClass);
if (action == null)
{
action = actionClass.newInstance();
registry.put(actionClass, action);
}
return action;
}
/**
*
* @return whether any actions have been registered with this manager
*/
public boolean hasActions()
{
return !registry.isEmpty();
}
/**
* This implementation guarantees the iterator order is the same as the order
* in which updateActions have been added
*
* @return iterator for UpdateActions
*/
public Iterator<UpdateAction> iterator()
{
return new Iterator<UpdateAction>()
{
private Iterator<Class<? extends UpdateAction>> itr = registry.keySet().iterator();
public boolean hasNext()
{
return itr.hasNext();
}
public UpdateAction next()
{
return registry.get(itr.next());
}
//not supported
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
}

View File

@@ -17,192 +17,196 @@ import java.util.ArrayList;
import java.util.List;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.content.Bitstream;
import org.dspace.content.BitstreamFormat;
import org.dspace.content.Bundle;
import org.dspace.content.DCDate;
import org.dspace.content.FormatIdentifier;
import org.dspace.content.InstallItem;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.content.service.InstallItemService;
import org.dspace.core.Context;
import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.GroupService;
/**
* Action to add bitstreams listed in item contents file to the item in DSpace
* Action to add bitstreams listed in item contents file to the item in DSpace
*
*
*/
public class AddBitstreamsAction extends UpdateBitstreamsAction {
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance()
.getBitstreamFormatService();
protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
public AddBitstreamsAction() {
//empty
}
/**
* Adds bitstreams from the archive as listed in the contents file.
*
* @param context DSpace Context
* @param itarch Item Archive
* @param isTest test flag
* @param suppressUndo undo flag
* @throws IOException if IO error
* @throws IllegalArgumentException if arg exception
* @throws SQLException if database error
* @throws AuthorizeException if authorization error
* @throws ParseException if parse error
*/
@Override
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws IllegalArgumentException,
ParseException, IOException, AuthorizeException, SQLException {
Item item = itarch.getItem();
File dir = itarch.getDirectory();
List<ContentsEntry> contents = MetadataUtilities.readContentsFile(new File(dir, ItemUpdate.CONTENTS_FILE));
if (contents.isEmpty()) {
ItemUpdate.pr("Contents is empty - no bitstreams to add");
return;
}
ItemUpdate.pr("Contents bitstream count: " + contents.size());
String[] files = dir.list(ItemUpdate.fileFilter);
List<String> fileList = new ArrayList<String>();
for (String filename : files) {
fileList.add(filename);
ItemUpdate.pr("file: " + filename);
}
for (ContentsEntry ce : contents) {
//validate match to existing file in archive
if (!fileList.contains(ce.filename)) {
throw new IllegalArgumentException("File listed in contents is missing: " + ce.filename);
}
}
int bitstream_bundles_updated = 0;
//now okay to add
for (ContentsEntry ce : contents) {
String targetBundleName = addBitstream(context, itarch, item, dir, ce, suppressUndo, isTest);
if (!targetBundleName.equals("")
&& !targetBundleName.equals("THUMBNAIL")
&& !targetBundleName.equals("TEXT")) {
bitstream_bundles_updated++;
}
}
if (alterProvenance && bitstream_bundles_updated > 0) {
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
String append = ". Added " + Integer.toString(bitstream_bundles_updated)
+ " bitstream(s) on " + DCDate.getCurrent() + " : "
+ installItemService.getBitstreamProvenanceMessage(context, item);
MetadataUtilities.appendMetadata(context, item, dtom, false, append);
}
}
/**
* Add bitstream
*
* @param context DSpace Context
* @param itarch Item Archive
* @param item DSpace Item
* @param dir directory
* @param ce contents entry for bitstream
* @param suppressUndo undo flag
* @param isTest test flag
* @return bundle name
* @throws IOException if IO error
* @throws IllegalArgumentException if arg exception
* @throws SQLException if database error
* @throws AuthorizeException if authorization error
* @throws ParseException if parse error
*/
protected String addBitstream(Context context, ItemArchive itarch, Item item, File dir,
ContentsEntry ce, boolean suppressUndo, boolean isTest)
throws IOException, IllegalArgumentException, SQLException, AuthorizeException, ParseException {
ItemUpdate.pr("contents entry for bitstream: " + ce.toString());
File f = new File(dir, ce.filename);
public AddBitstreamsAction()
{
//empty
}
/**
* Adds bitstreams from the archive as listed in the contents file.
*
* @param context
* @param itarch
* @param isTest
* @param suppressUndo
* @throws IllegalArgumentException
* @throws ParseException
* @throws IOException
* @throws AuthorizeException
* @throws SQLException
*/
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws IllegalArgumentException,
ParseException, IOException, AuthorizeException, SQLException
{
Item item = itarch.getItem();
File dir = itarch.getDirectory();
List<ContentsEntry> contents = MetadataUtilities.readContentsFile(new File(dir, ItemUpdate.CONTENTS_FILE));
if (contents.isEmpty())
{
ItemUpdate.pr("Contents is empty - no bitstreams to add");
return;
}
ItemUpdate.pr("Contents bitstream count: " + contents.size());
String[] files = dir.list(ItemUpdate.fileFilter);
List<String> fileList = new ArrayList<String>();
for (String filename : files)
{
fileList.add(filename);
ItemUpdate.pr("file: " + filename);
}
for (ContentsEntry ce : contents)
{
//validate match to existing file in archive
if (!fileList.contains(ce.filename))
{
throw new IllegalArgumentException("File listed in contents is missing: " + ce.filename);
}
}
int bitstream_bundles_updated = 0;
//now okay to add
for (ContentsEntry ce : contents)
{
String targetBundleName = addBitstream(context, itarch, item, dir, ce, suppressUndo, isTest);
if (!targetBundleName.equals("")
&& !targetBundleName.equals("THUMBNAIL")
&& !targetBundleName.equals("TEXT"))
{
bitstream_bundles_updated++;
}
}
if (alterProvenance && bitstream_bundles_updated > 0)
{
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
String append = ". Added " + Integer.toString(bitstream_bundles_updated)
+ " bitstream(s) on " + DCDate.getCurrent() + " : "
+ InstallItem.getBitstreamProvenanceMessage(item);
MetadataUtilities.appendMetadata(item, dtom, false, append);
}
}
private String addBitstream(Context context, ItemArchive itarch, Item item, File dir,
ContentsEntry ce, boolean suppressUndo, boolean isTest)
throws IOException, IllegalArgumentException, SQLException, AuthorizeException, ParseException
{
ItemUpdate.pr("contents entry for bitstream: " + ce.toString());
File f = new File(dir, ce.filename);
// get an input stream
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
Bitstream bs = null;
String newBundleName = ce.bundlename;
if (ce.bundlename == null) { // should be required but default convention established
if (ce.filename.equals("license.txt")) {
if (ce.bundlename == null) // should be required but default convention established
{
if (ce.filename.equals("license.txt"))
{
newBundleName = "LICENSE";
} else {
}
else
{
newBundleName = "ORIGINAL";
}
}
ItemUpdate.pr(" Bitstream " + ce.filename + " to be added to bundle: " + newBundleName);
if (!isTest)
{
// find the bundle
Bundle[] bundles = item.getBundles(newBundleName);
Bundle targetBundle = null;
if (bundles.length < 1)
{
// not found, create a new one
targetBundle = item.createBundle(newBundleName);
}
else
{
//verify bundle + name are not duplicates
for (Bundle b : bundles)
{
Bitstream[] bitstreams = b.getBitstreams();
for (Bitstream bsm : bitstreams)
{
if (bsm.getName().equals(ce.filename))
{
throw new IllegalArgumentException("Duplicate bundle + filename cannot be added: "
+ b.getName() + " + " + bsm.getName());
}
}
}
if (!isTest) {
// find the bundle
List<Bundle> bundles = itemService.getBundles(item, newBundleName);
Bundle targetBundle = null;
if (bundles.size() < 1) {
// not found, create a new one
targetBundle = bundleService.create(context, item, newBundleName);
} else {
//verify bundle + name are not duplicates
for (Bundle b : bundles) {
List<Bitstream> bitstreams = b.getBitstreams();
for (Bitstream bsm : bitstreams) {
if (bsm.getName().equals(ce.filename)) {
throw new IllegalArgumentException("Duplicate bundle + filename cannot be added: "
+ b.getName() + " + " + bsm.getName());
}
}
}
// select first bundle
targetBundle = bundles.iterator().next();
}
bs = bitstreamService.create(context, targetBundle, bis);
bs.setName(context, ce.filename);
// Identify the format
// FIXME - guessing format guesses license.txt incorrectly as a text file format!
BitstreamFormat fmt = bitstreamFormatService.guessFormat(context, bs);
bitstreamService.setFormat(context, bs, fmt);
if (ce.description != null) {
bs.setDescription(context, ce.description);
}
if ((ce.permissionsActionId != -1) && (ce.permissionsGroupName != null)) {
Group group = groupService.findByName(context, ce.permissionsGroupName);
if (group != null) {
authorizeService.removeAllPolicies(context, bs); // remove the default policy
authorizeService.createResourcePolicy(context, bs, group, null, ce.permissionsActionId, null);
}
}
//update after all changes are applied
bitstreamService.update(context, bs);
if (!suppressUndo) {
itarch.addUndoDeleteContents(bs.getID());
}
return targetBundle.getName();
// select first bundle
targetBundle = bundles[0];
}
bs = targetBundle.createBitstream(bis);
bs.setName(ce.filename);
// Identify the format
// FIXME - guessing format guesses license.txt incorrectly as a text file format!
BitstreamFormat fmt = FormatIdentifier.guessFormat(context, bs);
bs.setFormat(fmt);
if (ce.description != null)
{
bs.setDescription(ce.description);
}
if ((ce.permissionsActionId != -1) && (ce.permissionsGroupName != null))
{
Group group = Group.findByName(context, ce.permissionsGroupName);
if (group != null)
{
AuthorizeManager.removeAllPolicies(context, bs); // remove the default policy
ResourcePolicy rp = ResourcePolicy.create(context);
rp.setResource(bs);
rp.setAction(ce.permissionsActionId);
rp.setGroup(group);
rp.update();
}
}
//update after all changes are applied
bs.update();
if (!suppressUndo)
{
itarch.addUndoDeleteContents(bs.getID());
}
return targetBundle.getName();
}
return "";
return "";
}
}

View File

@@ -8,110 +8,113 @@
package org.dspace.app.itemupdate;
import java.sql.SQLException;
import java.util.List;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Metadatum;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.core.Context;
/**
* Action to add metadata to item
* Action to add metadata to item
*
*/
public class AddMetadataAction extends UpdateMetadataAction {
protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance()
.getMetadataSchemaService();
protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
/**
* Adds metadata specified in the source archive
*
* @param context DSpace Context
* @param itarch item archive
* @param isTest test flag
* @param suppressUndo undo flag
* @throws AuthorizeException if authorization error
* @throws SQLException if database error
*/
@Override
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws AuthorizeException, SQLException {
Item item = itarch.getItem();
String dirname = itarch.getDirectoryName();
for (DtoMetadata dtom : itarch.getMetadataFields()) {
for (String f : targetFields) {
if (dtom.matches(f, false)) {
// match against metadata for this field/value in repository
// qualifier must be strictly matched, possibly null
List<MetadataValue> ardcv = null;
ardcv = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
boolean found = false;
for (MetadataValue dcv : ardcv) {
if (dcv.getValue().equals(dtom.value)) {
found = true;
break;
}
}
if (found) {
ItemUpdate.pr("Warning: No new metadata found to add to item " + dirname
+ " for element " + f);
} else {
if (isTest) {
ItemUpdate.pr("Metadata to add: " + dtom.toString());
//validity tests that would occur in actual processing
// If we're just test the import, let's check that the actual metadata field exists.
MetadataSchema foundSchema = metadataSchemaService.find(context, dtom.schema);
if (foundSchema == null) {
ItemUpdate.pr("ERROR: schema '"
+ dtom.schema + "' was not found in the registry; found on item " +
dirname);
} else {
MetadataField foundField = metadataFieldService
.findByElement(context, foundSchema, dtom.element, dtom.qualifier);
if (foundField == null) {
ItemUpdate.pr("ERROR: Metadata field: '" + dtom.schema + "." + dtom.element + "."
+ dtom.qualifier + "' not found in registry; found on item " +
dirname);
}
}
} else {
itemService
.addMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language,
dtom.value);
ItemUpdate.pr("Metadata added: " + dtom.toString());
if (!suppressUndo) {
//itarch.addUndoDtom(dtom);
//ItemUpdate.pr("Undo metadata: " + dtom);
// add all as a replace record to be preceded by delete
for (MetadataValue dcval : ardcv) {
MetadataField metadataField = dcval.getMetadataField();
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
itarch.addUndoMetadataField(
DtoMetadata.create(metadataSchema.getName(), metadataField.getElement(),
metadataField.getQualifier(), dcval.getLanguage(),
dcval.getValue()));
}
}
}
}
break; // don't need to check if this field matches any other target fields
}
}
}
}
/**
* Adds metadata specified in the source archive
*
* @param context
* @param itarch
* @param isTest
* @param suppressUndo
* @throws AuthorizeException
* @throws SQLException
*/
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws AuthorizeException, SQLException
{
Item item = itarch.getItem();
String dirname = itarch.getDirectoryName();
for (DtoMetadata dtom : itarch.getMetadataFields())
{
for (String f : targetFields)
{
if (dtom.matches(f, false))
{
// match against metadata for this field/value in repository
// qualifier must be strictly matched, possibly null
Metadatum[] ardcv = null;
ardcv = item.getMetadata(dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
boolean found = false;
for (Metadatum dcv : ardcv)
{
if (dcv.value.equals(dtom.value))
{
found = true;
break;
}
}
if (found)
{
ItemUpdate.pr("Warning: No new metadata found to add to item " + dirname
+ " for element " + f);
}
else
{
if (isTest)
{
ItemUpdate.pr("Metadata to add: " + dtom.toString());
//validity tests that would occur in actual processing
// If we're just test the import, let's check that the actual metadata field exists.
MetadataSchema foundSchema = MetadataSchema.find(context, dtom.schema);
if (foundSchema == null)
{
ItemUpdate.pr("ERROR: schema '"
+ dtom.schema + "' was not found in the registry; found on item " + dirname);
}
else
{
int schemaID = foundSchema.getSchemaID();
MetadataField foundField = MetadataField.findByElement(context, schemaID, dtom.element, dtom.qualifier);
if (foundField == null)
{
ItemUpdate.pr("ERROR: Metadata field: '" + dtom.schema + "." + dtom.element + "."
+ dtom.qualifier + "' not found in registry; found on item " + dirname);
}
}
}
else
{
item.addMetadata(dtom.schema, dtom.element, dtom.qualifier, dtom.language, dtom.value);
ItemUpdate.pr("Metadata added: " + dtom.toString());
if (!suppressUndo)
{
//itarch.addUndoDtom(dtom);
//ItemUpdate.pr("Undo metadata: " + dtom);
// add all as a replace record to be preceded by delete
for (Metadatum dcval : ardcv)
{
itarch.addUndoMetadataField(DtoMetadata.create(dcval.schema, dcval.element,
dcval.qualifier, dcval.language, dcval.value));
}
}
}
}
break; // don't need to check if this field matches any other target fields
}
}
}
}
}

View File

@@ -7,49 +7,55 @@
*/
package org.dspace.app.itemupdate;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.io.InputStream;
import java.io.FileInputStream;
import org.dspace.content.Bitstream;
/**
* Filter interface to be used by ItemUpdate
* to determine which bitstreams in an Item
* acceptable for removal.
* Filter interface to be used by ItemUpdate
* to determine which bitstreams in an Item
* acceptable for removal.
*
*/
public abstract class BitstreamFilter {
protected Properties props = null;
protected Properties props = null;
/**
* The filter method
*
* @param bitstream
* @return whether the bitstream matches the criteria
* @throws BitstreamFilterException
*/
public abstract boolean accept(Bitstream bitstream) throws BitstreamFilterException;
/**
*
* @param filepath - The complete path for the properties file
* @throws IOException
*/
public void initProperties(String filepath)
throws IOException
{
props = new Properties();
InputStream in = null;
/**
* The filter method
*
* @param bitstream Bitstream
* @return whether the bitstream matches the criteria
* @throws BitstreamFilterException if filter error
*/
public abstract boolean accept(Bitstream bitstream) throws BitstreamFilterException;
/**
* @param filepath - The complete path for the properties file
* @throws IOException if IO error
*/
public void initProperties(String filepath)
throws IOException {
props = new Properties();
InputStream in = null;
try {
try
{
in = new FileInputStream(filepath);
props.load(in);
} finally {
if (in != null) {
}
finally
{
if (in != null)
{
in.close();
}
}
}
}
}

View File

@@ -8,50 +8,59 @@
package org.dspace.app.itemupdate;
import java.sql.SQLException;
import java.util.List;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
/**
* BitstreamFilter implementation to filter by bundle name
* BitstreamFilter implementation to filter by bundle name
*
*/
public class BitstreamFilterByBundleName extends BitstreamFilter {
protected String bundleName;
public BitstreamFilterByBundleName() {
//empty
}
/**
* Filter bitstream based on bundle name found in properties file
*
* @param bitstream Bitstream
* @return whether bitstream is in bundle
* @throws BitstreamFilterException if filter error
*/
@Override
public boolean accept(Bitstream bitstream)
throws BitstreamFilterException {
if (bundleName == null) {
bundleName = props.getProperty("bundle");
if (bundleName == null) {
throw new BitstreamFilterException("Property 'bundle' not found.");
}
}
try {
List<Bundle> bundles = bitstream.getBundles();
for (Bundle b : bundles) {
if (b.getName().equals(bundleName)) {
return true;
}
}
} catch (SQLException e) {
throw new BitstreamFilterException(e);
}
return false;
}
protected String bundleName;
public BitstreamFilterByBundleName()
{
//empty
}
/**
* Filter bitstream based on bundle name found in properties file
*
* @param bitstream
* @throws BitstreamFilterException
* @return whether bitstream is in bundle
*
*/
public boolean accept(Bitstream bitstream)
throws BitstreamFilterException
{
if (bundleName == null)
{
bundleName = props.getProperty("bundle");
if (bundleName == null)
{
throw new BitstreamFilterException("Property 'bundle' not found.");
}
}
try
{
Bundle[] bundles = bitstream.getBundles();
for (Bundle b : bundles)
{
if (b.getName().equals(bundleName))
{
return true;
}
}
}
catch(SQLException e)
{
throw new BitstreamFilterException(e);
}
return false;
}
}

View File

@@ -7,43 +7,44 @@
*/
package org.dspace.app.itemupdate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.*;
import org.dspace.content.Bitstream;
/**
* BitstreamFilter implementation to filter by filename pattern
*
*/
public class BitstreamFilterByFilename extends BitstreamFilter {
private Pattern pattern;
private String filenameRegex;
public BitstreamFilterByFilename()
{
//empty
}
protected Pattern pattern;
protected String filenameRegex;
public BitstreamFilterByFilename() {
//empty
}
/**
* Tests bitstream by matching the regular expression in the
* properties against the bitstream name
*
* @param bitstream Bitstream
* @return whether bitstream name matches the regular expression
* @throws BitstreamFilterException if filter error
*/
@Override
public boolean accept(Bitstream bitstream) throws BitstreamFilterException {
if (filenameRegex == null) {
filenameRegex = props.getProperty("filename");
if (filenameRegex == null) {
throw new BitstreamFilterException("BitstreamFilter property 'filename' not found.");
}
pattern = Pattern.compile(filenameRegex);
}
Matcher m = pattern.matcher(bitstream.getName());
return m.matches();
}
/**
* Tests bitstream by matching the regular expression in the
* properties against the bitstream name
*
* @return whether bitstream name matches the regular expression
*/
public boolean accept(Bitstream bitstream) throws BitstreamFilterException
{
if (filenameRegex == null)
{
filenameRegex = props.getProperty("filename");
if (filenameRegex == null)
{
throw new BitstreamFilterException("BitstreamFilter property 'filename' not found.");
}
pattern = Pattern.compile(filenameRegex);
}
Matcher m = pattern.matcher(bitstream.getName());
return m.matches();
}
}

View File

@@ -8,27 +8,22 @@
package org.dspace.app.itemupdate;
/**
* Exception class for BitstreamFilters
* Exception class for BitstreamFilters
*
*/
public class BitstreamFilterException extends Exception {
private static final long serialVersionUID = 1L;
public BitstreamFilterException() {
}
/**
* @param msg exception message
*/
public BitstreamFilterException(String msg) {
super(msg);
}
/**
* @param e exception
*/
public BitstreamFilterException(Exception e) {
super(e);
}
public class BitstreamFilterException extends Exception
{
private static final long serialVersionUID = 1L;
public BitstreamFilterException() {}
public BitstreamFilterException(String msg)
{
super(msg);
}
public BitstreamFilterException(Exception e)
{
super(e);
}
}

View File

@@ -8,124 +8,146 @@
package org.dspace.app.itemupdate;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.*;
import org.dspace.core.Constants;
/**
* Holds the elements of a line in the Contents Entry file
* Holds the elements of a line in the Contents Entry file
*
* Based on private methods in ItemImport
*
* Lacking a spec or full documentation for the file format,
* it looks from the source code that the ordering or elements is not fixed
*
* e.g.:
* 48217870-MIT.pdf\tbundle: bundlename\tpermissions: -r 'MIT Users'\tdescription: Full printable version (MIT only)
* permissions: -[r|w] ['group name']
* description: <the description of the file>
*
*
* Based on private methods in ItemImport
*
* Lacking a spec or full documentation for the file format,
* it looks from the source code that the ordering or elements is not fixed
*
* e.g.:
* {@code
* 48217870-MIT.pdf\tbundle: bundlename\tpermissions: -r 'MIT Users'\tdescription: Full printable version (MIT only)
* permissions: -[r|w] ['group name']
* description: <the description of the file>
* }
*/
public class ContentsEntry {
public static final String HDR_BUNDLE = "bundle:";
public static final String HDR_PERMISSIONS = "permissions:";
public static final String HDR_DESCRIPTION = "description:";
public static final Pattern permissionsPattern = Pattern.compile("-([rw])\\s*'?([^']+)'?");
final String filename;
final String bundlename;
final String permissionsGroupName;
final int permissionsActionId;
final String description;
protected ContentsEntry(String filename,
String bundlename,
int permissionsActionId,
String permissionsGroupName,
String description) {
this.filename = filename;
this.bundlename = bundlename;
this.permissionsActionId = permissionsActionId;
this.permissionsGroupName = permissionsGroupName;
this.description = description;
}
/**
* Factory method parses a line from the Contents Entry file
*
* @param line line as string
* @return the parsed ContentsEntry object
* @throws ParseException if parse error
*/
public static ContentsEntry parse(String line)
throws ParseException {
String[] ar = line.split("\t");
ItemUpdate.pr("ce line split: " + ar.length);
String[] arp = new String[4];
arp[0] = ar[0]; //bitstream name doesn't have header and is always first
String groupName = null;
int actionId = -1;
if (ar.length > 1) {
for (int i = 1; i < ar.length; i++) {
ItemUpdate.pr("ce " + i + " : " + ar[i]);
if (ar[i].startsWith(HDR_BUNDLE)) {
arp[1] = ar[i].substring(HDR_BUNDLE.length()).trim();
} else if (ar[i].startsWith(HDR_PERMISSIONS)) {
arp[2] = ar[i].substring(HDR_PERMISSIONS.length()).trim();
// parse into actionId and group name
Matcher m = permissionsPattern.matcher(arp[2]);
if (m.matches()) {
String action = m.group(1); //
if (action.equals("r")) {
actionId = Constants.READ;
} else if (action.equals("w")) {
actionId = Constants.WRITE;
}
groupName = m.group(2).trim();
}
} else if (ar[i].startsWith(HDR_DESCRIPTION)) {
arp[3] = ar[i].substring(HDR_DESCRIPTION.length()).trim();
} else {
throw new ParseException("Unknown text in contents file: " + ar[i], 0);
}
}
}
return new ContentsEntry(arp[0], arp[1], actionId, groupName, arp[3]);
}
public String toString() {
StringBuilder sb = new StringBuilder(filename);
if (bundlename != null) {
sb.append(HDR_BUNDLE).append(" ").append(bundlename);
}
if (permissionsGroupName != null) {
sb.append(HDR_PERMISSIONS);
if (permissionsActionId == Constants.READ) {
sb.append(" -r ");
} else if (permissionsActionId == Constants.WRITE) {
sb.append(" -w ");
}
sb.append(permissionsGroupName);
}
if (description != null) {
sb.append(HDR_DESCRIPTION).append(" ").append(description);
}
return sb.toString();
}
public class ContentsEntry
{
public static final String HDR_BUNDLE = "bundle:";
public static final String HDR_PERMISSIONS = "permissions:";
public static final String HDR_DESCRIPTION = "description:";
public static final Pattern permissionsPattern = Pattern.compile("-([rw])\\s*'?([^']+)'?");
final String filename;
final String bundlename;
final String permissionsGroupName;
final int permissionsActionId;
final String description;
private ContentsEntry(String filename,
String bundlename,
int permissionsActionId,
String permissionsGroupName,
String description)
{
this.filename = filename;
this.bundlename = bundlename;
this.permissionsActionId = permissionsActionId;
this.permissionsGroupName = permissionsGroupName;
this.description = description;
}
/**
* Factory method parses a line from the Contents Entry file
*
* @param line
* @return the parsed ContentsEntry object
* @throws ParseException
*/
public static ContentsEntry parse(String line)
throws ParseException
{
String[] ar = line.split("\t");
ItemUpdate.pr("ce line split: " + ar.length);
String[] arp = new String[4];
arp[0] = ar[0]; //bitstream name doesn't have header and is always first
String groupName = null;
int actionId = -1;
if (ar.length > 1)
{
for (int i=1; i < ar.length; i++)
{
ItemUpdate.pr("ce " + i + " : " + ar[i]);
if (ar[i].startsWith(HDR_BUNDLE))
{
arp[1] = ar[i].substring(HDR_BUNDLE.length()).trim();
}
else if (ar[i].startsWith(HDR_PERMISSIONS))
{
arp[2] = ar[i].substring(HDR_PERMISSIONS.length()).trim();
// parse into actionId and group name
Matcher m = permissionsPattern.matcher(arp[2]);
if (m.matches())
{
String action = m.group(1); //
if (action.equals("r"))
{
actionId = Constants.READ;
}
else if (action.equals("w"))
{
actionId = Constants.WRITE;
}
groupName = m.group(2).trim();
}
}
else if (ar[i].startsWith(HDR_DESCRIPTION))
{
arp[3] = ar[i].substring(HDR_DESCRIPTION.length()).trim();
}
else
{
throw new ParseException("Unknown text in contents file: " + ar[i], 0);
}
}
}
return new ContentsEntry(arp[0], arp[1], actionId, groupName, arp[3]);
}
public String toString()
{
StringBuilder sb = new StringBuilder(filename);
if (bundlename != null)
{
sb.append(HDR_BUNDLE).append(" ").append(bundlename);
}
if (permissionsGroupName != null)
{
sb.append(HDR_PERMISSIONS);
if (permissionsActionId == Constants.READ)
{
sb.append(" -r ");
}
else if (permissionsActionId == Constants.WRITE)
{
sb.append(" -w ");
}
sb.append(permissionsGroupName);
}
if (description != null)
{
sb.append(HDR_DESCRIPTION).append(" ").append(description);
}
return sb.toString();
}
}

View File

@@ -21,74 +21,94 @@ import org.dspace.content.Item;
import org.dspace.core.Context;
/**
* Action to delete bitstreams
* Action to delete bitstreams
*
* Undo not supported for this UpdateAction
*
* Derivatives of the bitstream to be deleted are not also deleted
*
* Undo not supported for this UpdateAction
*
* Derivatives of the bitstream to be deleted are not also deleted
*/
public class DeleteBitstreamsAction extends UpdateBitstreamsAction {
/**
* Delete bitstream from item
*
* @param context DSpace Context
* @param itarch item archive
* @param isTest test flag
* @param suppressUndo undo flag
* @throws IOException if IO error
* @throws IllegalArgumentException if arg exception
* @throws SQLException if database error
* @throws AuthorizeException if authorization error
* @throws ParseException if parse error
*/
@Override
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws IllegalArgumentException, IOException,
SQLException, AuthorizeException, ParseException {
File f = new File(itarch.getDirectory(), ItemUpdate.DELETE_CONTENTS_FILE);
if (!f.exists()) {
ItemUpdate.pr("Warning: Delete_contents file for item " + itarch.getDirectoryName() + " not found.");
} else {
List<String> list = MetadataUtilities.readDeleteContentsFile(f);
if (list.isEmpty()) {
ItemUpdate.pr("Warning: empty delete_contents file for item " + itarch.getDirectoryName());
} else {
for (String id : list) {
try {
Bitstream bs = bitstreamService.findByIdOrLegacyId(context, id);
if (bs == null) {
ItemUpdate.pr("Bitstream not found by id: " + id);
} else {
List<Bundle> bundles = bs.getBundles();
for (Bundle b : bundles) {
if (isTest) {
ItemUpdate.pr("Delete bitstream with id = " + id);
} else {
bundleService.removeBitstream(context, b, bs);
ItemUpdate.pr("Deleted bitstream with id = " + id);
}
}
if (alterProvenance) {
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
String append = "Bitstream " + bs.getName() + " deleted on " + DCDate
.getCurrent() + "; ";
Item item = bundles.iterator().next().getItems().iterator().next();
ItemUpdate.pr("Append provenance with: " + append);
if (!isTest) {
MetadataUtilities.appendMetadata(context, item, dtom, false, append);
}
}
}
} catch (SQLException e) {
ItemUpdate.pr("Error finding bitstream from id: " + id + " : " + e.toString());
}
}
}
}
}
public class DeleteBitstreamsAction extends UpdateBitstreamsAction
{
/**
* Delete bitstream from item
*
* @param context
* @param itarch
* @param isTest
* @param suppressUndo
* @throws IllegalArgumentException
* @throws ParseException
* @throws IOException
* @throws AuthorizeException
* @throws SQLException
*/
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws IllegalArgumentException, IOException,
SQLException, AuthorizeException, ParseException
{
File f = new File(itarch.getDirectory(), ItemUpdate.DELETE_CONTENTS_FILE);
if (!f.exists())
{
ItemUpdate.pr("Warning: Delete_contents file for item " + itarch.getDirectoryName() + " not found.");
}
else
{
List<Integer> list = MetadataUtilities.readDeleteContentsFile(f);
if (list.isEmpty())
{
ItemUpdate.pr("Warning: empty delete_contents file for item " + itarch.getDirectoryName() );
}
else
{
for (int id : list)
{
try
{
Bitstream bs = Bitstream.find(context, id);
if (bs == null)
{
ItemUpdate.pr("Bitstream not found by id: " + id);
}
else
{
Bundle[] bundles = bs.getBundles();
for (Bundle b : bundles)
{
if (isTest)
{
ItemUpdate.pr("Delete bitstream with id = " + id);
}
else
{
b.removeBitstream(bs);
ItemUpdate.pr("Deleted bitstream with id = " + id);
}
}
if (alterProvenance)
{
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
String append = "Bitstream " + bs.getName() + " deleted on " + DCDate.getCurrent() + "; ";
Item item = bundles[0].getItems()[0];
ItemUpdate.pr("Append provenance with: " + append);
if (!isTest)
{
MetadataUtilities.appendMetadata(item, dtom, false, append);
}
}
}
}
catch(SQLException e)
{
ItemUpdate.pr("Error finding bitstream from id: " + id + " : " + e.toString());
}
}
}
}
}
}

View File

@@ -21,97 +21,110 @@ import org.dspace.content.Item;
import org.dspace.core.Context;
/**
* Action to delete bitstreams using a specified filter implementing BitstreamFilter
* Derivatives for the target bitstreams are not deleted.
* Action to delete bitstreams using a specified filter implementing BitstreamFilter
* Derivatives for the target bitstreams are not deleted.
*
* The dc.description.provenance field is amended to reflect the deletions
*
* Note: Multiple filters are impractical if trying to manage multiple properties files
* in a commandline environment
*
*
* The dc.description.provenance field is amended to reflect the deletions
*
* Note: Multiple filters are impractical if trying to manage multiple properties files
* in a commandline environment
*/
public class DeleteBitstreamsByFilterAction extends UpdateBitstreamsAction {
protected BitstreamFilter filter;
/**
* Set filter
*
* @param filter BitstreamFilter
*/
public void setBitstreamFilter(BitstreamFilter filter) {
this.filter = filter;
}
/**
* Get filter
*
* @return filter
*/
public BitstreamFilter getBitstreamFilter() {
return filter;
}
/**
* Delete bitstream
*
* @param context DSpace Context
* @param itarch item archive
* @param isTest test flag
* @param suppressUndo undo flag
* @throws IOException if IO error
* @throws SQLException if database error
* @throws AuthorizeException if authorization error
* @throws ParseException if parse error
* @throws BitstreamFilterException if filter error
*/
@Override
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws AuthorizeException,
BitstreamFilterException, IOException, ParseException, SQLException {
List<String> deleted = new ArrayList<String>();
Item item = itarch.getItem();
List<Bundle> bundles = item.getBundles();
for (Bundle b : bundles) {
List<Bitstream> bitstreams = b.getBitstreams();
String bundleName = b.getName();
for (Bitstream bs : bitstreams) {
if (filter.accept(bs)) {
if (isTest) {
ItemUpdate.pr("Delete from bundle " + bundleName + " bitstream " + bs.getName()
+ " with id = " + bs.getID());
} else {
//provenance is not maintained for derivative bitstreams
if (!bundleName.equals("THUMBNAIL") && !bundleName.equals("TEXT")) {
deleted.add(bs.getName());
}
bundleService.removeBitstream(context, b, bs);
ItemUpdate.pr("Deleted " + bundleName + " bitstream " + bs.getName()
+ " with id = " + bs.getID());
}
}
}
private BitstreamFilter filter;
/**
* Set filter
*
* @param filter
*/
public void setBitstreamFilter(BitstreamFilter filter)
{
this.filter = filter;
}
/**
* Get filter
* @return filter
*/
public BitstreamFilter getBitstreamFilter()
{
return filter;
}
/**
* Delete bitstream
*
* @param context
* @param itarch
* @param isTest
* @param suppressUndo
* @throws IllegalArgumentException
* @throws ParseException
* @throws IOException
* @throws AuthorizeException
* @throws SQLException
*/
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws AuthorizeException,
BitstreamFilterException, IOException, ParseException, SQLException
{
List<String> deleted = new ArrayList<String>();
Item item = itarch.getItem();
Bundle[] bundles = item.getBundles();
for (Bundle b : bundles)
{
Bitstream[] bitstreams = b.getBitstreams();
String bundleName = b.getName();
for (Bitstream bs : bitstreams)
{
if (filter.accept(bs))
{
if (isTest)
{
ItemUpdate.pr("Delete from bundle " + bundleName + " bitstream " + bs.getName()
+ " with id = " + bs.getID());
}
else
{
//provenance is not maintained for derivative bitstreams
if (!bundleName.equals("THUMBNAIL") && !bundleName.equals("TEXT"))
{
deleted.add(bs.getName());
}
b.removeBitstream(bs);
ItemUpdate.pr("Deleted " + bundleName + " bitstream " + bs.getName()
+ " with id = " + bs.getID());
}
}
}
}
if (alterProvenance && !deleted.isEmpty())
{
StringBuilder sb = new StringBuilder(" Bitstreams deleted on ");
sb.append(DCDate.getCurrent()).append(": ");
for (String s : deleted)
{
sb.append(s).append(", ");
}
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
ItemUpdate.pr("Append provenance with: " + sb.toString());
if (!isTest)
{
MetadataUtilities.appendMetadata(item, dtom, false, sb.toString());
}
}
if (alterProvenance && !deleted.isEmpty()) {
StringBuilder sb = new StringBuilder(" Bitstreams deleted on ");
sb.append(DCDate.getCurrent()).append(": ");
for (String s : deleted) {
sb.append(s).append(", ");
}
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
ItemUpdate.pr("Append provenance with: " + sb.toString());
if (!isTest) {
MetadataUtilities.appendMetadata(context, item, dtom, false, sb.toString());
}
}
}
}
}

View File

@@ -7,59 +7,58 @@
*/
package org.dspace.app.itemupdate;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.List;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Metadatum;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
import org.dspace.core.Context;
/**
* Action to delete metadata
* Action to delete metadata
*
*
*/
public class DeleteMetadataAction extends UpdateMetadataAction {
/**
* Delete metadata from item
*
* @param context DSpace Context
* @param itarch Item Archive
* @param isTest test flag
* @param suppressUndo undo flag
* @throws SQLException if database error
* @throws AuthorizeException if authorization error
* @throws ParseException if parse error
*/
@Override
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws AuthorizeException, ParseException, SQLException {
Item item = itarch.getItem();
for (String f : targetFields) {
DtoMetadata dummy = DtoMetadata.create(f, Item.ANY, "");
List<MetadataValue> ardcv = itemService.getMetadataByMetadataString(item, f);
/**
* Delete metadata from item
*
* @param context
* @param itarch
* @param isTest
* @param suppressUndo
* @throws ParseException
* @throws AuthorizeException
*/
public void execute(Context context, ItemArchive itarch, boolean isTest,
boolean suppressUndo) throws AuthorizeException, ParseException
{
Item item = itarch.getItem();
for (String f : targetFields)
{
DtoMetadata dummy = DtoMetadata.create(f, Item.ANY, "");
Metadatum[] ardcv = item.getMetadataByMetadataString(f);
ItemUpdate.pr("Metadata to be deleted: ");
for (MetadataValue dcv : ardcv) {
ItemUpdate.pr(" " + MetadataUtilities.getDCValueString(dcv));
}
ItemUpdate.pr("Metadata to be deleted: ");
for (Metadatum dcv : ardcv)
{
ItemUpdate.pr(" " + MetadataUtilities.getDCValueString(dcv));
}
if (!isTest) {
if (!suppressUndo) {
for (MetadataValue dcv : ardcv) {
MetadataField metadataField = dcv.getMetadataField();
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
itarch.addUndoMetadataField(
DtoMetadata.create(metadataSchema.getName(), metadataField.getElement(),
metadataField.getQualifier(), dcv.getLanguage(), dcv.getValue()));
}
}
itemService.clearMetadata(context, item, dummy.schema, dummy.element, dummy.qualifier, Item.ANY);
}
}
}
if (!isTest)
{
if (!suppressUndo)
{
for (Metadatum dcv : ardcv)
{
itarch.addUndoMetadataField(DtoMetadata.create(dcv.schema, dcv.element,
dcv.qualifier, dcv.language, dcv.value));
}
}
item.clearMetadata(dummy.schema, dummy.element, dummy.qualifier, Item.ANY);
}
}
}
}

View File

@@ -10,13 +10,15 @@ package org.dspace.app.itemupdate;
import java.util.Properties;
/**
* Bitstream filter to delete from TEXT bundle
* Bitstream filter to delete from TEXT bundle
*
*/
public class DerivativeTextBitstreamFilter extends BitstreamFilterByBundleName {
public DerivativeTextBitstreamFilter() {
props = new Properties();
props.setProperty("bundle", "TEXT");
}
public DerivativeTextBitstreamFilter()
{
props = new Properties();
props.setProperty("bundle", "TEXT");
}
}

View File

@@ -8,131 +8,149 @@
package org.dspace.app.itemupdate;
import java.text.ParseException;
import org.dspace.content.Item;
/**
* A data transfer object class enhancement of org.dspace.content.DCValue, which is deprecated
* Name intended to not conflict with DSpace API classes for similar concepts but not usable in this context
* A data transfer object class enhancement of org.dspace.content.DCValue, which is deprecated
* Name intended to not conflict with DSpace API classes for similar concepts but not usable in this context
*
* Adds some utility methods
*
* Really not at all general enough but supports Dublin Core and the compound form notation <schema>.<element>[.<qualifier>]
*
* Does not support wildcard for qualifier
*
*
* Adds some utility methods
*
* Really not at all general enough but supports Dublin Core and the compound form notation {@code <schema>
* .<element>[.<qualifier>]}
*
* Does not support wildcard for qualifier
*/
class DtoMetadata {
final String schema;
final String element;
final String qualifier;
final String language;
final String value;
protected DtoMetadata(String schema, String element, String qualifier, String language, String value) {
this.schema = schema;
this.element = element;
this.qualifier = qualifier;
this.language = language;
this.value = value;
class DtoMetadata
{
final String schema;
final String element;
final String qualifier;
final String language;
final String value;
private DtoMetadata(String schema, String element, String qualifier, String language, String value)
{
this.schema = schema;
this.element = element;
this.qualifier = qualifier;
this.language = language;
this.value = value;
}
/**
* Factory method
*
*
* @param schema not null, not empty - 'dc' is the standard case
* @param element not null, not empty
* @param qualifier null; don't allow empty string or * indicating 'any'
* @param language null or empty
* @param value
* @return DtoMetadata object
*/
public static DtoMetadata create(String schema,
String element,
String qualifier,
String language,
String value)
throws IllegalArgumentException
{
if ((qualifier != null) && (qualifier.equals(Item.ANY) || qualifier.equals("")))
{
throw new IllegalArgumentException("Invalid qualifier: " + qualifier);
}
return new DtoMetadata(schema, element, qualifier, language, value);
}
/**
* Factory method
*
* @param schema not null, not empty - 'dc' is the standard case
* @param element not null, not empty
* @param qualifier null; don't allow empty string or * indicating 'any'
* @param language null or empty
* @param value value
* @return DtoMetadata object
* @throws IllegalArgumentException if arg error
*/
public static DtoMetadata create(String schema,
String element,
String qualifier,
String language,
String value)
throws IllegalArgumentException {
if ((qualifier != null) && (qualifier.equals(Item.ANY) || qualifier.equals(""))) {
throw new IllegalArgumentException("Invalid qualifier: " + qualifier);
}
return new DtoMetadata(schema, element, qualifier, language, value);
/**
* Factory method to create metadata object
*
*
* @param compoundForm of the form <schema>.<element>[.<qualifier>]
* @param language null or empty
* @param value
*/
public static DtoMetadata create(String compoundForm, String language, String value)
throws ParseException, IllegalArgumentException
{
String[] ar = MetadataUtilities.parseCompoundForm(compoundForm);
String qual = null;
if (ar.length > 2)
{
qual = ar[2];
}
return create(ar[0], ar[1], qual, language, value);
}
/**
* Factory method to create metadata object
*
* @param compoundForm of the form <schema>.<element>[.<qualifier>]
* @param language null or empty
* @param value value
* @throws ParseException if parse error
* @throws IllegalArgumentException if arg error
*/
public static DtoMetadata create(String compoundForm, String language, String value)
throws ParseException, IllegalArgumentException {
String[] ar = MetadataUtilities.parseCompoundForm(compoundForm);
String qual = null;
if (ar.length > 2) {
qual = ar[2];
}
return create(ar[0], ar[1], qual, language, value);
}
/**
* Determine if this metadata field matches the specified type:
* schema.element or schema.element.qualifier
*
* @param compoundForm of the form <schema>.<element>[.<qualifier>|.*]
* @param wildcard allow wildcards in compoundForm param
* @return whether matches
*/
public boolean matches(String compoundForm, boolean wildcard) {
String[] ar = compoundForm.split("\\s*\\.\\s*"); //MetadataUtilities.parseCompoundForm(compoundForm);
if ((ar.length < 2) || (ar.length > 3)) {
return false;
}
if (!this.schema.equals(ar[0]) || !this.element.equals(ar[1])) {
return false;
}
if (ar.length == 2) {
if (this.qualifier != null) {
return false;
}
}
if (ar.length == 3) {
if (this.qualifier == null) {
return false;
}
if (wildcard && ar[2].equals(Item.ANY)) {
return true;
}
if (!this.qualifier.equals(ar[2])) {
return false;
}
}
return true;
}
public String toString() {
String s = "\tSchema: " + schema + " Element: " + element;
if (qualifier != null) {
s += " Qualifier: " + qualifier;
}
s += " Language: " + ((language == null) ? "[null]" : language);
/**
* Determine if this metadata field matches the specified type:
* schema.element or schema.element.qualifier
*
*
* @param compoundForm of the form <schema>.<element>[.<qualifier>|.*]
* @param wildcard allow wildcards in compoundForm param
* @return whether matches
*/
public boolean matches(String compoundForm, boolean wildcard)
{
String[] ar = compoundForm.split("\\s*\\.\\s*"); //MetadataUtilities.parseCompoundForm(compoundForm);
if ((ar.length < 2) || (ar.length > 3))
{
return false;
}
if (!this.schema.equals(ar[0]) || !this.element.equals(ar[1]))
{
return false;
}
if (ar.length == 2)
{
if (this.qualifier != null)
{
return false;
}
}
if (ar.length == 3)
{
if (this.qualifier == null)
{
return false;
}
if (wildcard && ar[2].equals(Item.ANY))
{
return true;
}
if (!this.qualifier.equals(ar[2]))
{
return false;
}
}
return true;
}
public String toString()
{
String s = "\tSchema: " + schema + " Element: " + element;
if (qualifier != null)
{
s+= " Qualifier: " + qualifier;
}
s+= " Language: " + ((language == null) ? "[null]" : language);
s += " Value: " + value;
return s;
}
public String getValue() {
return value;
}
}
public String getValue()
{
return value;
}
}

View File

@@ -10,334 +10,339 @@ package org.dspace.app.itemupdate;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerConfigurationException;
import org.apache.log4j.Logger;
import org.dspace.app.util.LocalSchemaFilenameFilter;
import org.dspace.content.ItemIterator;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.handle.HandleManager;
import org.w3c.dom.Document;
/**
* Encapsulates the Item in the context of the DSpace Archive Format
* Encapsulates the Item in the context of the DSpace Archive Format
*
*/
public class ItemArchive {
private static final Logger log = Logger.getLogger(ItemArchive.class);
private static final Logger log = Logger.getLogger(ItemArchive.class);
public static final String DUBLIN_CORE_XML = "dublin_core.xml";
protected static DocumentBuilder builder = null;
protected Transformer transformer = null;
protected List<DtoMetadata> dtomList = null;
protected List<DtoMetadata> undoDtomList = new ArrayList<DtoMetadata>();
protected List<UUID> undoAddContents = new ArrayList<>(); // for undo of add
protected Item item;
protected File dir; // directory name in source archive for this item
protected String dirname; //convenience
protected HandleService handleService;
protected ItemService itemService;
//constructors
protected ItemArchive() {
handleService = HandleServiceFactory.getInstance().getHandleService();
itemService = ContentServiceFactory.getInstance().getItemService();
}
/**
* factory method
*
* Minimal requirements for dublin_core.xml for this application
* is the presence of dc.identifier.uri
* which must contain the handle for the item
*
* @param context - The DSpace context
* @param dir - The directory File in the source archive
* @param itemField - The metadata field in which the Item identifier is located
* if null, the default is the handle in the dc.identifier.uri field
* @return ItemArchive object
* @throws Exception if error
*/
public static ItemArchive create(Context context, File dir, String itemField)
throws Exception {
ItemArchive itarch = new ItemArchive();
itarch.dir = dir;
itarch.dirname = dir.getName();
public static final String DUBLIN_CORE_XML = "dublin_core.xml";
private static DocumentBuilder builder = null;
private static Transformer transformer = null;
private List<DtoMetadata> dtomList = null;
private List<DtoMetadata> undoDtomList = new ArrayList<DtoMetadata>();
private List<Integer> undoAddContents = new ArrayList<Integer>(); // for undo of add
private Item item;
private File dir; // directory name in source archive for this item
private String dirname; //convenience
//constructors
private ItemArchive()
{
// nothing
}
/** factory method
*
* Minimal requirements for dublin_core.xml for this application
* is the presence of dc.identifier.uri
* which must contain the handle for the item
*
* @param context - The DSpace context
* @param dir - The directory File in the source archive
* @param itemField - The metadata field in which the Item identifier is located
* if null, the default is the handle in the dc.identifier.uri field
*
*/
public static ItemArchive create(Context context, File dir, String itemField)
throws Exception
{
ItemArchive itarch = new ItemArchive();
itarch.dir = dir;
itarch.dirname = dir.getName();
InputStream is = null;
try {
try
{
is = new FileInputStream(new File(dir, DUBLIN_CORE_XML));
itarch.dtomList = MetadataUtilities.loadDublinCore(getDocumentBuilder(), is);
//The code to search for local schema files was copied from org.dspace.app.itemimport
// .ItemImportServiceImpl.java
File file[] = dir.listFiles(new LocalSchemaFilenameFilter());
for (int i = 0; i < file.length; i++) {
is = new FileInputStream(file[i]);
itarch.dtomList.addAll(MetadataUtilities.loadDublinCore(getDocumentBuilder(), is));
}
} finally {
if (is != null) {
}
finally
{
if (is != null)
{
is.close();
}
}
ItemUpdate.pr("Loaded metadata with " + itarch.dtomList.size() + " fields");
ItemUpdate.pr("Loaded metadata with " + itarch.dtomList.size() + " fields");
if (itemField == null)
{
itarch.item = itarch.itemFromHandleInput(context); // sets the item instance var and seeds the undo list
}
else
{
itarch.item = itarch.itemFromMetadataField(context, itemField);
}
if (itarch.item == null)
{
throw new Exception("Item not instantiated: " + itarch.dirname);
}
ItemUpdate.prv("item instantiated: " + itarch.item.getHandle());
if (itemField == null) {
itarch.item = itarch.itemFromHandleInput(context); // sets the item instance var and seeds the undo list
} else {
itarch.item = itarch.itemFromMetadataField(context, itemField);
}
if (itarch.item == null) {
throw new Exception("Item not instantiated: " + itarch.dirname);
}
ItemUpdate.prv("item instantiated: " + itarch.item.getHandle());
return itarch;
}
protected static DocumentBuilder getDocumentBuilder()
throws ParserConfigurationException {
if (builder == null) {
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
}
return builder;
}
return itarch;
}
private static DocumentBuilder getDocumentBuilder()
throws ParserConfigurationException
{
if (builder == null)
{
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
}
return builder;
}
private static Transformer getTransformer()
throws TransformerConfigurationException
{
if (transformer == null)
{
transformer = TransformerFactory.newInstance().newTransformer();
}
return transformer;
}
/**
* Getter for the DSpace item referenced in the archive
* @return DSpace item
*/
public Item getItem()
{
return item;
}
/**
* Getter for directory in archive on disk
* @return directory in archive
*/
public File getDirectory()
{
return dir;
}
/**
* Getter for directory name in archive
* @return directory name in archive
*/
public String getDirectoryName()
{
return dirname;
}
/**
* Add metadata field to undo list
* @param dtom
*/
public void addUndoMetadataField(DtoMetadata dtom)
{
this.undoDtomList.add(dtom);
}
/**
* Getter for list of metadata fields
* @return list of metadata fields
*/
public List<DtoMetadata> getMetadataFields()
{
return dtomList;
}
/**
* Add bitstream id to delete contents file
* @param bitstreamId
*/
public void addUndoDeleteContents(int bitstreamId)
{
this.undoAddContents.add(bitstreamId);
}
/**
* Getter for Transformer
*
* @return Transformer
* @throws TransformerConfigurationException if config error
*/
protected Transformer getTransformer()
throws TransformerConfigurationException {
if (transformer == null) {
transformer = TransformerFactory.newInstance().newTransformer();
}
return transformer;
}
/**
* Getter for the DSpace item referenced in the archive
*
* @return DSpace item
*/
public Item getItem() {
return item;
}
/**
* Getter for directory in archive on disk
*
* @return directory in archive
*/
public File getDirectory() {
return dir;
}
/**
* Getter for directory name in archive
*
* @return directory name in archive
*/
public String getDirectoryName() {
return dirname;
}
/**
* Add metadata field to undo list
*
* @param dtom DtoMetadata (represents metadata field)
*/
public void addUndoMetadataField(DtoMetadata dtom) {
this.undoDtomList.add(dtom);
}
/**
* Getter for list of metadata fields
*
* @return list of metadata fields
*/
public List<DtoMetadata> getMetadataFields() {
return dtomList;
}
/**
* Add bitstream id to delete contents file
*
* @param bitstreamId bitstream ID
*/
public void addUndoDeleteContents(UUID bitstreamId) {
this.undoAddContents.add(bitstreamId);
}
/**
* Obtain item from DSpace based on handle
* This is the default implementation
* that uses the dc.identifier.uri metadatafield
* that contains the item handle as its value
*
* @param context DSpace Context
* @throws SQLException if database error
* @throws Exception if error
* Obtain item from DSpace based on handle
* This is the default implementation
* that uses the dc.identifier.uri metadatafield
* that contains the item handle as its value
*
*/
private Item itemFromHandleInput(Context context)
throws SQLException, Exception {
DtoMetadata dtom = getMetadataField("dc.identifier.uri");
if (dtom == null) {
throw new Exception("No dc.identier.uri field found for handle");
}
this.addUndoMetadataField(dtom); //seed the undo list with the uri
String uri = dtom.value;
if (!uri.startsWith(ItemUpdate.HANDLE_PREFIX)) {
throw new Exception("dc.identifier.uri for item " + uri
+ " does not begin with prefix: " + ItemUpdate.HANDLE_PREFIX);
}
String handle = uri.substring(ItemUpdate.HANDLE_PREFIX.length());
DSpaceObject dso = handleService.resolveToObject(context, handle);
if (dso instanceof Item) {
item = (Item) dso;
} else {
ItemUpdate.pr("Warning: item not instantiated");
throw new IllegalArgumentException("Item " + handle + " not instantiated.");
}
return item;
throws SQLException, Exception
{
DtoMetadata dtom = getMetadataField("dc.identifier.uri");
if (dtom == null)
{
throw new Exception("No dc.identier.uri field found for handle");
}
this.addUndoMetadataField(dtom); //seed the undo list with the uri
String uri = dtom.value;
if (!uri.startsWith(ItemUpdate.HANDLE_PREFIX))
{
throw new Exception("dc.identifier.uri for item " + uri
+ " does not begin with prefix: " + ItemUpdate.HANDLE_PREFIX);
}
String handle = uri.substring(ItemUpdate.HANDLE_PREFIX.length());
DSpaceObject dso = HandleManager.resolveToObject(context, handle);
if (dso instanceof Item)
{
item = (Item) dso;
}
else
{
ItemUpdate.pr("Warning: item not instantiated");
throw new IllegalArgumentException("Item " + handle + " not instantiated.");
}
return item;
}
/**
* Find and instantiate Item from the dublin_core.xml based
* on the specified itemField for the item identifier,
*
* Find and instantiate Item from the dublin_core.xml based
* on the specified itemField for the item identifier,
*
*
* @param context - the DSpace context
* @param itemField - the compound form of the metadata element <schema>.<element>.<qualifier>
* @throws SQLException if database error
* @throws Exception if error
* @throws SQLException
* @throws Exception
*/
private Item itemFromMetadataField(Context context, String itemField)
throws SQLException, AuthorizeException, Exception {
DtoMetadata dtom = getMetadataField(itemField);
throws SQLException, AuthorizeException, Exception
{
DtoMetadata dtom = getMetadataField(itemField);
Item item = null;
if (dtom == null)
{
throw new IllegalArgumentException("No field found for item identifier field: " + itemField);
}
ItemUpdate.prv("Metadata field to match for item: " + dtom.toString());
Item item = null;
if (dtom == null) {
throw new IllegalArgumentException("No field found for item identifier field: " + itemField);
}
ItemUpdate.prv("Metadata field to match for item: " + dtom.toString());
this.addUndoMetadataField(dtom); //seed the undo list with the identifier field
Iterator<Item> itr = itemService
.findByMetadataField(context, dtom.schema, dtom.element, dtom.qualifier, dtom.value);
int count = 0;
while (itr.hasNext()) {
item = itr.next();
count++;
}
ItemUpdate.prv("items matching = " + count);
if (count != 1) {
throw new Exception("" + count + " items matching item identifier: " + dtom.value);
}
return item;
}
/**
* Get DtoMetadata field
*
* @param compoundForm compound form
* @return DtoMetadata field
*/
private DtoMetadata getMetadataField(String compoundForm) {
for (DtoMetadata dtom : dtomList) {
if (dtom.matches(compoundForm, false)) {
return dtom;
}
}
return null;
}
this.addUndoMetadataField(dtom); //seed the undo list with the identifier field
ItemIterator itr = Item.findByMetadataField(context, dtom.schema, dtom.element, dtom.qualifier, dtom.value);
int count = 0;
while (itr.hasNext())
{
item = itr.next();
count++;
}
itr.close();
ItemUpdate.prv("items matching = " + count );
if (count != 1)
{
throw new Exception ("" + count + " items matching item identifier: " + dtom.value);
}
return item;
}
private DtoMetadata getMetadataField(String compoundForm)
{
for (DtoMetadata dtom : dtomList)
{
if (dtom.matches(compoundForm, false))
{
return dtom;
}
}
return null;
}
/**
* write undo directory and files to Disk in archive format
*
*
*
* @param undoDir - the root directory of the undo archive
* @throws IOException if IO error
* @throws ParserConfigurationException if config error
* @throws TransformerConfigurationException if transformer config error
* @throws TransformerException if transformer error
* @throws FileNotFoundException if file not found
*/
public void writeUndo(File undoDir)
throws IOException, ParserConfigurationException, TransformerConfigurationException,
TransformerException, FileNotFoundException {
// create directory for item
File dir = new File(undoDir, dirname);
if (!dir.exists() && !dir.mkdir()) {
public void writeUndo(File undoDir)
throws IOException, ParserConfigurationException, TransformerConfigurationException,
TransformerException, FileNotFoundException
{
// create directory for item
File dir = new File(undoDir, dirname);
if (!dir.exists() && !dir.mkdir())
{
log.error("Unable to create undo directory");
}
OutputStream out = null;
OutputStream out = null;
try {
try
{
out = new FileOutputStream(new File(dir, "dublin_core.xml"));
Document doc = MetadataUtilities.writeDublinCore(getDocumentBuilder(), undoDtomList);
MetadataUtilities.writeDocument(doc, getTransformer(), out);
// if undo has delete bitstream
if (undoAddContents.size() > 0) {
if (undoAddContents.size() > 0)
{
PrintWriter pw = null;
try {
try
{
File f = new File(dir, ItemUpdate.DELETE_CONTENTS_FILE);
pw = new PrintWriter(new BufferedWriter(new FileWriter(f)));
for (UUID i : undoAddContents) {
for (Integer i : undoAddContents)
{
pw.println(i);
}
} finally {
}
finally
{
pw.close();
}
}
} finally {
if (out != null) {
}
finally
{
if (out != null)
{
out.close();
}
}
}
}
} //end class

View File

@@ -11,13 +11,14 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
@@ -30,15 +31,7 @@ import javax.xml.transform.stream.StreamResult;
import org.apache.commons.lang.StringUtils;
import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
@@ -46,420 +39,491 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Metadatum;
import org.dspace.content.Item;
import org.dspace.content.MetadataSchema;
import org.dspace.core.ConfigurationManager;
/**
* Miscellaneous methods for metadata handling that build on the API
* which might have general utility outside of the specific use
* in context in ItemUpdate.
* Miscellaneous methods for metadata handling that build on the API
* which might have general utility outside of the specific use
* in context in ItemUpdate.
*
* The XML methods were based on those in ItemImport
*
*
* The XML methods were based on those in ItemImport
*/
public class MetadataUtilities {
protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
/**
* Default constructor
*/
private MetadataUtilities() { }
/**
* Working around Item API to delete a value-specific Metadatum
* For a given element/qualifier/lang:
* get all DCValues
* clear (i.e. delete) all of these DCValues
* add them back, minus the one to actually delete
*
* @param context DSpace Context
* @param item Item Object
* @param dtom metadata field
* @param isLanguageStrict whether strict or not
/**
*
* Working around Item API to delete a value-specific Metadatum
For a given element/qualifier/lang:
get all DCValues
clear (i.e. delete) all of these DCValues
* add them back, minus the one to actually delete
*
*
* @param item
* @param dtom
* @param isLanguageStrict -
*
* @return true if metadata field is found with matching value and was deleted
* @throws SQLException if database error
*/
public static boolean deleteMetadataByValue(Context context, Item item, DtoMetadata dtom, boolean isLanguageStrict)
throws SQLException {
List<MetadataValue> ar = null;
if (isLanguageStrict) { // get all for given type
ar = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, dtom.language);
} else {
ar = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
}
boolean found = false;
//build new set minus the one to delete
List<String> vals = new ArrayList<String>();
for (MetadataValue dcv : ar) {
if (dcv.getValue().equals(dtom.value)) {
found = true;
} else {
vals.add(dcv.getValue());
}
}
if (found) { //remove all for given type ??synchronize this block??
if (isLanguageStrict) {
itemService.clearMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language);
} else {
itemService.clearMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
}
itemService.addMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language, vals);
}
return found;
public static boolean deleteMetadataByValue(Item item, DtoMetadata dtom, boolean isLanguageStrict)
{
Metadatum[] ar = null;
if (isLanguageStrict)
{ // get all for given type
ar = item.getMetadata(dtom.schema, dtom.element, dtom.qualifier, dtom.language);
}
else
{
ar = item.getMetadata(dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
}
boolean found = false;
//build new set minus the one to delete
List<String> vals = new ArrayList<String>();
for (Metadatum dcv : ar)
{
if (dcv.value.equals(dtom.value))
{
found = true;
}
else
{
vals.add(dcv.value);
}
}
if (found) //remove all for given type ??synchronize this block??
{
if (isLanguageStrict)
{
item.clearMetadata(dtom.schema, dtom.element, dtom.qualifier, dtom.language);
}
else
{
item.clearMetadata(dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
}
item.addMetadata(dtom.schema, dtom.element, dtom.qualifier, dtom.language, vals.toArray(new String[vals.size()]));
}
return found;
}
/**
* Append text to value metadata field to item
*
* @param context DSpace Context
* @param item DSpace Item
* @param dtom metadata field
* @param isLanguageStrict if strict
* @param textToAppend text to append
* @throws IllegalArgumentException - When target metadata field is not found
* @throws SQLException if database error
* Append text to value metadata field to item
*
* @param item
* @param dtom
* @param isLanguageStrict
* @param textToAppend
* @throws IllegalArgumentException - When target metadata field is not found
*/
public static void appendMetadata(Context context, Item item, DtoMetadata dtom, boolean isLanguageStrict,
String textToAppend)
throws IllegalArgumentException, SQLException {
List<MetadataValue> ar = null;
public static void appendMetadata(Item item, DtoMetadata dtom, boolean isLanguageStrict,
String textToAppend)
throws IllegalArgumentException
{
Metadatum[] ar = null;
// get all values for given element/qualifier
if (isLanguageStrict) // get all for given element/qualifier
{
ar = item.getMetadata(dtom.schema, dtom.element, dtom.qualifier, dtom.language);
}
else
{
ar = item.getMetadata(dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
}
if (ar.length == 0)
{
throw new IllegalArgumentException("Metadata to append to not found");
}
int idx = 0; //index of field to change
if (ar.length > 1) //need to pick one, can't be sure it's the last one
{
// TODO maybe get highest id ?
}
//build new set minus the one to delete
List<String> vals = new ArrayList<String>();
for (int i=0; i < ar.length; i++)
{
if (i == idx)
{
vals.add(ar[i].value + textToAppend);
}
else
{
vals.add(ar[i].value);
}
}
// get all values for given element/qualifier
if (isLanguageStrict) { // get all for given element/qualifier
ar = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, dtom.language);
} else {
ar = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
}
if (ar.size() == 0) {
throw new IllegalArgumentException("Metadata to append to not found");
}
int idx = 0; //index of field to change
if (ar.size() > 1) { //need to pick one, can't be sure it's the last one
// TODO maybe get highest id ?
}
//build new set minus the one to delete
List<String> vals = new ArrayList<String>();
for (int i = 0; i < ar.size(); i++) {
if (i == idx) {
vals.add(ar.get(i).getValue() + textToAppend);
} else {
vals.add(ar.get(i).getValue());
}
}
if (isLanguageStrict) {
itemService.clearMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language);
} else {
itemService.clearMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
}
itemService.addMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language, vals);
if (isLanguageStrict)
{
item.clearMetadata(dtom.schema, dtom.element, dtom.qualifier, dtom.language);
}
else
{
item.clearMetadata(dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
}
item.addMetadata(dtom.schema, dtom.element, dtom.qualifier, dtom.language, vals.toArray(new String[vals.size()]));
}
/**
* Modification of method from ItemImporter.loadDublinCore
* as a Factory method
*
* @param docBuilder DocumentBuilder
* @param is - InputStream of dublin_core.xml
* Modification of method from ItemImporter.loadDublinCore
* as a Factory method
*
* @param docBuilder -
* @param is - InputStream of dublin_core.xml
* @return list of DtoMetadata representing the metadata fields relating to an Item
* @throws SQLException if database error
* @throws IOException if IO error
* @throws ParserConfigurationException if parser config error
* @throws SAXException if XML error
* @throws TransformerException if transformer error
* @throws AuthorizeException if authorization error
* @throws SQLException
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
* @throws TransformerException
* @throws AuthorizeException
*/
public static List<DtoMetadata> loadDublinCore(DocumentBuilder docBuilder, InputStream is)
throws SQLException, IOException, ParserConfigurationException,
SAXException, TransformerException, AuthorizeException {
Document document = docBuilder.parse(is);
throws SQLException, IOException, ParserConfigurationException,
SAXException, TransformerException, AuthorizeException
{
Document document = docBuilder.parse(is);
List<DtoMetadata> dtomList = new ArrayList<DtoMetadata>();
// Get the schema, for backward compatibility we will default to the
// dublin core schema if the schema name is not available in the import file
String schema = null;
NodeList metadata = XPathAPI.selectNodeList(document, "/dublin_core");
Node schemaAttr = metadata.item(0).getAttributes().getNamedItem("schema");
if (schemaAttr == null)
{
schema = MetadataSchema.DC_SCHEMA;
}
else
{
schema = schemaAttr.getNodeValue();
}
List<DtoMetadata> dtomList = new ArrayList<DtoMetadata>();
// Get the nodes corresponding to formats
NodeList dcNodes = XPathAPI.selectNodeList(document, "/dublin_core/dcvalue");
for (int i = 0; i < dcNodes.getLength(); i++)
{
Node n = dcNodes.item(i);
String value = getStringValue(n).trim();
// compensate for empty value getting read as "null", which won't display
if (value == null)
{
value = "";
}
String element = getAttributeValue(n, "element");
if (element != null)
{
element = element.trim();
}
String qualifier = getAttributeValue(n, "qualifier");
if (qualifier != null)
{
qualifier = qualifier.trim();
}
String language = getAttributeValue(n, "language");
if (language != null)
{
language = language.trim();
}
// Get the schema, for backward compatibility we will default to the
// dublin core schema if the schema name is not available in the import file
String schema = null;
NodeList metadata = XPathAPI.selectNodeList(document, "/dublin_core");
Node schemaAttr = metadata.item(0).getAttributes().getNamedItem("schema");
if (schemaAttr == null) {
schema = MetadataSchema.DC_SCHEMA;
} else {
schema = schemaAttr.getNodeValue();
}
// Get the nodes corresponding to formats
NodeList dcNodes = XPathAPI.selectNodeList(document, "/dublin_core/dcvalue");
for (int i = 0; i < dcNodes.getLength(); i++) {
Node n = dcNodes.item(i);
String value = getStringValue(n).trim();
// compensate for empty value getting read as "null", which won't display
if (value == null) {
value = "";
}
String element = getAttributeValue(n, "element");
if (element != null) {
element = element.trim();
}
String qualifier = getAttributeValue(n, "qualifier");
if (qualifier != null) {
qualifier = qualifier.trim();
}
String language = getAttributeValue(n, "language");
if (language != null) {
language = language.trim();
}
if ("none".equals(qualifier) || "".equals(qualifier)) {
qualifier = null;
}
// a goofy default, but consistent with DSpace treatment elsewhere
if (language == null) {
language = "en";
} else if ("".equals(language)) {
language = ConfigurationManager.getProperty("default.language");
}
DtoMetadata dtom = DtoMetadata.create(schema, element, qualifier, language, value);
ItemUpdate.pr(dtom.toString());
dtomList.add(dtom);
}
return dtomList;
}
if ("none".equals(qualifier) || "".equals(qualifier))
{
qualifier = null;
}
// a goofy default, but consistent with DSpace treatment elsewhere
if (language == null)
{
language = "en";
}
else if ("".equals(language))
{
language = ConfigurationManager.getProperty("default.language");
}
DtoMetadata dtom = DtoMetadata.create(schema, element, qualifier, language, value);
ItemUpdate.pr(dtom.toString());
dtomList.add(dtom);
}
return dtomList;
}
/**
* Write dublin_core.xml
*
* @param docBuilder DocumentBuilder
* @param dtomList List of metadata fields
* Write dublin_core.xml
*
* @param docBuilder
* @param dtomList
* @return xml document
* @throws ParserConfigurationException if parser config error
* @throws TransformerConfigurationException if transformer config error
* @throws TransformerException if transformer error
* @throws ParserConfigurationException
* @throws TransformerConfigurationException
* @throws TransformerException
*/
public static Document writeDublinCore(DocumentBuilder docBuilder, List<DtoMetadata> dtomList)
throws ParserConfigurationException, TransformerConfigurationException, TransformerException {
public static Document writeDublinCore(DocumentBuilder docBuilder, List<DtoMetadata> dtomList)
throws ParserConfigurationException, TransformerConfigurationException, TransformerException
{
Document doc = docBuilder.newDocument();
Element root = doc.createElement("dublin_core");
doc.appendChild(root);
for (DtoMetadata dtom : dtomList) {
Element mel = doc.createElement("dcvalue");
mel.setAttribute("element", dtom.element);
if (dtom.qualifier == null) {
mel.setAttribute("qualifier", "none");
} else {
mel.setAttribute("qualifier", dtom.qualifier);
}
if (StringUtils.isEmpty(dtom.language)) {
mel.setAttribute("language", "en");
} else {
mel.setAttribute("language", dtom.language);
}
mel.setTextContent(dtom.value);
root.appendChild(mel);
for (DtoMetadata dtom : dtomList)
{
Element mel = doc.createElement("dcvalue");
mel.setAttribute("element", dtom.element);
if (dtom.qualifier == null)
{
mel.setAttribute("qualifier", "none");
}
else
{
mel.setAttribute("qualifier", dtom.qualifier);
}
if (StringUtils.isEmpty(dtom.language))
{
mel.setAttribute("language", "en");
}
else
{
mel.setAttribute("language", dtom.language);
}
mel.setTextContent(dtom.value);
root.appendChild(mel);
}
return doc;
}
return doc;
}
/**
* write xml document to output stream
*
* @param doc XML Document
* @param transformer XML Transformer
* @param out OutputStream
* @throws IOException if IO Error
* @throws TransformerException if Transformer error
* write xml document to output stream
* @param doc
* @param transformer
* @param out
* @throws IOException
* @throws TransformerException
*/
public static void writeDocument(Document doc, Transformer transformer, OutputStream out)
throws IOException, TransformerException {
Source src = new DOMSource(doc);
Result dest = new StreamResult(out);
transformer.transform(src, dest);
}
public static void writeDocument(Document doc, Transformer transformer, OutputStream out)
throws IOException, TransformerException
{
Source src = new DOMSource(doc);
Result dest = new StreamResult(out);
transformer.transform(src, dest);
}
// XML utility methods
/**
* Lookup an attribute from a DOM node.
*
* @param n Node
* @param name name
* @return attribute value
* @param n
* @param name
* @return
*/
private static String getAttributeValue(Node n, String name) {
private static String getAttributeValue(Node n, String name)
{
NamedNodeMap nm = n.getAttributes();
for (int i = 0; i < nm.getLength(); i++) {
for (int i = 0; i < nm.getLength(); i++)
{
Node node = nm.item(i);
if (name.equals(node.getNodeName())) {
if (name.equals(node.getNodeName()))
{
return node.getNodeValue();
}
}
return "";
}
/**
* Return the String value of a Node.
*
* @param node node
* @return string value
* @param node
* @return
*/
private static String getStringValue(Node node) {
private static String getStringValue(Node node)
{
String value = node.getNodeValue();
if (node.hasChildNodes()) {
if (node.hasChildNodes())
{
Node first = node.getFirstChild();
if (first.getNodeType() == Node.TEXT_NODE) {
if (first.getNodeType() == Node.TEXT_NODE)
{
return first.getNodeValue();
}
}
return value;
}
/**
* Rewrite of ItemImport's functionality
* but just the parsing of the file, not the processing of its elements.
*
* @param f file
* @return list of ContentsEntry
* @throws FileNotFoundException if file doesn't exist
* @throws IOException if IO error
* @throws ParseException if parse error
*
* @validate flag to verify matching files in tree
*/
public static List<ContentsEntry> readContentsFile(File f)
throws FileNotFoundException, IOException, ParseException {
List<ContentsEntry> list = new ArrayList<ContentsEntry>();
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(f));
String line = null;
while ((line = in.readLine()) != null) {
line = line.trim();
if ("".equals(line)) {
continue;
}
ItemUpdate.pr("Contents entry: " + line);
list.add(ContentsEntry.parse(line));
}
} finally {
try {
in.close();
} catch (IOException e) {
//skip
}
}
return list;
throws FileNotFoundException, IOException, ParseException
{
List<ContentsEntry> list = new ArrayList<ContentsEntry>();
BufferedReader in = null;
try
{
in = new BufferedReader(new FileReader(f));
String line = null;
while ((line = in.readLine()) != null)
{
line = line.trim();
if ("".equals(line))
{
continue;
}
ItemUpdate.pr("Contents entry: " + line);
list.add(ContentsEntry.parse(line));
}
}
finally
{
try
{
in.close();
}
catch(IOException e)
{
//skip
}
}
return list;
}
/**
* @param f file
* @return list of lines as strings
* @throws FileNotFoundException if file doesn't exist
* @throws IOException if IO Error
*
* @param f
* @throws FileNotFoundException
* @throws IOException
*/
public static List<String> readDeleteContentsFile(File f)
throws FileNotFoundException, IOException {
List<String> list = new ArrayList<>();
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(f));
String line = null;
while ((line = in.readLine()) != null) {
line = line.trim();
if ("".equals(line)) {
continue;
}
list.add(line);
}
} finally {
try {
in.close();
} catch (IOException e) {
//skip
}
}
return list;
public static List<Integer> readDeleteContentsFile(File f)
throws FileNotFoundException, IOException
{
List<Integer> list = new ArrayList<Integer>();
BufferedReader in = null;
try
{
in = new BufferedReader(new FileReader(f));
String line = null;
while ((line = in.readLine()) != null)
{
line = line.trim();
if ("".equals(line))
{
continue;
}
int n = 0;
try
{
n = Integer.parseInt(line);
list.add(n);
}
catch(NumberFormatException e)
{
ItemUpdate.pr("Error reading delete contents line:" + e.toString());
}
}
}
finally
{
try
{
in.close();
}
catch(IOException e)
{
//skip
}
}
return list;
}
/**
* Get display of Metadatum
*
* @param dcv MetadataValue
* Get display of Metadatum
*
* @param dcv
* @return string displaying elements of the Metadatum
*/
public static String getDCValueString(MetadataValue dcv) {
MetadataField metadataField = dcv.getMetadataField();
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
return "schema: " + metadataSchema.getName() + "; element: " + metadataField
.getElement() + "; qualifier: " + metadataField.getQualifier() +
"; language: " + dcv.getLanguage() + "; value: " + dcv.getValue();
public static String getDCValueString(Metadatum dcv)
{
return "schema: " + dcv.schema + "; element: " + dcv.element + "; qualifier: " + dcv.qualifier +
"; language: " + dcv.language + "; value: " + dcv.value;
}
/**
* Return compound form of a metadata field (i.e. schema.element.qualifier)
*
* @param schema schema
* @param element element
* @param qualifier qualifier
* @return a String representation of the two- or three-part form of a metadata element
* e.g. dc.identifier.uri
*/
public static String getCompoundForm(String schema, String element, String qualifier) {
StringBuilder sb = new StringBuilder();
sb.append(schema).append(".").append(element);
if (qualifier != null) {
sb.append(".").append(qualifier);
}
return sb.toString();
}
/**
* Parses metadata field given in the form {@code <schema>.<element>[.<qualifier>|.*]}
* checks for correct number of elements (2 or 3) and for empty strings
*
* @param compoundForm compound form of metadata field
* @return String Array
* @throws ParseException if validity checks fail
*/
public static String[] parseCompoundForm(String compoundForm)
throws ParseException {
String[] ar = compoundForm.split("\\s*\\.\\s*"); //trim ends
if ("".equals(ar[0])) {
throw new ParseException("schema is empty string: " + compoundForm, 0);
}
if ((ar.length < 2) || (ar.length > 3) || "".equals(ar[1])) {
throw new ParseException("element is malformed or empty string: " + compoundForm, 0);
}
return ar;
}
}
/**
*
* @return a String representation of the two- or three-part form of a metadata element
* e.g. dc.identifier.uri
*/
public static String getCompoundForm(String schema, String element, String qualifier)
{
StringBuilder sb = new StringBuilder();
sb.append(schema).append(".").append(element);
if (qualifier != null)
{
sb.append(".").append(qualifier);
}
return sb.toString();
}
/**
* Parses metadata field given in the form <schema>.<element>[.<qualifier>|.*]
* checks for correct number of elements (2 or 3) and for empty strings
*
* @return String Array
* @throws ParseException if validity checks fail
*
*/
public static String[] parseCompoundForm(String compoundForm)
throws ParseException
{
String[] ar = compoundForm.split("\\s*\\.\\s*"); //trim ends
if ("".equals(ar[0]))
{
throw new ParseException("schema is empty string: " + compoundForm, 0);
}
if ((ar.length < 2) || (ar.length > 3) || "".equals(ar[1]))
{
throw new ParseException("element is malformed or empty string: " + compoundForm, 0);
}
return ar;
}
}

View File

@@ -8,42 +8,48 @@
package org.dspace.app.itemupdate;
import java.sql.SQLException;
import java.util.List;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
/**
* Filter all bitstreams in the ORIGINAL bundle
* Also delete all derivative bitstreams, i.e.
* all bitstreams in the TEXT and THUMBNAIL bundles
/**
* Filter all bitstreams in the ORIGINAL bundle
* Also delete all derivative bitstreams, i.e.
* all bitstreams in the TEXT and THUMBNAIL bundles
*/
public class OriginalBitstreamFilter extends BitstreamFilterByBundleName {
public OriginalBitstreamFilter() {
//empty
}
/**
* Tests bitstreams for containment in an ORIGINAL bundle
*
* @param bitstream Bitstream
* @return true if the bitstream is in the ORIGINAL bundle
* @throws BitstreamFilterException if filter error
*/
@Override
public boolean accept(Bitstream bitstream)
throws BitstreamFilterException {
try {
List<Bundle> bundles = bitstream.getBundles();
for (Bundle bundle : bundles) {
if (bundle.getName().equals("ORIGINAL")) {
return true;
}
}
} catch (SQLException e) {
throw new BitstreamFilterException(e);
}
return false;
}
public class OriginalBitstreamFilter extends BitstreamFilterByBundleName
{
public OriginalBitstreamFilter()
{
//empty
}
/**
* Tests bitstreams for containment in an ORIGINAL bundle
*
* @return true if the bitstream is in the ORIGINAL bundle
*
* @throws BitstreamFilterException
*/
public boolean accept(Bitstream bitstream)
throws BitstreamFilterException
{
try
{
Bundle[] bundles = bitstream.getBundles();
for (Bundle b : bundles)
{
if (b.getName().equals("ORIGINAL"))
{
return true;
}
}
}
catch(SQLException e)
{
throw new BitstreamFilterException(e);
}
return false;
}
}

View File

@@ -8,46 +8,52 @@
package org.dspace.app.itemupdate;
import java.sql.SQLException;
import java.util.List;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
/**
* Filter all bitstreams in the ORIGINAL bundle
* Also delete all derivative bitstreams, i.e.
* all bitstreams in the TEXT and THUMBNAIL bundles
/**
* Filter all bitstreams in the ORIGINAL bundle
* Also delete all derivative bitstreams, i.e.
* all bitstreams in the TEXT and THUMBNAIL bundles
*/
public class OriginalWithDerivativesBitstreamFilter extends BitstreamFilter {
protected String[] bundlesToEmpty = {"ORIGINAL", "TEXT", "THUMBNAIL"};
public OriginalWithDerivativesBitstreamFilter() {
//empty
}
/**
* Tests bitstream for membership in specified bundles (ORIGINAL, TEXT, THUMBNAIL)
*
* @param bitstream Bitstream
* @return true if bitstream is in specified bundles
* @throws BitstreamFilterException if error
*/
@Override
public boolean accept(Bitstream bitstream)
throws BitstreamFilterException {
try {
List<Bundle> bundles = bitstream.getBundles();
for (Bundle b : bundles) {
for (String bn : bundlesToEmpty) {
if (b.getName().equals(bn)) {
return true;
}
}
}
} catch (SQLException e) {
throw new BitstreamFilterException(e);
}
return false;
}
public class OriginalWithDerivativesBitstreamFilter extends BitstreamFilter
{
private String[] bundlesToEmpty = { "ORIGINAL", "TEXT", "THUMBNAIL" };
public OriginalWithDerivativesBitstreamFilter()
{
//empty
}
/**
* Tests bitstream for membership in specified bundles (ORIGINAL, TEXT, THUMBNAIL)
*
* @param bitstream
* @throws BitstreamFilterException
* @return true if bitstream is in specified bundles
*/
public boolean accept(Bitstream bitstream)
throws BitstreamFilterException
{
try
{
Bundle[] bundles = bitstream.getBundles();
for (Bundle b : bundles)
{
for (String bn : bundlesToEmpty)
{
if (b.getName().equals(bn))
{
return true;
}
}
}
}
catch(SQLException e)
{
throw new BitstreamFilterException(e);
}
return false;
}
}

View File

@@ -10,13 +10,15 @@ package org.dspace.app.itemupdate;
import java.util.Properties;
/**
* Bitstream filter targetting the THUMBNAIL bundle
* Bitstream filter targetting the THUMBNAIL bundle
*
*/
public class ThumbnailBitstreamFilter extends BitstreamFilterByBundleName {
public ThumbnailBitstreamFilter() {
props = new Properties();
props.setProperty("bundle", "THUMBNAIL");
}
public ThumbnailBitstreamFilter()
{
props = new Properties();
props.setProperty("bundle", "THUMBNAIL");
}
}

View File

@@ -7,27 +7,24 @@
*/
package org.dspace.app.itemupdate;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
/**
* Interface for actions to update an item
* Interface for actions to update an item
*
*/
public interface UpdateAction {
public ItemService itemService = ContentServiceFactory.getInstance().getItemService();
/**
* Action to update item
*
* @param context DSpace context
* @param itarch item archive
* @param isTest test flag
* @param suppressUndo undo flag
* @throws Exception if error
*/
public void execute(Context context, ItemArchive itarch, boolean isTest, boolean suppressUndo)
throws Exception;
public interface UpdateAction
{
/**
* Action to update item
*
* @param context
* @param itarch
* @param isTest
* @param suppressUndo
* @throws Exception
*/
public void execute(Context context, ItemArchive itarch, boolean isTest, boolean suppressUndo)
throws Exception;
}

View File

@@ -7,37 +7,33 @@
*/
package org.dspace.app.itemupdate;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.BundleService;
/**
* Base class for Bitstream actions
* Base class for Bitstream actions
*
*
*/
public abstract class UpdateBitstreamsAction implements UpdateAction {
protected boolean alterProvenance = true;
protected boolean alterProvenance = true;
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
/**
* Set variable to indicate that the dc.description.provenance field may
* be changed as a result of Bitstream changes by ItemUpdate
*
* @param alterProvenance whether to alter provenance
*/
public void setAlterProvenance(boolean alterProvenance) {
this.alterProvenance = alterProvenance;
}
/**
* @return boolean value to indicate whether the dc.description.provenance field may
* be changed as a result of Bitstream changes by ItemUpdate
*/
public boolean getAlterProvenance() {
return alterProvenance;
}
/**
* Set variable to indicate that the dc.description.provenance field may
* be changed as a result of Bitstream changes by ItemUpdate
* @param alterProvenance
*/
public void setAlterProvenance(boolean alterProvenance)
{
this.alterProvenance = alterProvenance;
}
/**
*
* @return boolean value to indicate whether the dc.description.provenance field may
* be changed as a result of Bitstream changes by ItemUpdate
*/
public boolean getAlterProvenance()
{
return alterProvenance;
}
}

View File

@@ -11,57 +11,60 @@ import java.util.HashSet;
import java.util.Set;
/**
* This abstract subclass for metadata actions
* maintains a collection for the target metadata fields
* expressed as a string in the compound notation ( {@code <schema>.<element>.<qualifier>} )
* on which to apply the action when the method execute is called.
* This abstract subclass for metadata actions
* maintains a collection for the target metadata fields
* expressed as a string in the compound notation ( <schema>.<element>.<qualifier> )
* on which to apply the action when the method execute is called.
*
* Implemented as a Set to avoid problems with duplicates
*
*
* Implemented as a Set to avoid problems with duplicates
*/
public abstract class UpdateMetadataAction implements UpdateAction {
protected Set<String> targetFields = new HashSet<String>();
protected Set<String> targetFields = new HashSet<String>();
/**
* Get target fields
*
* Get target fields
*
* @return set of fields to update
*/
public Set<String> getTargetFields() {
return targetFields;
}
public Set<String> getTargetFields() {
return targetFields;
}
/**
* Set target fields
*
* @param targetFields Set of target fields to update
*/
public void addTargetFields(Set<String> targetFields) {
for (String tf : targetFields) {
this.targetFields.add(tf);
}
/**
* Set target fields
*
* @param targetFields
*/
public void addTargetFields(Set<String> targetFields) {
for (String tf : targetFields)
{
this.targetFields.add(tf);
}
}
}
/**
* Add array of target fields to update
* @param targetFields
*/
public void addTargetFields(String[] targetFields) {
for (String tf : targetFields)
{
this.targetFields.add(tf);
}
}
/**
* Add array of target fields to update
*
* @param targetFields array of target fields to update
*/
public void addTargetFields(String[] targetFields) {
for (String tf : targetFields) {
this.targetFields.add(tf);
}
}
/**
* Add single field to update
*
* @param targetField target field to update
*/
public void addTargetField(String targetField) {
this.targetFields.add(targetField);
}
/**
* Add single field to update
*
* @param targetField
*/
public void addTargetField(String targetField) {
this.targetFields.add(targetField);
}
}

View File

@@ -16,28 +16,21 @@ import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.List;
import org.jdom.Document;
/**
*
* @author mwood
*/
public class CommandRunner {
/**
* Default constructor
*/
private CommandRunner() { }
/**
* @param args the command line arguments given
* @throws IOException if IO error
* @throws FileNotFoundException if file doesn't exist
*/
public class CommandRunner
{
public static void main(String[] args)
throws FileNotFoundException, IOException {
if (args.length > 0) {
throws FileNotFoundException, IOException
{
if (args.length > 0)
{
runManyCommands(args[0]);
} else {
}
else
{
runManyCommands("-");
}
// There is no sensible way to use the status returned by runManyCommands().
@@ -52,17 +45,22 @@ public class CommandRunner {
/**
* Read a file of command lines and execute each in turn.
*
* @param doc details of recognized commands.
* @param script the file of command lines to be executed.
* @return status code
* @throws IOException if IO error
* @throws FileNotFoundException if file doesn't exist
* @return
* @throws FileNotFoundException
* @throws IOException
*/
static int runManyCommands(String script)
throws FileNotFoundException, IOException {
throws FileNotFoundException, IOException
{
Reader input;
if ("-".equals(script)) {
if ("-".equals(script))
{
input = new InputStreamReader(System.in);
} else {
}
else
{
input = new FileReader(script);
}
@@ -84,17 +82,22 @@ public class CommandRunner {
int status = 0;
List<String> tokens = new ArrayList<String>();
Document commandConfigs = ScriptLauncher.getConfig();
while (StreamTokenizer.TT_EOF != tokenizer.nextToken()) {
if (StreamTokenizer.TT_EOL == tokenizer.ttype) {
if (tokens.size() > 0) {
status = ScriptLauncher.runOneCommand(commandConfigs, tokens.toArray(new String[tokens.size()]));
if (status > 0) {
while (StreamTokenizer.TT_EOF != tokenizer.nextToken())
{
if (StreamTokenizer.TT_EOL == tokenizer.ttype)
{
if (tokens.size() > 0)
{
status = ScriptLauncher.runOneCommand(tokens.toArray(new String[tokens.size()]));
if (status > 0)
{
break;
}
tokens.clear();
}
} else {
}
else
{
tokens.add(tokenizer.sval);
}
}

View File

@@ -12,7 +12,7 @@ import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.TreeMap;
import org.dspace.core.ConfigurationManager;
import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit;
import org.dspace.services.RequestService;
@@ -26,61 +26,60 @@ import org.jdom.input.SAXBuilder;
* @author Stuart Lewis
* @author Mark Diggory
*/
public class ScriptLauncher {
/**
* The service manager kernel
*/
public class ScriptLauncher
{
/** The service manager kernel */
private static transient DSpaceKernelImpl kernelImpl;
/**
* Default constructor
*/
private ScriptLauncher() { }
/** Definitions of all commands. */
private static final Document commandConfigs = getConfig();
/**
* Execute the DSpace script launcher
*
* @param args Any parameters required to be passed to the scripts it executes
* @throws IOException if IO error
* @throws FileNotFoundException if file doesn't exist
*/
public static void main(String[] args)
throws FileNotFoundException, IOException {
throws FileNotFoundException, IOException
{
// Check that there is at least one argument
if (args.length < 1)
{
System.err.println("You must provide at least one command argument");
display();
System.exit(1);
}
// Initialise the service manager kernel
try {
kernelImpl = DSpaceKernelInit.getKernel(null);
if (!kernelImpl.isRunning()) {
kernelImpl.start();
if (!kernelImpl.isRunning())
{
kernelImpl.start(ConfigurationManager.getProperty("dspace.dir"));
}
} catch (Exception e) {
} catch (Exception e)
{
// Failed to start so destroy it and log and throw an exception
try {
try
{
kernelImpl.destroy();
} catch (Exception e1) {
}
catch (Exception e1)
{
// Nothing to do
}
String message = "Failure during kernel init: " + e.getMessage();
System.err.println(message);
e.printStackTrace();
String message = "Failure during filter init: " + e.getMessage();
System.err.println(message + ":" + e);
throw new IllegalStateException(message, e);
}
// Load up the ScriptLauncher's configuration
Document commandConfigs = getConfig();
// Check that there is at least one argument (if not display command options)
if (args.length < 1) {
System.err.println("You must provide at least one command argument");
display(commandConfigs);
System.exit(1);
}
// Look up command in the configuration, and execute.
int status;
status = runOneCommand(commandConfigs, args);
status = runOneCommand(args);
// Destroy the service kernel if it is still alive
if (kernelImpl != null) {
if (kernelImpl != null)
{
kernelImpl.destroy();
kernelImpl = null;
}
@@ -88,57 +87,63 @@ public class ScriptLauncher {
System.exit(status);
}
protected static int runOneCommand(Document commandConfigs, String[] args) {
return runOneCommand(commandConfigs, args, kernelImpl);
}
/**
* Recognize and execute a single command.
*
* @param commandConfigs Document
* @param args the command line arguments given
* @param doc
* @param args
*/
public static int runOneCommand(Document commandConfigs, String[] args, DSpaceKernelImpl kernelImpl) {
static int runOneCommand(String[] args)
{
String request = args[0];
Element root = commandConfigs.getRootElement();
List<Element> commands = root.getChildren("command");
Element command = null;
for (Element candidate : commands) {
if (request.equalsIgnoreCase(candidate.getChild("name").getValue())) {
for (Element candidate : commands)
{
if (request.equalsIgnoreCase(candidate.getChild("name").getValue()))
{
command = candidate;
break;
}
}
if (null == command) {
if (null == command)
{
// The command wasn't found
System.err.println("Command not found: " + args[0]);
display(commandConfigs);
display();
return 1;
}
// Run each step
List<Element> steps = command.getChildren("step");
for (Element step : steps) {
for (Element step : steps)
{
// Instantiate the class
Class target = null;
// Is it the special case 'dsrun' where the user provides the class name?
String className;
if ("dsrun".equals(request)) {
if (args.length < 2) {
if ("dsrun".equals(request))
{
if (args.length < 2)
{
System.err.println("Error in launcher.xml: Missing class name");
return 1;
}
className = args[1];
} else {
}
else {
className = step.getChild("class").getValue();
}
try {
try
{
target = Class.forName(className,
true,
Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
}
catch (ClassNotFoundException e)
{
System.err.println("Error in launcher.xml: Invalid class name: " + className);
return 1;
}
@@ -149,20 +154,26 @@ public class ScriptLauncher {
Class[] argTypes = {useargs.getClass()};
boolean passargs = true;
if ((step.getAttribute("passuserargs") != null) &&
("false".equalsIgnoreCase(step.getAttribute("passuserargs").getValue()))) {
("false".equalsIgnoreCase(step.getAttribute("passuserargs").getValue())))
{
passargs = false;
}
if ((args.length == 1) || (("dsrun".equals(request)) && (args.length == 2)) || (!passargs)) {
if ((args.length == 1) || (("dsrun".equals(request)) && (args.length == 2)) || (!passargs))
{
useargs = new String[0];
} else {
}
else
{
// The number of arguments to ignore
// If dsrun is the command, ignore the next, as it is the class name not an arg
int x = 1;
if ("dsrun".equals(request)) {
if ("dsrun".equals(request))
{
x = 2;
}
String[] argsnew = new String[useargs.length - x];
for (int i = x; i < useargs.length; i++) {
for (int i = x; i < useargs.length; i++)
{
argsnew[i - x] = useargs[i];
}
useargs = argsnew;
@@ -170,13 +181,16 @@ public class ScriptLauncher {
// Add any extra properties
List<Element> bits = step.getChildren("argument");
if (step.getChild("argument") != null) {
if (step.getChild("argument") != null)
{
String[] argsnew = new String[useargs.length + bits.size()];
int i = 0;
for (Element arg : bits) {
for (Element arg : bits)
{
argsnew[i++] = arg.getValue();
}
for (; i < bits.size() + useargs.length; i++) {
for (; i < bits.size() + useargs.length; i++)
{
argsnew[i] = useargs[i - bits.size()];
}
useargs = argsnew;
@@ -184,10 +198,11 @@ public class ScriptLauncher {
// Establish the request service startup
RequestService requestService = kernelImpl.getServiceManager().getServiceByName(
RequestService.class.getName(), RequestService.class);
if (requestService == null) {
RequestService.class.getName(), RequestService.class);
if (requestService == null)
{
throw new IllegalStateException(
"Could not get the DSpace RequestService to start the request transaction");
"Could not get the DSpace RequestService to start the request transaction");
}
// Establish a request related to the current session
@@ -195,23 +210,26 @@ public class ScriptLauncher {
requestService.startRequest();
// Run the main() method
try {
try
{
Object[] arguments = {useargs};
// Useful for debugging, so left in the code...
/**System.out.print("About to execute: " + className);
for (String param : useargs)
{
System.out.print(" " + param);
}
System.out.println("");**/
for (String param : useargs)
{
System.out.print(" " + param);
}
System.out.println("");**/
Method main = target.getMethod("main", argTypes);
main.invoke(null, arguments);
// ensure we close out the request (happy request)
requestService.endRequest(null);
} catch (Exception e) {
}
catch (Exception e)
{
// Failure occurred in the request so we destroy it
requestService.endRequest(e);
@@ -232,23 +250,22 @@ public class ScriptLauncher {
*
* @return The XML configuration file Document
*/
protected static Document getConfig() {
return getConfig(kernelImpl);
}
public static Document getConfig(DSpaceKernelImpl kernelImpl) {
private static Document getConfig()
{
// Load the launcher configuration file
String config = kernelImpl.getConfigurationService().getProperty("dspace.dir") +
System.getProperty("file.separator") + "config" +
System.getProperty("file.separator") + "launcher.xml";
String config = ConfigurationManager.getProperty("dspace.dir") +
System.getProperty("file.separator") + "config" +
System.getProperty("file.separator") + "launcher.xml";
SAXBuilder saxBuilder = new SAXBuilder();
Document doc = null;
try {
try
{
doc = saxBuilder.build(config);
} catch (Exception e) {
}
catch (Exception e)
{
System.err.println("Unable to load the launcher configuration file: [dspace]/config/launcher.xml");
System.err.println(e.getMessage());
e.printStackTrace();
System.exit(1);
}
return doc;
@@ -256,10 +273,9 @@ public class ScriptLauncher {
/**
* Display the commands that the current launcher config file knows about
*
* @param commandConfigs configs as Document
*/
private static void display(Document commandConfigs) {
private static void display()
{
// List all command elements
List<Element> commands = commandConfigs.getRootElement().getChildren("command");
@@ -267,15 +283,17 @@ public class ScriptLauncher {
// We cannot just use commands.sort() because it tries to remove and
// reinsert Elements within other Elements, and that doesn't work.
TreeMap<String, Element> sortedCommands = new TreeMap<>();
for (Element command : commands) {
for (Element command : commands)
{
sortedCommands.put(command.getChild("name").getValue(), command);
}
// Display the sorted list
System.out.println("Usage: dspace [command-name] {parameters}");
for (Element command : sortedCommands.values()) {
for (Element command : sortedCommands.values())
{
System.out.println(" - " + command.getChild("name").getValue() +
": " + command.getChild("description").getValue());
": " + command.getChild("description").getValue());
}
}
}

View File

@@ -7,12 +7,12 @@
*/
package org.dspace.app.mediafilter;
import java.awt.image.BufferedImage;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
/**
* Class to attach a footer to an image using ImageMagick.
@@ -20,117 +20,143 @@ import java.awt.image.BufferedImage;
* This version of the code is basically Ninh's but reorganised a little. Used with permission.
*/
public class Brand {
private int brandWidth;
private int brandHeight;
private Font font;
private int xOffset;
public class Brand
{
private int brandWidth;
private int brandHeight;
private Font font;
private int xOffset;
/**
* Constructor to set up footer image attributes.
*
* @param brandWidth length of the footer in pixels
* @param brandHeight height of the footer in pixels
* @param font font to use for text on the footer
* @param xOffset number of pixels text should be indented from left-hand side of footer
*/
public Brand(int brandWidth,
int brandHeight,
Font font,
int xOffset) {
this.brandWidth = brandWidth;
this.brandHeight = brandHeight;
this.font = font;
this.xOffset = xOffset;
}
/**
* Constructor to set up footer image attributes.
*
* @param brandWidth length of the footer in pixels
* @param brandHeight height of the footer in pixels
* @param font font to use for text on the footer
* @param xOffset number of pixels text should be indented from left-hand side of footer
*
*/
public Brand(int brandWidth,
int brandHeight,
Font font,
int xOffset)
{
this.brandWidth = brandWidth;
this.brandHeight = brandHeight;
this.font = font;
this.xOffset = xOffset;
}
/**
* Create the brand image
*
* @param brandLeftText text that should appear in the bottom left of the image
* @param shortLeftText abbreviated form of brandLeftText that will be substituted if
* the image is resized such that brandLeftText will not fit. <code>null</code> if not
* required
* @param brandRightText text that should appear in the bottom right of the image
* @return BufferedImage a BufferedImage object describing the brand image file
*/
public BufferedImage create(String brandLeftText,
String shortLeftText,
String brandRightText) {
BrandText[] allBrandText = null;
/**
* Create the brand image
*
* @param brandLeftText text that should appear in the bottom left of the image
* @param shortLeftText abbreviated form of brandLeftText that will be substituted if
* the image is resized such that brandLeftText will not fit. <code>null</code> if not
* required
* @param brandRightText text that should appear in the bottom right of the image
*
* @return BufferedImage a BufferedImage object describing the brand image file
*/
public BufferedImage create(String brandLeftText,
String shortLeftText,
String brandRightText)
{
BrandText[] allBrandText = null;
BufferedImage brandImage =
new BufferedImage(brandWidth, brandHeight, BufferedImage.TYPE_INT_RGB);
BufferedImage brandImage =
new BufferedImage(brandWidth, brandHeight, BufferedImage.TYPE_INT_RGB);
if (brandWidth >= 350) {
allBrandText = new BrandText[] {
new BrandText(BrandText.BL, brandLeftText),
new BrandText(BrandText.BR, brandRightText)
};
} else if (brandWidth >= 190) {
allBrandText = new BrandText[] {
new BrandText(BrandText.BL, shortLeftText),
new BrandText(BrandText.BR, brandRightText)
};
} else {
allBrandText = new BrandText[] {
new BrandText(BrandText.BR, brandRightText)
};
}
if (brandWidth >= 350)
{
allBrandText = new BrandText[]
{
new BrandText(BrandText.BL, brandLeftText),
new BrandText(BrandText.BR, brandRightText)
};
}
else if (brandWidth >= 190)
{
allBrandText = new BrandText[]
{
new BrandText(BrandText.BL, shortLeftText),
new BrandText(BrandText.BR, brandRightText)
};
}
else
{
allBrandText = new BrandText[]
{
new BrandText(BrandText.BR, brandRightText)
};
}
if (allBrandText != null && allBrandText.length > 0) {
for (int i = 0; i < allBrandText.length; ++i) {
drawImage(brandImage, allBrandText[i]);
}
}
if (allBrandText != null && allBrandText.length > 0)
{
for (int i = 0; i < allBrandText.length; ++i)
{
drawImage(brandImage, allBrandText[i]);
}
}
return brandImage;
}
return brandImage;
}
/**
* do the text placements and preparatory work for the brand image generation
*
* @param brandImage a BufferedImage object where the image is created
* @param identifier and Identifier object describing what text is to be placed in what
* position within the brand
*/
private void drawImage(BufferedImage brandImage,
BrandText brandText) {
int imgWidth = brandImage.getWidth();
int imgHeight = brandImage.getHeight();
/**
* do the text placements and preparatory work for the brand image generation
*
* @param brandImage a BufferedImage object where the image is created
* @param identifier and Identifier object describing what text is to be placed in what
* position within the brand
*/
private void drawImage(BufferedImage brandImage,
BrandText brandText)
{
int imgWidth = brandImage.getWidth();
int imgHeight = brandImage.getHeight();
Graphics2D g2 = brandImage.createGraphics();
g2.setFont(font);
FontMetrics fm = g2.getFontMetrics();
int bx, by, tx, ty, bWidth, bHeight;
int bWidth = fm.stringWidth(brandText.getText()) + xOffset * 2 + 1;
int bHeight = fm.getHeight();
Graphics2D g2 = brandImage.createGraphics();
g2.setFont(font);
FontMetrics fm = g2.getFontMetrics();
int bx = 0;
int by = 0;
if (brandText.getLocation().equals(BrandText.TL)) {
bx = 0;
by = 0;
} else if (brandText.getLocation().equals(BrandText.TR)) {
bx = imgWidth - bWidth;
by = 0;
} else if (brandText.getLocation().equals(BrandText.BL)) {
bx = 0;
by = imgHeight - bHeight;
} else if (brandText.getLocation().equals(BrandText.BR)) {
bx = imgWidth - bWidth;
by = imgHeight - bHeight;
}
bWidth = fm.stringWidth(brandText.getText()) + xOffset * 2 + 1;
bHeight = fm.getHeight();
Rectangle box = new Rectangle(bx, by, bWidth, bHeight);
int tx = bx + xOffset;
int ty = by + fm.getAscent();
bx = 0;
by = 0;
g2.setColor(Color.black);
g2.fill(box);
g2.setColor(Color.white);
g2.drawString(brandText.getText(), tx, ty);
}
if (brandText.getLocation().equals(BrandText.TL))
{
bx = 0;
by = 0;
}
else if (brandText.getLocation().equals(BrandText.TR))
{
bx = imgWidth - bWidth;
by = 0;
}
else if (brandText.getLocation().equals(BrandText.BL))
{
bx = 0;
by = imgHeight - bHeight;
}
else if (brandText.getLocation().equals(BrandText.BR))
{
bx = imgWidth - bWidth;
by = imgHeight - bHeight;
}
Rectangle box = new Rectangle(bx, by, bWidth, bHeight);
tx = bx + xOffset;
ty = by + fm.getAscent();
g2.setColor(Color.black);
g2.fill(box);
g2.setColor(Color.white);
g2.drawString(brandText.getText(), tx, ty);
}
}

View File

@@ -13,75 +13,73 @@ package org.dspace.app.mediafilter;
* This is a copy of Picture Australia's PiObj class re-organised with methods.
* Thanks to Ninh Nguyen at the National Library for providing the original source.
*/
class BrandText {
/**
* Bottom Left
*/
public static final String BL = "bl";
/**
* Bottom Right
*/
public static final String BR = "br";
/**
* Top Left
*/
public static final String TL = "tl";
/**
* Top Right
*/
public static final String TR = "tr";
class BrandText
{
/** Bottom Left */
public static final String BL = "bl";
/** Bottom Right */
public static final String BR = "br";
/** Top Left */
public static final String TL = "tl";
/** Top Right */
public static final String TR = "tr";
private String location;
private String text;
private String location;
private String text;
/**
* Constructor for an Identifier object containing a text string and
* its location within a rectangular area.
*
* @param location one of the class location constants e.g. <code>Identifier.BL</code>
* @param the text associated with the location
*/
public BrandText(String location, String text) {
this.location = location;
this.text = text;
}
/**
* Constructor for an Identifier object containing a text string and
* its location within a rectangular area.
*
* @param location one of the class location constants e.g. <code>Identifier.BL</code>
* @param the text associated with the location
*/
public BrandText(String location, String text)
{
this.location = location;
this.text = text;
}
/**
* get the location the text of the Identifier object is associated with
*
* @return String one the class location constants e.g. <code>Identifier.BL</code>
*/
public String getLocation() {
return location;
}
/**
* get the location the text of the Identifier object is associated with
*
* @return String one the class location constants e.g. <code>Identifier.BL</code>
*/
public String getLocation()
{
return location;
}
/**
* get the text associated with the Identifier object
*
* @return String the text associated with the Identifier object
*/
public String getText() {
return text;
}
/**
* get the text associated with the Identifier object
*
* @return String the text associated with the Identifier object
*/
public String getText()
{
return text;
}
/**
* set the location associated with the Identifier object
*
* @param location one of the class location constants
*/
public void setLocation(String location) {
this.location = location;
}
/**
* set the location associated with the Identifier object
*
* @param location one of the class location constants
*/
public void setLocation(String location)
{
this.location = location;
}
/**
* set the text associated with the Identifier object
*
* @param text any text string (typically a branding or identifier)
*/
public void setText(String text) {
this.text = text;
}
/**
* set the text associated with the Identifier object
*
* @param text any text string (typically a branding or identifier)
*/
public void setText(String text)
{
this.text = text;
}
}

View File

@@ -7,11 +7,18 @@
*/
package org.dspace.app.mediafilter;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.image.*;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.Font;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.dspace.content.Item;
import org.dspace.core.ConfigurationManager;
/**
@@ -19,68 +26,271 @@ import org.dspace.core.ConfigurationManager;
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
* no bigger than. Creates only JPEGs.
*
* @author Jason Sherman jsherman@usao.edu
* @author Jason Sherman <jsherman@usao.edu>
*/
public class BrandedPreviewJPEGFilter extends MediaFilter {
@Override
public String getFilteredName(String oldFilename) {
public class BrandedPreviewJPEGFilter extends MediaFilter
{
public String getFilteredName(String oldFilename)
{
return oldFilename + ".preview.jpg";
}
/**
* @return String bundle name
*
*/
@Override
public String getBundleName() {
public String getBundleName()
{
return "BRANDED_PREVIEW";
}
/**
* @return String bitstreamformat
*/
@Override
public String getFormatString() {
public String getFormatString()
{
return "JPEG";
}
/**
* @return String description
*/
@Override
public String getDescription() {
public String getDescription()
{
return "Generated Branded Preview";
}
/**
* @param currentItem item
* @param source source input stream
* @param verbose verbose mode
* @param source
* source input stream
*
* @return InputStream the resulting input stream
* @throws Exception if error
*/
@Override
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
throws Exception {
public InputStream getDestinationStream(InputStream source)
throws Exception
{
// read in bitstream's image
BufferedImage buf = ImageIO.read(source);
// get config params
float xmax = (float) ConfigurationManager
.getIntProperty("webui.preview.maxwidth");
.getIntProperty("webui.preview.maxwidth");
float ymax = (float) ConfigurationManager
.getIntProperty("webui.preview.maxheight");
.getIntProperty("webui.preview.maxheight");
boolean blurring = (boolean) ConfigurationManager
.getBooleanProperty("webui.preview.blurring");
.getBooleanProperty("webui.preview.blurring");
boolean hqscaling = (boolean) ConfigurationManager
.getBooleanProperty("webui.preview.hqscaling");
.getBooleanProperty("webui.preview.hqscaling");
int brandHeight = ConfigurationManager.getIntProperty("webui.preview.brand.height");
String brandFont = ConfigurationManager.getProperty("webui.preview.brand.font");
int brandFontPoint = ConfigurationManager.getIntProperty("webui.preview.brand.fontpoint");
// now get the image dimensions
float xsize = (float) buf.getWidth(null);
float ysize = (float) buf.getHeight(null);
JPEGFilter jpegFilter = new JPEGFilter();
return jpegFilter
.getThumbDim(currentItem, buf, verbose, xmax, ymax, blurring, hqscaling, brandHeight, brandFontPoint,
brandFont);
// if verbose flag is set, print out dimensions
// to STDOUT
if (MediaFilterManager.isVerbose)
{
System.out.println("original size: " + xsize + "," + ysize);
}
// scale by x first if needed
if (xsize > xmax)
{
// calculate scaling factor so that xsize * scale = new size (max)
float scaleFactor = xmax / xsize;
// if verbose flag is set, print out extracted text
// to STDOUT
if (MediaFilterManager.isVerbose)
{
System.out.println("x scale factor: " + scaleFactor);
}
// now reduce x size
// and y size
xsize = xsize * scaleFactor;
ysize = ysize * scaleFactor;
// if verbose flag is set, print out extracted text
// to STDOUT
if (MediaFilterManager.isVerbose)
{
System.out.println("new size: " + xsize + "," + ysize);
}
}
// scale by y if needed
if (ysize > ymax)
{
float scaleFactor = ymax / ysize;
// now reduce x size
// and y size
xsize = xsize * scaleFactor;
ysize = ysize * scaleFactor;
}
// if verbose flag is set, print details to STDOUT
if (MediaFilterManager.isVerbose)
{
System.out.println("created thumbnail size: " + xsize + ", "
+ ysize);
}
// create an image buffer for the preview with the new xsize, ysize
// we add
BufferedImage branded = new BufferedImage((int) xsize, (int) ysize + brandHeight,
BufferedImage.TYPE_INT_RGB);
// Use blurring if selected in config.
// a little blur before scaling does wonders for keeping moire in check.
if (blurring)
{
// send the buffered image off to get blurred.
buf = getBlurredInstance((BufferedImage) buf);
}
// Use high quality scaling method if selected in config.
// this has a definite performance penalty.
if (hqscaling)
{
// send the buffered image off to get an HQ downscale.
buf = getScaledInstance((BufferedImage) buf, (int) xsize, (int) ysize,
(Object) RenderingHints.VALUE_INTERPOLATION_BICUBIC, (boolean) true);
}
// now render the image into the preview buffer
Graphics2D g2d = branded.createGraphics();
g2d.drawImage(buf, 0, 0, (int) xsize, (int) ysize, null);
Brand brand = new Brand((int) xsize, brandHeight, new Font(brandFont, Font.PLAIN, brandFontPoint), 5);
BufferedImage brandImage = brand.create(ConfigurationManager.getProperty("webui.preview.brand"),
ConfigurationManager.getProperty("webui.preview.brand.abbrev"),
MediaFilterManager.getCurrentItem() == null ? "" : "hdl:" + MediaFilterManager.getCurrentItem().getHandle());
g2d.drawImage(brandImage, (int)0, (int)ysize, (int) xsize, (int) 20, null);
// now create an input stream for the thumbnail buffer and return it
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(branded, "jpeg", baos);
// now get the array
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
return bais; // hope this gets written out before its garbage collected!
}
public BufferedImage getNormalizedInstance(BufferedImage buf)
{
int type = (buf.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB_PRE;
int w, h;
w = buf.getWidth();
h = buf.getHeight();
BufferedImage normal = new BufferedImage(w, h, type);
Graphics2D g2d = normal.createGraphics();
g2d.drawImage(buf, 0, 0, w, h, Color.WHITE, null);
g2d.dispose();
return normal;
}
public BufferedImage getBlurredInstance(BufferedImage buf)
{
/**
* Convenience method that returns a blurred instance of the
* provided {@code BufferedImage}.
*
*/
buf = getNormalizedInstance(buf);
// kernel for blur op
float[] matrix = {
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
};
// perform the blur and return the blurred version.
BufferedImageOp blur = new ConvolveOp( new Kernel(3, 3, matrix) );
BufferedImage blurbuf = blur.filter(buf, null);
return blurbuf;
}
/**
* Convenience method that returns a scaled instance of the
* provided {@code BufferedImage}.
*
* @param buf the original image to be scaled
* @param targetWidth the desired width of the scaled instance,
* in pixels
* @param targetHeight the desired height of the scaled instance,
* in pixels
* @param hint one of the rendering hints that corresponds to
* {@code RenderingHints.KEY_INTERPOLATION} (e.g.
* {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
* {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
* {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
* @param higherQuality if true, this method will use a multi-step
* scaling technique that provides higher quality than the usual
* one-step technique (only useful in downscaling cases, where
* {@code targetWidth} or {@code targetHeight} is
* smaller than the original dimensions, and generally only when
* the {@code BILINEAR} hint is specified)
* @return a scaled version of the original {@code BufferedImage}
*/
public BufferedImage getScaledInstance(BufferedImage buf,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality)
{
int type = (buf.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scalebuf = (BufferedImage)buf;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = buf.getWidth();
h = buf.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2d = tmp.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2d.drawImage(scalebuf, 0, 0, w, h, Color.WHITE, null);
g2d.dispose();
scalebuf = tmp;
} while (w != targetWidth || h != targetHeight);
return scalebuf;
}
}

View File

@@ -1,99 +0,0 @@
/**
* 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.app.mediafilter;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.poi.POITextExtractor;
import org.apache.poi.extractor.ExtractorFactory;
import org.apache.poi.hssf.extractor.ExcelExtractor;
import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
import org.dspace.content.Item;
/*
* ExcelFilter
*
* Entries you must add to dspace.cfg:
*
* filter.plugins = blah, \
* Excel Text Extractor
*
* plugin.named.org.dspace.app.mediafilter.FormatFilter = \
* blah = blah, \
* org.dspace.app.mediafilter.ExcelFilter = Excel Text Extractor
*
* #Configure each filter's input Formats
* filter.org.dspace.app.mediafilter.ExcelFilter.inputFormats = Microsoft Excel, Microsoft Excel XML
*
*/
public class ExcelFilter extends MediaFilter {
private static Logger log = Logger.getLogger(ExcelFilter.class);
public String getFilteredName(String oldFilename) {
return oldFilename + ".txt";
}
/**
* @return String bundle name
*/
public String getBundleName() {
return "TEXT";
}
/**
* @return String bitstream format
*/
public String getFormatString() {
return "Text";
}
/**
* @return String description
*/
public String getDescription() {
return "Extracted text";
}
/**
* @param item item
* @param source source input stream
* @param verbose verbose mode
* @return InputStream the resulting input stream
* @throws Exception if error
*/
@Override
public InputStream getDestinationStream(Item item, InputStream source, boolean verbose)
throws Exception {
String extractedText = null;
try {
POITextExtractor theExtractor = ExtractorFactory.createExtractor(source);
if (theExtractor instanceof ExcelExtractor) {
// for xls file
extractedText = (theExtractor).getText();
} else if (theExtractor instanceof XSSFExcelExtractor) {
// for xlsx file
extractedText = (theExtractor).getText();
}
} catch (Exception e) {
log.error("Error filtering bitstream: " + e.getMessage(), e);
throw e;
}
if (extractedText != null) {
// generate an input stream with the extracted text
return IOUtils.toInputStream(extractedText, StandardCharsets.UTF_8);
}
return null;
}
}

View File

@@ -14,70 +14,72 @@ import org.dspace.content.Item;
import org.dspace.core.Context;
/**
* Public interface for any class which transforms or converts content/bitstreams
* Public interface for any class which transforms or converts content/bitstreams
* from one format to another. This interface should be implemented by any class
* which defines a "filter" to be run by the MediaFilterManager.
*/
public interface FormatFilter {
public interface FormatFilter
{
/**
* Get a filename for a newly created filtered bitstream
*
* @param sourceName name of source bitstream
*
* @param sourceName
* name of source bitstream
* @return filename generated by the filter - for example, document.pdf
* becomes document.pdf.txt
* becomes document.pdf.txt
*/
public String getFilteredName(String sourceName);
/**
* @return name of the bundle this filter will stick its generated
* Bitstreams
* Bitstreams
*/
public String getBundleName();
/**
* @return name of the bitstream format (say "HTML" or "Microsoft Word")
* returned by this filter look in the bitstream format registry or
* mediafilter.cfg for valid format strings.
* returned by this filter look in the bitstream format registry or
* mediafilter.cfg for valid format strings.
*/
public String getFormatString();
/**
* @return string to describe the newly-generated Bitstream - how it was
* produced is a good idea
* @return string to describe the newly-generated Bitstream's - how it was
* produced is a good idea
*/
public String getDescription();
/**
* Read the source stream and produce the filtered content.
*
* @param item Item
* @param source input stream
* @param verbose verbosity flag
* @return result of filter's transformation as a byte stream.
* @throws Exception if error
* @param source
* input stream
*
* @return result of filter's transformation, written out to a bitstream
*/
public InputStream getDestinationStream(Item item, InputStream source, boolean verbose)
throws Exception;
public InputStream getDestinationStream(InputStream source)
throws Exception;
/**
* Perform any pre-processing of the source bitstream *before* the actual
* Perform any pre-processing of the source bitstream *before* the actual
* filtering takes place in MediaFilterManager.processBitstream().
* <p>
* Return true if pre-processing is successful (or no pre-processing
* is necessary). Return false if bitstream should be skipped
* for any reason.
*
* @param c context
* @param item item containing bitstream to process
* @param source source bitstream to be processed
* @param verbose verbose mode
* @return true if bitstream processing should continue,
* false if this bitstream should be skipped
* @throws Exception if error
*
*
* @param c
* context
* @param item
* item containing bitstream to process
* @param source
* source bitstream to be processed
*
* @return true if bitstream processing should continue,
* false if this bitstream should be skipped
*/
public boolean preProcessBitstream(Context c, Item item, Bitstream source, boolean verbose)
throws Exception;
public boolean preProcessBitstream(Context c, Item item, Bitstream source)
throws Exception;
/**
* Perform any post-processing of the generated bitstream *after* this
* filter has already been run.
@@ -85,14 +87,17 @@ public interface FormatFilter {
* Return true if pre-processing is successful (or no pre-processing
* is necessary). Return false if bitstream should be skipped
* for some reason.
*
* @param c context
* @param item item containing bitstream to process
* @param generatedBitstream the bitstream which was generated by
* this filter.
* @throws Exception if error
*
*
* @param c
* context
* @param item
* item containing bitstream to process
* @param generatedBitstream
* the bitstream which was generated by
* this filter.
*/
public void postProcessBitstream(Context c, Item item, Bitstream generatedBitstream)
throws Exception;
throws Exception;
}

View File

@@ -9,58 +9,58 @@ package org.dspace.app.mediafilter;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLEditorKit;
import org.dspace.content.Item;
/*
*
*
* to do: helpful error messages - can't find mediafilter.cfg - can't
* instantiate filter - bitstream format doesn't exist
*
*
*/
public class HTMLFilter extends MediaFilter {
public class HTMLFilter extends MediaFilter
{
@Override
public String getFilteredName(String oldFilename) {
public String getFilteredName(String oldFilename)
{
return oldFilename + ".txt";
}
/**
* @return String bundle name
*
*/
@Override
public String getBundleName() {
public String getBundleName()
{
return "TEXT";
}
/**
* @return String bitstreamformat
*/
@Override
public String getFormatString() {
public String getFormatString()
{
return "Text";
}
/**
* @return String description
*/
@Override
public String getDescription() {
public String getDescription()
{
return "Extracted text";
}
/**
* @param currentItem item
* @param source source input stream
* @param verbose verbose mode
* @param source
* source input stream
*
* @return InputStream the resulting input stream
* @throws Exception if error
*/
@Override
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
throws Exception {
public InputStream getDestinationStream(InputStream source)
throws Exception
{
// try and read the document - set to ignore character set directive,
// assuming that the input stream is already set properly (I hope)
HTMLEditorKit kit = new HTMLEditorKit();

View File

@@ -12,41 +12,43 @@ import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import org.dspace.content.Item;
/**
* Filter image bitstreams, scaling the image to be within the bounds of
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
* no bigger than. Creates only JPEGs.
*/
public class ImageMagickImageThumbnailFilter extends ImageMagickThumbnailFilter {
public class ImageMagickImageThumbnailFilter extends ImageMagickThumbnailFilter
{
/**
* @param currentItem item
* @param source source input stream
* @param verbose verbose mode
* @param source
* source input stream
*
* @return InputStream the resulting input stream
* @throws Exception if error
*/
@Override
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
throws Exception {
File f = inputStreamToTempFile(source, "imthumb", ".tmp");
File f2 = null;
try {
f2 = getThumbnailFile(f, verbose);
byte[] bytes = Files.readAllBytes(f2.toPath());
return new ByteArrayInputStream(bytes);
} finally {
//noinspection ResultOfMethodCallIgnored
f.delete();
if (f2 != null) {
//noinspection ResultOfMethodCallIgnored
f2.delete();
}
}
}
public InputStream getDestinationStream(InputStream source)
throws Exception
{
File f = inputStreamToTempFile(source, "imthumb", ".tmp");
File f2 = null;
try
{
f2 = getThumbnailFile(f);
byte[] bytes = Files.readAllBytes(f2.toPath());
return new ByteArrayInputStream(bytes);
}
finally
{
//noinspection ResultOfMethodCallIgnored
f.delete();
if (f2 != null)
{
//noinspection ResultOfMethodCallIgnored
f2.delete();
}
}
}
}

View File

@@ -12,32 +12,35 @@ import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import org.dspace.content.Item;
public class ImageMagickPdfThumbnailFilter extends ImageMagickThumbnailFilter {
@Override
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
throws Exception {
File f = inputStreamToTempFile(source, "impdfthumb", ".pdf");
File f2 = null;
File f3 = null;
try {
f2 = getImageFile(f, 0, verbose);
f3 = getThumbnailFile(f2, verbose);
byte[] bytes = Files.readAllBytes(f3.toPath());
return new ByteArrayInputStream(bytes);
} finally {
//noinspection ResultOfMethodCallIgnored
f.delete();
if (f2 != null) {
//noinspection ResultOfMethodCallIgnored
f2.delete();
}
if (f3 != null) {
//noinspection ResultOfMethodCallIgnored
f3.delete();
}
}
public InputStream getDestinationStream(InputStream source)
throws Exception
{
File f = inputStreamToTempFile(source, "impdfthumb", ".pdf");
File f2 = null;
File f3 = null;
try
{
f2 = getImageFile(f, 0);
f3 = getThumbnailFile(f2);
byte[] bytes = Files.readAllBytes(f3.toPath());
return new ByteArrayInputStream(bytes);
}
finally
{
//noinspection ResultOfMethodCallIgnored
f.delete();
if (f2 != null)
{
//noinspection ResultOfMethodCallIgnored
f2.delete();
}
if (f3 != null)
{
//noinspection ResultOfMethodCallIgnored
f3.delete();
}
}
}
}

View File

@@ -14,189 +14,184 @@ import java.io.InputStream;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.imageio.ImageIO;
import org.dspace.app.mediafilter.MediaFilter;
import org.dspace.app.mediafilter.SelfRegisterInputFormats;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.im4java.core.ConvertCmd;
import org.im4java.core.Info;
import org.im4java.core.IM4JavaException;
import org.im4java.core.IMOperation;
import org.im4java.core.Info;
import org.im4java.process.ProcessStarter;
import org.dspace.core.ConfigurationManager;
/**
* Filter image bitstreams, scaling the image to be within the bounds of
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
* no bigger than. Creates only JPEGs.
*/
public abstract class ImageMagickThumbnailFilter extends MediaFilter {
protected static int width = 180;
protected static int height = 120;
private static boolean flatten = true;
static String bitstreamDescription = "IM Thumbnail";
static final String defaultPattern = "Generated Thumbnail";
static Pattern replaceRegex = Pattern.compile(defaultPattern);
protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
private static int width = 180;
private static int height = 120;
private static boolean flatten = true;
static String bitstreamDescription = "IM Thumbnail";
static final String defaultPattern = "Generated Thumbnail";
static Pattern replaceRegex = Pattern.compile(defaultPattern);
static String cmyk_profile;
static String srgb_profile;
static String cmyk_profile;
static String srgb_profile;
static {
String pre = ImageMagickThumbnailFilter.class.getName();
String s = ConfigurationManager.getProperty(pre + ".ProcessStarter");
ProcessStarter.setGlobalSearchPath(s);
width = ConfigurationManager.getIntProperty("thumbnail.maxwidth", width);
height = ConfigurationManager.getIntProperty("thumbnail.maxheight", height);
flatten = ConfigurationManager.getBooleanProperty(pre + ".flatten", flatten);
String description = ConfigurationManager.getProperty(pre + ".bitstreamDescription");
cmyk_profile = ConfigurationManager.getProperty(pre + ".cmyk_profile");
srgb_profile = ConfigurationManager.getProperty(pre + ".srgb_profile");
if (description != null) {
bitstreamDescription = description;
}
try {
String patt = ConfigurationManager.getProperty(pre + ".replaceRegex");
replaceRegex = Pattern.compile(patt == null ? defaultPattern : patt);
} catch (PatternSyntaxException e) {
System.err.println("Invalid thumbnail replacement pattern: " + e.getMessage());
}
}
public ImageMagickThumbnailFilter() {
}
@Override
public String getFilteredName(String oldFilename) {
return oldFilename + ".jpg";
}
/**
* @return String bundle name
*/
@Override
public String getBundleName() {
return "THUMBNAIL";
}
/**
* @return String bitstreamformat
*/
@Override
public String getFormatString() {
return "JPEG";
}
/**
* @return String bitstreamDescription
*/
@Override
public String getDescription() {
return bitstreamDescription;
}
public File inputStreamToTempFile(InputStream source, String prefix, String suffix) throws IOException {
File f = File.createTempFile(prefix, suffix);
f.deleteOnExit();
FileOutputStream fos = new FileOutputStream(f);
byte[] buffer = new byte[1024];
int len = source.read(buffer);
while (len != -1) {
fos.write(buffer, 0, len);
len = source.read(buffer);
}
fos.close();
return f;
}
public File getThumbnailFile(File f, boolean verbose)
throws IOException, InterruptedException, IM4JavaException {
File f2 = new File(f.getParentFile(), f.getName() + ".jpg");
f2.deleteOnExit();
ConvertCmd cmd = new ConvertCmd();
IMOperation op = new IMOperation();
op.autoOrient();
op.addImage(f.getAbsolutePath());
op.thumbnail(width, height);
op.addImage(f2.getAbsolutePath());
if (verbose) {
System.out.println("IM Thumbnail Param: " + op);
}
cmd.run(op);
return f2;
}
public File getImageFile(File f, int page, boolean verbose)
throws IOException, InterruptedException, IM4JavaException {
File f2 = new File(f.getParentFile(), f.getName() + ".jpg");
f2.deleteOnExit();
ConvertCmd cmd = new ConvertCmd();
IMOperation op = new IMOperation();
String s = "[" + page + "]";
op.addImage(f.getAbsolutePath() + s);
if (flatten) {
op.flatten();
}
// PDFs using the CMYK color system can be handled specially if
// profiles are defined
if (cmyk_profile != null && srgb_profile != null) {
Info imageInfo = new Info(f.getAbsolutePath(), true);
String imageClass = imageInfo.getImageClass();
if (imageClass.contains("CMYK")) {
op.profile(cmyk_profile);
op.profile(srgb_profile);
}
}
op.addImage(f2.getAbsolutePath());
if (verbose) {
System.out.println("IM Image Param: " + op);
}
cmd.run(op);
return f2;
}
@Override
public boolean preProcessBitstream(Context c, Item item, Bitstream source, boolean verbose) throws Exception {
String nsrc = source.getName();
for (Bundle b : itemService.getBundles(item, "THUMBNAIL")) {
for (Bitstream bit : b.getBitstreams()) {
String n = bit.getName();
if (n != null) {
if (nsrc != null) {
if (!n.startsWith(nsrc)) {
continue;
}
}
}
String description = bit.getDescription();
// If anything other than a generated thumbnail
// is found, halt processing
static {
String pre = ImageMagickThumbnailFilter.class.getName();
String s = ConfigurationManager.getProperty(pre + ".ProcessStarter");
ProcessStarter.setGlobalSearchPath(s);
width = ConfigurationManager.getIntProperty("thumbnail.maxwidth", width);
height = ConfigurationManager.getIntProperty("thumbnail.maxheight", height);
flatten = ConfigurationManager.getBooleanProperty(pre + ".flatten", flatten);
String description = ConfigurationManager.getProperty(pre + ".bitstreamDescription");
cmyk_profile = ConfigurationManager.getProperty(pre + ".cmyk_profile");
srgb_profile = ConfigurationManager.getProperty(pre + ".srgb_profile");
if (description != null) {
if (replaceRegex.matcher(description).matches()) {
if (verbose) {
System.out.println(description + " " + nsrc
+ " matches pattern and is replacable.");
}
continue;
}
if (description.equals(bitstreamDescription)) {
if (verbose) {
System.out.println(bitstreamDescription + " " + nsrc
+ " is replacable.");
}
continue;
}
bitstreamDescription = description;
}
System.out.println("Custom Thumbnail exists for " + nsrc + " for item "
+ item.getHandle() + ". Thumbnail will not be generated. ");
return false;
}
try {
String patt = ConfigurationManager.getProperty(pre + ".replaceRegex");
replaceRegex = Pattern.compile(patt == null ? defaultPattern : patt);
} catch (PatternSyntaxException e) {
System.err.println("Invalid thumbnail replacement pattern: " + e.getMessage());
}
}
return true; // assume that the thumbnail is a custom one
}
public ImageMagickThumbnailFilter() {
}
public String getFilteredName(String oldFilename) {
return oldFilename + ".jpg";
}
/**
* @return String bundle name
*
*/
public String getBundleName() {
return "THUMBNAIL";
}
/**
* @return String bitstreamformat
*/
public String getFormatString() {
return "JPEG";
}
/**
* @return String bitstreamDescription
*/
public String getDescription() {
return bitstreamDescription;
}
public static File inputStreamToTempFile(InputStream source, String prefix, String suffix) throws IOException {
File f = File.createTempFile(prefix, suffix);
f.deleteOnExit();
FileOutputStream fos = new FileOutputStream(f);
byte[] buffer = new byte[1024];
int len = source.read(buffer);
while (len != -1) {
fos.write(buffer, 0, len);
len = source.read(buffer);
}
fos.close();
return f;
}
public static File getThumbnailFile(File f) throws IOException, InterruptedException, IM4JavaException {
File f2 = new File(f.getParentFile(), f.getName() + ".jpg");
f2.deleteOnExit();
ConvertCmd cmd = new ConvertCmd();
IMOperation op = new IMOperation();
op.autoOrient();
op.addImage(f.getAbsolutePath());
op.thumbnail(width, height);
op.addImage(f2.getAbsolutePath());
if (MediaFilterManager.isVerbose) {
System.out.println("IM Thumbnail Param: " + op);
}
cmd.run(op);
return f2;
}
public static File getImageFile(File f, int page) throws IOException, InterruptedException, IM4JavaException {
File f2 = new File(f.getParentFile(), f.getName() + ".jpg");
f2.deleteOnExit();
ConvertCmd cmd = new ConvertCmd();
IMOperation op = new IMOperation();
String s = "[" + page + "]";
op.addImage(f.getAbsolutePath() + s);
if (flatten) {
op.flatten();
}
// PDFs using the CMYK color system can be handled specially if
// profiles are defined
if (cmyk_profile != null && srgb_profile != null) {
Info imageInfo = new Info(f.getAbsolutePath() + s, true);
String imageClass = imageInfo.getImageClass();
if (imageClass.contains("CMYK")) {
op.profile(cmyk_profile);
op.profile(srgb_profile);
}
}
op.addImage(f2.getAbsolutePath());
if (MediaFilterManager.isVerbose) {
System.out.println("IM Image Param: " + op);
}
cmd.run(op);
return f2;
}
public boolean preProcessBitstream(Context c, Item item, Bitstream source) throws Exception {
String nsrc = source.getName();
for (Bundle b : item.getBundles("THUMBNAIL")) {
for (Bitstream bit : b.getBitstreams()) {
String n = bit.getName();
if (n != null) {
if (nsrc != null) {
if (!n.startsWith(nsrc))
continue;
}
}
String description = bit.getDescription();
// If anything other than a generated thumbnail
// is found, halt processing
if (description != null) {
if (replaceRegex.matcher(description).matches()) {
if (MediaFilterManager.isVerbose) {
System.out.println(description + " " + nsrc
+ " matches pattern and is replacable.");
}
continue;
}
if (description.equals(bitstreamDescription)) {
if (MediaFilterManager.isVerbose) {
System.out.println(bitstreamDescription + " " + nsrc
+ " is replacable.");
}
continue;
}
}
System.out.println("Custom Thumbnail exists for " + nsrc + " for item "
+ item.getHandle() + ". Thumbnail will not be generated. ");
return false;
}
}
return true; // assume that the thumbnail is a custom one
}
}

View File

@@ -7,21 +7,17 @@
*/
package org.dspace.app.mediafilter;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.image.*;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.dspace.content.Item;
import org.dspace.core.ConfigurationManager;
/**
@@ -29,91 +25,83 @@ import org.dspace.core.ConfigurationManager;
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
* no bigger than. Creates only JPEGs.
*
* @author Jason Sherman jsherman@usao.edu
* @author Jason Sherman <jsherman@usao.edu>
*/
public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats {
@Override
public String getFilteredName(String oldFilename) {
public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats
{
public String getFilteredName(String oldFilename)
{
return oldFilename + ".jpg";
}
/**
* @return String bundle name
*
*/
@Override
public String getBundleName() {
public String getBundleName()
{
return "THUMBNAIL";
}
/**
* @return String bitstreamformat
*/
@Override
public String getFormatString() {
public String getFormatString()
{
return "JPEG";
}
/**
* @return String description
*/
@Override
public String getDescription() {
public String getDescription()
{
return "Generated Thumbnail";
}
/**
* @param currentItem item
* @param source source input stream
* @param verbose verbose mode
* @param source
* source input stream
*
* @return InputStream the resulting input stream
* @throws Exception if error
*/
@Override
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
throws Exception {
public InputStream getDestinationStream(InputStream source)
throws Exception
{
// read in bitstream's image
BufferedImage buf = ImageIO.read(source);
return getThumb(currentItem, buf, verbose);
}
public InputStream getThumb(Item currentItem, BufferedImage buf, boolean verbose)
throws Exception {
// get config params
float xmax = (float) ConfigurationManager
.getIntProperty("thumbnail.maxwidth");
.getIntProperty("thumbnail.maxwidth");
float ymax = (float) ConfigurationManager
.getIntProperty("thumbnail.maxheight");
.getIntProperty("thumbnail.maxheight");
boolean blurring = (boolean) ConfigurationManager
.getBooleanProperty("thumbnail.blurring");
.getBooleanProperty("thumbnail.blurring");
boolean hqscaling = (boolean) ConfigurationManager
.getBooleanProperty("thumbnail.hqscaling");
.getBooleanProperty("thumbnail.hqscaling");
return getThumbDim(currentItem, buf, verbose, xmax, ymax, blurring, hqscaling, 0, 0, null);
}
public InputStream getThumbDim(Item currentItem, BufferedImage buf, boolean verbose, float xmax, float ymax,
boolean blurring, boolean hqscaling, int brandHeight, int brandFontPoint,
String brandFont)
throws Exception {
// now get the image dimensions
float xsize = (float) buf.getWidth(null);
float ysize = (float) buf.getHeight(null);
// if verbose flag is set, print out dimensions
// to STDOUT
if (verbose) {
if (MediaFilterManager.isVerbose)
{
System.out.println("original size: " + xsize + "," + ysize);
}
// scale by x first if needed
if (xsize > xmax) {
if (xsize > xmax)
{
// calculate scaling factor so that xsize * scale = new size (max)
float scale_factor = xmax / xsize;
// if verbose flag is set, print out extracted text
// to STDOUT
if (verbose) {
if (MediaFilterManager.isVerbose)
{
System.out.println("x scale factor: " + scale_factor);
}
@@ -124,13 +112,15 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats
// if verbose flag is set, print out extracted text
// to STDOUT
if (verbose) {
System.out.println("size after fitting to maximum width: " + xsize + "," + ysize);
if (MediaFilterManager.isVerbose)
{
System.out.println("new size: " + xsize + "," + ysize);
}
}
// scale by y if needed
if (ysize > ymax) {
if (ysize > ymax)
{
float scale_factor = ymax / ysize;
// now reduce x size
@@ -140,43 +130,37 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats
}
// if verbose flag is set, print details to STDOUT
if (verbose) {
System.out.println("size after fitting to maximum height: " + xsize + ", "
+ ysize);
if (MediaFilterManager.isVerbose)
{
System.out.println("created thumbnail size: " + xsize + ", "
+ ysize);
}
// create an image buffer for the thumbnail with the new xsize, ysize
BufferedImage thumbnail = new BufferedImage((int) xsize, (int) ysize,
BufferedImage.TYPE_INT_RGB);
BufferedImage.TYPE_INT_RGB);
// Use blurring if selected in config.
// a little blur before scaling does wonders for keeping moire in check.
if (blurring) {
// send the buffered image off to get blurred.
buf = getBlurredInstance((BufferedImage) buf);
if (blurring)
{
// send the buffered image off to get blurred.
buf = getBlurredInstance((BufferedImage) buf);
}
// Use high quality scaling method if selected in config.
// this has a definite performance penalty.
if (hqscaling) {
// send the buffered image off to get an HQ downscale.
buf = getScaledInstance((BufferedImage) buf, (int) xsize, (int) ysize,
(Object) RenderingHints.VALUE_INTERPOLATION_BICUBIC, (boolean) true);
if (hqscaling)
{
// send the buffered image off to get an HQ downscale.
buf = getScaledInstance((BufferedImage) buf, (int) xsize, (int) ysize,
(Object) RenderingHints.VALUE_INTERPOLATION_BICUBIC, (boolean) true);
}
// now render the image into the thumbnail buffer
Graphics2D g2d = thumbnail.createGraphics();
g2d.drawImage(buf, 0, 0, (int) xsize, (int) ysize, null);
if (brandHeight != 0) {
Brand brand = new Brand((int) xsize, brandHeight, new Font(brandFont, Font.PLAIN, brandFontPoint), 5);
BufferedImage brandImage = brand.create(ConfigurationManager.getProperty("webui.preview.brand"),
ConfigurationManager.getProperty("webui.preview.brand.abbrev"),
currentItem == null ? "" : "hdl:" + currentItem.getHandle());
g2d.drawImage(brandImage, (int) 0, (int) ysize, (int) xsize, (int) 20, null);
}
// now create an input stream for the thumbnail buffer and return it
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -189,90 +173,92 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats
}
@Override
public String[] getInputMIMETypes() {
public String[] getInputMIMETypes()
{
return ImageIO.getReaderMIMETypes();
}
@Override
public String[] getInputDescriptions() {
public String[] getInputDescriptions()
{
return null;
}
@Override
public String[] getInputExtensions() {
public String[] getInputExtensions()
{
// Temporarily disabled as JDK 1.6 only
// return ImageIO.getReaderFileSuffixes();
return null;
}
public BufferedImage getNormalizedInstance(BufferedImage buf) {
int type = (buf.getTransparency() == Transparency.OPAQUE) ?
public BufferedImage getNormalizedInstance(BufferedImage buf)
{
int type = (buf.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB_PRE;
int w = buf.getWidth();
int h = buf.getHeight();
BufferedImage normal = new BufferedImage(w, h, type);
Graphics2D g2d = normal.createGraphics();
g2d.drawImage(buf, 0, 0, w, h, Color.WHITE, null);
g2d.dispose();
return normal;
int w, h;
w = buf.getWidth();
h = buf.getHeight();
BufferedImage normal = new BufferedImage(w, h, type);
Graphics2D g2d = normal.createGraphics();
g2d.drawImage(buf, 0, 0, w, h, Color.WHITE, null);
g2d.dispose();
return normal;
}
public BufferedImage getBlurredInstance(BufferedImage buf)
{
/**
* Convenience method that returns a blurred instance of the
* provided {@code BufferedImage}.
*
* @param buf buffered image
* @return updated BufferedImage
*/
public BufferedImage getBlurredInstance(BufferedImage buf) {
buf = getNormalizedInstance(buf);
// kernel for blur op
float[] matrix = {
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
};
buf = getNormalizedInstance(buf);
// perform the blur and return the blurred version.
BufferedImageOp blur = new ConvolveOp(new Kernel(3, 3, matrix));
BufferedImage blurbuf = blur.filter(buf, null);
return blurbuf;
// kernel for blur op
float[] matrix = {
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
};
// perform the blur and return the blurred version.
BufferedImageOp blur = new ConvolveOp( new Kernel(3, 3, matrix) );
BufferedImage blurbuf = blur.filter(buf, null);
return blurbuf;
}
/**
* Convenience method that returns a scaled instance of the
* provided {@code BufferedImage}.
*
* @param buf the original image to be scaled
* @param targetWidth the desired width of the scaled instance,
* in pixels
* @param targetHeight the desired height of the scaled instance,
* in pixels
* @param hint one of the rendering hints that corresponds to
* {@code RenderingHints.KEY_INTERPOLATION} (e.g.
* {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
* {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
* {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
* @param buf the original image to be scaled
* @param targetWidth the desired width of the scaled instance,
* in pixels
* @param targetHeight the desired height of the scaled instance,
* in pixels
* @param hint one of the rendering hints that corresponds to
* {@code RenderingHints.KEY_INTERPOLATION} (e.g.
* {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
* {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
* {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
* @param higherQuality if true, this method will use a multi-step
* scaling technique that provides higher quality than the usual
* one-step technique (only useful in downscaling cases, where
* {@code targetWidth} or {@code targetHeight} is
* smaller than the original dimensions, and generally only when
* the {@code BILINEAR} hint is specified)
* scaling technique that provides higher quality than the usual
* one-step technique (only useful in downscaling cases, where
* {@code targetWidth} or {@code targetHeight} is
* smaller than the original dimensions, and generally only when
* the {@code BILINEAR} hint is specified)
* @return a scaled version of the original {@code BufferedImage}
*/
public BufferedImage getScaledInstance(BufferedImage buf,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
boolean higherQuality)
{
int type = (buf.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scalebuf = (BufferedImage) buf;
int w;
int h;
BufferedImage scalebuf = (BufferedImage)buf;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()

Some files were not shown because too many files have changed in this diff Show More