1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.opencastproject.oaipmh.server;
22
23 import static org.opencastproject.oaipmh.OaiPmhConstants.OAI_2_0_SCHEMA_LOCATION;
24 import static org.opencastproject.oaipmh.OaiPmhConstants.OAI_2_0_XML_NS;
25 import static org.opencastproject.oaipmh.OaiPmhUtil.toUtcSecond;
26 import static org.opencastproject.util.data.Option.none;
27 import static org.opencastproject.util.data.Option.some;
28
29 import org.opencastproject.mediapackage.EName;
30 import org.opencastproject.metadata.dublincore.DublinCore;
31 import org.opencastproject.metadata.dublincore.DublinCoreCatalog;
32 import org.opencastproject.metadata.dublincore.DublinCoreValue;
33 import org.opencastproject.oaipmh.OaiPmhConstants;
34 import org.opencastproject.oaipmh.persistence.OaiPmhDatabaseException;
35 import org.opencastproject.oaipmh.persistence.SearchResult;
36 import org.opencastproject.oaipmh.persistence.SearchResultItem;
37 import org.opencastproject.oaipmh.util.XmlGen;
38 import org.opencastproject.util.data.Function;
39 import org.opencastproject.util.data.Option;
40
41 import org.w3c.dom.Element;
42 import org.w3c.dom.Node;
43
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Collections;
47 import java.util.Date;
48 import java.util.List;
49
50 import javax.xml.XMLConstants;
51
52
53
54
55 public abstract class OaiXmlGen extends XmlGen {
56
57 protected OaiPmhRepository repository;
58
59
60
61
62 public OaiXmlGen(OaiPmhRepository repository) {
63 super(some(OaiPmhConstants.OAI_2_0_XML_NS));
64 this.repository = repository;
65 }
66
67
68
69
70 Element oai(Node... nodes) {
71 final List<Node> combined = new ArrayList<>();
72 combined.add(schemaLocation(OAI_2_0_SCHEMA_LOCATION));
73 combined.add($eTxt("responseDate", OAI_2_0_XML_NS, toUtcSecond(new Date())));
74 Collections.addAll(combined, nodes);
75 return $e("OAI-PMH",
76 Collections.singletonList(ns("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)),
77 combined);
78 }
79
80
81
82
83 Element dc(Node... nodes) {
84 List<Node> combined = new ArrayList<Node>(Arrays.asList(nodes));
85 combined.add(schemaLocation(OaiPmhConstants.OAI_DC_SCHEMA_LOCATION));
86 return $e("oai_dc:dc", OaiPmhConstants.OAI_DC_XML_NS,
87 Arrays.asList(ns("dc", "http://purl.org/dc/elements/1.1/"),
88 ns("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)),
89 combined);
90 }
91
92
93
94
95 @SuppressWarnings("unchecked") Element dc(final SearchResultItem item, Option<String> set) {
96 try {
97 return getDublincoreElement(item.getEpisodeDublinCore());
98 } catch (OaiPmhDatabaseException ex) {
99 return dc($e("dc:identifier", $txtBlank(item.getId())));
100 }
101 }
102
103
104
105
106 private Element getDublincoreElement(DublinCoreCatalog dc) {
107 List<Node> nodes = new ArrayList<Node>();
108 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_TITLE));
109 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_CREATOR));
110 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_SUBJECT));
111 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_DESCRIPTION));
112 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_PUBLISHER));
113 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_CONTRIBUTOR));
114 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_TYPE));
115 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_FORMAT));
116 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_IDENTIFIER));
117 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_SOURCE));
118 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_LANGUAGE));
119 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_RELATION));
120 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_COVERAGE));
121 nodes.addAll(getDublinCoreNodes(dc, DublinCore.PROPERTY_LICENSE));
122 return dc(nodes.toArray(new Node[nodes.size()]));
123 }
124
125 private List<Node> getDublinCoreNodes(DublinCoreCatalog dc, EName eName) {
126 List<Node> nodes = new ArrayList<Node>();
127
128 List<DublinCoreValue> values = dc.get(eName);
129 for (DublinCoreValue dcValue : values) {
130 Element element = $e("dc:" + eName.getLocalName(), $langNode(dcValue.getLanguage()), $txt(dcValue.getValue()));
131 nodes.add(element);
132 }
133 return nodes;
134 }
135
136
137
138
139 Node resumptionToken(final Option<String> resumptionToken, final String metadataPrefix, final SearchResult result,
140 Date until, Option<String> set) {
141
142 final Option<Option<String>> token;
143 if (result.size() == result.getLimit()) {
144 SearchResultItem lastResult = result.getItems().get((int) (result.size() - 1));
145
146 token = some(some(repository.saveQuery(new ResumableQuery(metadataPrefix, lastResult.getModificationDate(),
147 until, set))));
148 } else if (resumptionToken.isSome()) {
149
150 token = some(Option.<String>none());
151 } else {
152 token = none();
153 }
154
155 return token.map(new Function<Option<String>, Node>() {
156 @Override
157 public Node apply(Option<String> token) {
158 return $e("resumptionToken",
159
160
161 token.map(mkText).getOrElse(nodeZero));
162 }
163 }).getOrElse(nodeZero);
164 }
165
166
167
168
169 Element record(final SearchResultItem item, final Node metadata) {
170 if (item.isDeleted()) {
171 return $e("record", header(item));
172 } else {
173 return $e("record", header(item), $e("metadata", metadata));
174 }
175 }
176
177
178
179
180 Element metadataFormat(MetadataFormat f) {
181 return $e("metadataFormat", $eTxt("metadataPrefix", f.getPrefix()), $eTxt("schema", f.getSchema().toString()),
182 $eTxt("metadataNamespace", f.getNamespace().toString()));
183 }
184
185
186
187
188 Node metadataPrefixAttr(Params p) {
189 return $aSome("metadataPrefix", p.getMetadataPrefix());
190 }
191
192
193
194
195 Element header(final SearchResultItem item) {
196
197
198
199 Element header = $e("header",
200 $eTxt("identifier", item.getId()),
201 $eTxt("datestamp", repository.toSupportedGranularity(item.getModificationDate())));
202 if (item.isDeleted()) {
203 header.setAttribute("status", "deleted");
204 }
205 for (String setSpec: item.getSetSpecs()) {
206 header.appendChild($eTxt("setSpec", setSpec));
207 }
208 return header;
209 }
210
211
212
213
214 protected List<Node> merge(Node[] a, Node... b) {
215 List<Node> merge = new ArrayList<Node>(a.length + b.length);
216 java.util.Collections.addAll(merge, a);
217 java.util.Collections.addAll(merge, b);
218 return merge;
219 }
220 }