diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6270ca8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,54 @@ + + 4.0.0 + se.kb + oai4j + jar + 1.0 + oai4j + http://maven.apache.org + + + + junit + junit + 4.1 + test + + + org.oclc + oaiharvester2 + 0.1.10 + + + dom4j + dom4j + 1.6.1 + + + log4j + log4j + 1.2.14 + + + jaxen + jaxen + 1.1.1 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.0 + + 1.5 + 1.5 + + + + + + diff --git a/src/main/java/se/kb/oai/OAIException.java b/src/main/java/se/kb/oai/OAIException.java new file mode 100644 index 0000000..20835ed --- /dev/null +++ b/src/main/java/se/kb/oai/OAIException.java @@ -0,0 +1,34 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai; + +public class OAIException extends Exception { + + private static final long serialVersionUID = 5926653436917245659L; + + public OAIException() { + super(); + } + + public OAIException(Exception e) { + super(e); + } + +} diff --git a/src/main/java/se/kb/oai/ore/AggregateBase.java b/src/main/java/se/kb/oai/ore/AggregateBase.java new file mode 100644 index 0000000..2268c53 --- /dev/null +++ b/src/main/java/se/kb/oai/ore/AggregateBase.java @@ -0,0 +1,62 @@ +package se.kb.oai.ore; + +import java.net.URI; +import java.util.LinkedList; +import java.util.List; + +import org.dom4j.QName; + +public abstract class AggregateBase { + + protected URI id; + protected List types; + protected List metadata; + + public AggregateBase(URI id) { + this.id = id; + this.types = new LinkedList(); + this.metadata = new LinkedList(); + } + + public URI getId() { + return id; + } + + public void setId(URI id) { + this.id = id; + } + + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } + + public void addType(Type type) { + types.add(type); + } + + public List getMetadata() { + return metadata; + } + + public List getMetadata(QName name) { + List list = new LinkedList(); + for (Metadata meta : metadata) { + if (meta.getName().equals(name)) { + list.add(meta); + } + } + return list; + } + + public void setMetadata(List metadata) { + this.metadata = metadata; + } + + public void addMetadata(Metadata meta) { + metadata.add(meta); + } +} diff --git a/src/main/java/se/kb/oai/ore/AggregatedResource.java b/src/main/java/se/kb/oai/ore/AggregatedResource.java new file mode 100644 index 0000000..a127270 --- /dev/null +++ b/src/main/java/se/kb/oai/ore/AggregatedResource.java @@ -0,0 +1,34 @@ +package se.kb.oai.ore; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; + +public class AggregatedResource extends AggregateBase { + + public AggregatedResource(String id) throws URISyntaxException { + this(new URI(id)); + } + + public AggregatedResource(URI id) { + super(id); + } + + public InputStream getContent() throws IOException { + return id.toURL().openStream(); + } + public String getContentAsString() throws IOException { + InputStream in = getContent(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] bytes = new byte[4 * 1024]; + int read = in.read(bytes); + while (read != -1) { + out.write(bytes, 0, read); + read = in.read(bytes); + } + in.close(); + return new String(out.toByteArray()); + } +} diff --git a/src/main/java/se/kb/oai/ore/Aggregation.java b/src/main/java/se/kb/oai/ore/Aggregation.java new file mode 100644 index 0000000..901224e --- /dev/null +++ b/src/main/java/se/kb/oai/ore/Aggregation.java @@ -0,0 +1,53 @@ +package se.kb.oai.ore; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.LinkedList; +import java.util.List; + +public class Aggregation extends AggregateBase { + + private List resources; + + public Aggregation(String id) throws URISyntaxException { + this(new URI(id)); + } + + public Aggregation(URI id) { + super(id); + this.resources = new LinkedList(); + } + + public int numberOfResources() { + return resources.size(); + } + + public List getResources() { + return resources; + } + + public AggregatedResource getResource(int index) { + return resources.get(index); + } + + public AggregatedResource getResource(String id) throws URISyntaxException { + return getResource(new URI(id)); + } + + public AggregatedResource getResource(URI id) { + for (AggregatedResource resource : resources) { + if (resource.getId().equals(id)) { + return resource; + } + } + return null; + } + + public void setResources(List resources) { + this.resources = resources; + } + + public void addResource(AggregatedResource resource) { + resources.add(resource); + } +} diff --git a/src/main/java/se/kb/oai/ore/Metadata.java b/src/main/java/se/kb/oai/ore/Metadata.java new file mode 100644 index 0000000..46ea2ce --- /dev/null +++ b/src/main/java/se/kb/oai/ore/Metadata.java @@ -0,0 +1,40 @@ +package se.kb.oai.ore; + +import static se.kb.oai.ore.OREConstants.*; + +import org.dom4j.QName; + +public class Metadata { + + public enum Namespace { DC, DCTERMS } + + private QName qname; + private String value; + + public Metadata(Namespace ns, String name, String value) { + this.qname = getName(ns, name); + this.value = value; + } + + public QName getName() { + return qname; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public static QName getName(Namespace ns, String name) { + switch (ns) { + case DC: + return new QName(name, DC_NS); + case DCTERMS: + return new QName(name, DCTERMS_NS); + } + return null; + } +} diff --git a/src/main/java/se/kb/oai/ore/OREConstants.java b/src/main/java/se/kb/oai/ore/OREConstants.java new file mode 100644 index 0000000..5b7fbb7 --- /dev/null +++ b/src/main/java/se/kb/oai/ore/OREConstants.java @@ -0,0 +1,22 @@ +package se.kb.oai.ore; + +import org.dom4j.Namespace; + +public class OREConstants { + + public static final String ATOM_NS_PREFIX = "atom"; + public static final String ATOM_NS_URI = "http://www.w3.org/2005/Atom"; + public static final Namespace ATOM_NS = new Namespace(ATOM_NS_PREFIX, ATOM_NS_URI); + + public static final String DC_NS_PREFIX = "dc"; + public static final String DC_NS_URI = "http://purl.org/dc/"; + public static final Namespace DC_NS = new Namespace(DC_NS_PREFIX, DC_NS_URI); + + public static final String DCTERMS_NS_PREFIX = "dcterms"; + public static final String DCTERMS_NS_URI = "http://purl.org/dc/terms/"; + public static final Namespace DCTERMS_NS = new Namespace(DCTERMS_NS_PREFIX, DCTERMS_NS_URI); + + public static final String RDF_NS_PREFIX = "rdf"; + public static final String RDF_NS_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + public static final Namespace RDF_NS = new Namespace(RDF_NS_PREFIX, RDF_NS_URI); +} diff --git a/src/main/java/se/kb/oai/ore/ResourceMap.java b/src/main/java/se/kb/oai/ore/ResourceMap.java new file mode 100644 index 0000000..b82eae3 --- /dev/null +++ b/src/main/java/se/kb/oai/ore/ResourceMap.java @@ -0,0 +1,72 @@ +package se.kb.oai.ore; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Date; + +public class ResourceMap { + + private URI id; + private String creator; + private String rights; + private Date created; + private Date modified; + private Aggregation aggregation; + + public ResourceMap(String id) throws URISyntaxException { + this(new URI(id)); + } + + public ResourceMap(URI id) { + this.id = id; + this.aggregation = new Aggregation(id.resolve("#aggregation")); + } + + public URI getId() { + return id; + } + + public void setId(URI id) { + this.id = id; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public String getRights() { + return rights; + } + + public void setRights(String rights) { + this.rights = rights; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getModified() { + return modified; + } + + public void setModified(Date modified) { + this.modified = modified; + } + + public Aggregation getAggregation() { + return aggregation; + } + + public void setAggregation(Aggregation aggregation) { + this.aggregation = aggregation; + } +} diff --git a/src/main/java/se/kb/oai/ore/ResourceMapFactory.java b/src/main/java/se/kb/oai/ore/ResourceMapFactory.java new file mode 100644 index 0000000..ad448d9 --- /dev/null +++ b/src/main/java/se/kb/oai/ore/ResourceMapFactory.java @@ -0,0 +1,22 @@ +package se.kb.oai.ore; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +import org.dom4j.Element; + +import se.kb.oai.OAIException; + +public interface ResourceMapFactory { + + public ResourceMap newResourceMap(String uri) throws URISyntaxException; + + public ResourceMap newResourceMap(URI uri); + + public ResourceMap getResourceMap(URL url) throws OAIException; + + public ResourceMap getResourceMap(String url) throws OAIException; + + public ResourceMap getResourceMap(Element root) throws OAIException; +} diff --git a/src/main/java/se/kb/oai/ore/ResourceMapSerializer.java b/src/main/java/se/kb/oai/ore/ResourceMapSerializer.java new file mode 100644 index 0000000..4d33a4a --- /dev/null +++ b/src/main/java/se/kb/oai/ore/ResourceMapSerializer.java @@ -0,0 +1,15 @@ +package se.kb.oai.ore; + +import java.io.File; +import java.io.IOException; + +import org.dom4j.Element; + +public interface ResourceMapSerializer { + + public void serializeToFile(File file, ResourceMap map) throws IOException; + + public String serializeToString(ResourceMap map) throws IOException; + + public Element serializeToXml(ResourceMap map); +} diff --git a/src/main/java/se/kb/oai/ore/Type.java b/src/main/java/se/kb/oai/ore/Type.java new file mode 100644 index 0000000..4361d43 --- /dev/null +++ b/src/main/java/se/kb/oai/ore/Type.java @@ -0,0 +1,14 @@ +package se.kb.oai.ore; + +public class Type { + + private String value; + + public Type(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/se/kb/oai/ore/impl/AtomConstants.java b/src/main/java/se/kb/oai/ore/impl/AtomConstants.java new file mode 100644 index 0000000..2c6accc --- /dev/null +++ b/src/main/java/se/kb/oai/ore/impl/AtomConstants.java @@ -0,0 +1,47 @@ +package se.kb.oai.ore.impl; + +import java.text.SimpleDateFormat; + +import org.dom4j.QName; + +import se.kb.oai.ore.OREConstants; + +public class AtomConstants extends OREConstants { + + public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + + public static final String COLON = ":"; + public static final String SLASH = "/"; + + public static final QName FEED = new QName("feed", ATOM_NS); + public static final QName ID = new QName("id", ATOM_NS); + public static final QName LINK = new QName("link", ATOM_NS); + public static final QName TITLE = new QName("title", ATOM_NS); + public static final QName AUTHOR = new QName("author", ATOM_NS); + public static final QName NAME = new QName("name", ATOM_NS); + public static final QName RIGHTS = new QName("rights", ATOM_NS); + public static final QName PUBLISHED = new QName("published", ATOM_NS); + public static final QName UPDATED = new QName("updated", ATOM_NS); + public static final QName CATEGORY = new QName("category", ATOM_NS); + public static final QName ICON = new QName("icon", ATOM_NS); + public static final QName ENTRY = new QName("entry", ATOM_NS); + public static final QName TYPE = new QName("type", RDF_NS); + + public static final String SCHEME = "scheme"; + public static final String TERM = "term"; + public static final String LABEL = "label"; + public static final String REL = "rel"; + public static final String HREF = "href"; + + public static final String ORE_TERMS_URL = "http://www.openarchives.org/ore/terms/"; + public static final String ORE_TERMS_REM_URL = "http://www.openarchives.org/ore/terms/ResourceMap"; + public static final String ICON_URL = "http://www.openarchives.org/ore/logos/ore_icon.png"; + + public static final String ID_XPATH = ATOM_NS_PREFIX + COLON + LINK.getName() + "[@rel='self']/@href"; + public static final String CREATOR_XPATH = ATOM_NS_PREFIX + COLON + AUTHOR.getName() + SLASH + ATOM_NS_PREFIX + COLON + NAME.getName(); + public static final String MODIFIED_XPATH = ATOM_NS_PREFIX + COLON + UPDATED.getName(); + public static final String CREATED_XPATH = ATOM_NS_PREFIX + COLON + PUBLISHED.getName(); + public static final String RIGHTS_XPATH = ATOM_NS_PREFIX + COLON + RIGHTS.getName(); + public static final String ENTRY_XPATH = ATOM_NS_PREFIX + COLON + ENTRY.getName(); + public static final String ENTRY_ID_XPATH = ATOM_NS_PREFIX + COLON + LINK.getName() + "[@rel='alternate']/@href"; +} diff --git a/src/main/java/se/kb/oai/ore/impl/AtomFactory.java b/src/main/java/se/kb/oai/ore/impl/AtomFactory.java new file mode 100644 index 0000000..e495b48 --- /dev/null +++ b/src/main/java/se/kb/oai/ore/impl/AtomFactory.java @@ -0,0 +1,88 @@ +package se.kb.oai.ore.impl; + +import java.util.List; + +import org.dom4j.Element; +import org.dom4j.Node; + +import se.kb.oai.OAIException; +import se.kb.oai.ore.AggregateBase; +import se.kb.oai.ore.AggregatedResource; +import se.kb.oai.ore.Metadata; +import se.kb.oai.ore.Metadata.Namespace; +import se.kb.oai.ore.ResourceMap; +import se.kb.oai.ore.Type; +import se.kb.xml.XPathWrapper; + +import static se.kb.oai.ore.OREConstants.ATOM_NS_PREFIX; +import static se.kb.oai.ore.OREConstants.ATOM_NS_URI; +import static se.kb.oai.ore.OREConstants.DCTERMS_NS_PREFIX; +import static se.kb.oai.ore.OREConstants.DCTERMS_NS_URI; +import static se.kb.oai.ore.OREConstants.DC_NS_PREFIX; +import static se.kb.oai.ore.OREConstants.DC_NS_URI; +import static se.kb.oai.ore.OREConstants.RDF_NS_PREFIX; +import static se.kb.oai.ore.OREConstants.RDF_NS_URI; +import static se.kb.oai.ore.impl.AtomConstants.*; + +public class AtomFactory extends FactoryBase { + + @Override + public ResourceMap getResourceMap(Element feed) throws OAIException { + try { + XPathWrapper xpath = createXPath(feed); + + ResourceMap map = new ResourceMap(xpath.valueOf(ID_XPATH)); + map.setCreator(xpath.valueOf(CREATOR_XPATH)); + map.setModified(DATE_FORMAT.parse(xpath.valueOf(MODIFIED_XPATH))); + + String rights = xpath.valueOf(RIGHTS_XPATH); + if (notEmpty(rights)) + map.setRights(rights); + + String created = xpath.valueOf(CREATED_XPATH); + if (notEmpty(created)) + map.setCreated(DATE_FORMAT.parse(created)); + + addTypesAndMetadata(map.getAggregation(), xpath.selectNodes("*")); + + for (Node node : xpath.selectNodes(ENTRY_XPATH)) { + xpath = createXPath(node); + AggregatedResource resource = new AggregatedResource(xpath.valueOf(ENTRY_ID_XPATH)); + addTypesAndMetadata(resource, xpath.selectNodes("*")); + map.getAggregation().addResource(resource); + } + + return map; + } catch (Exception e) { + throw new OAIException(e); + } + } + + private void addTypesAndMetadata(AggregateBase aggregate, List nodes) { + for (Node node : nodes) { + Element element = (Element) node; + if (element.getNamespace().equals(DC_NS)) { + aggregate.addMetadata((new Metadata(Namespace.DC, element.getName(), element.getText()))); + } + else if (element.getNamespace().equals(DCTERMS_NS)) { + aggregate.addMetadata((new Metadata(Namespace.DCTERMS, element.getName(), element.getText()))); + } + else if (element.getNamespace().equals(RDF_NS) && element.getName().equals("type")) { + aggregate.addType(new Type(element.getText())); + } + } + } + + private XPathWrapper createXPath(Node node) { + XPathWrapper xpath = new XPathWrapper(node); + xpath.addNamespace(ATOM_NS_PREFIX, ATOM_NS_URI); + xpath.addNamespace(RDF_NS_PREFIX, RDF_NS_URI); + xpath.addNamespace(DC_NS_PREFIX, DC_NS_URI); + xpath.addNamespace(DCTERMS_NS_PREFIX, DCTERMS_NS_URI); + return xpath; + } + + private boolean notEmpty(String string) { + return (string != null && string.trim().length() > 0); + } +} diff --git a/src/main/java/se/kb/oai/ore/impl/AtomSerializer.java b/src/main/java/se/kb/oai/ore/impl/AtomSerializer.java new file mode 100644 index 0000000..82c30f0 --- /dev/null +++ b/src/main/java/se/kb/oai/ore/impl/AtomSerializer.java @@ -0,0 +1,127 @@ +package se.kb.oai.ore.impl; + +import java.util.List; + +import org.dom4j.DocumentHelper; +import org.dom4j.Element; + +import se.kb.oai.ore.AggregatedResource; +import se.kb.oai.ore.Metadata; +import se.kb.oai.ore.ResourceMap; +import se.kb.oai.ore.Type; + +import static se.kb.oai.ore.impl.AtomConstants.*; + +public class AtomSerializer extends SerializerBase { + + @Override + public Element serializeToXml(ResourceMap map) { + Element feed = DocumentHelper.createElement(FEED); + feed.addNamespace(ATOM_NS_PREFIX, ATOM_NS_URI); + feed.addNamespace(RDF_NS_PREFIX, RDF_NS_URI); + feed.addNamespace(DC_NS_PREFIX, DC_NS_URI); + feed.addNamespace(DCTERMS_NS_PREFIX, DCTERMS_NS_URI); + + Element id = DocumentHelper.createElement(ID); + id.setText(createAtomId()); + feed.add(id); + + Element link = DocumentHelper.createElement(LINK); + link.addAttribute(REL, "self"); + link.addAttribute("type", "application/atom+xml"); + link.addAttribute(HREF, map.getId().toString()); + feed.add(link); + + Element title = DocumentHelper.createElement(TITLE); + title.setText("Resource Map " + map.getId().toString()); + feed.add(title); + + Element author = DocumentHelper.createElement(AUTHOR); + Element name = DocumentHelper.createElement(NAME); + name.setText(map.getCreator()); + author.add(name); + feed.add(author); + + if (map.getRights() != null) { + Element rights = DocumentHelper.createElement(RIGHTS); + rights.setText(map.getRights()); + feed.add(rights); + } + + if (map.getCreated() != null) { + Element published = DocumentHelper.createElement(PUBLISHED); + published.setText(DATE_FORMAT.format(map.getCreated())); + feed.add(published); + } + + Element updated = DocumentHelper.createElement(UPDATED); + updated.setText(DATE_FORMAT.format(map.getModified())); + feed.add(updated); + + Element category = DocumentHelper.createElement(CATEGORY); + category.addAttribute(SCHEME, ORE_TERMS_URL); + category.addAttribute(TERM, ORE_TERMS_REM_URL); + category.addAttribute(LABEL, "Resource Map"); + feed.add(category); + + Element icon = DocumentHelper.createElement(ICON); + icon.setText(ICON_URL); + feed.add(icon); + + link = DocumentHelper.createElement(LINK); + link.addAttribute(REL, "describes"); + link.addAttribute(HREF, map.getAggregation().getId().toString()); + feed.add(link); + + addTypes(feed, map.getAggregation().getTypes()); + addMetadata(feed, map.getAggregation().getMetadata()); + + for (AggregatedResource resource : map.getAggregation().getResources()) { + Element entry = DocumentHelper.createElement(ENTRY); + + id = DocumentHelper.createElement(ID); + id.setText(createAtomId()); + entry.add(id); + + title = DocumentHelper.createElement(TITLE); + title.setText("Aggregated Resource " + resource.getId().toString()); + entry.add(title); + + updated = DocumentHelper.createElement(UPDATED); + updated.setText(DATE_FORMAT.format(map.getModified())); + entry.add(updated); + + link = DocumentHelper.createElement(LINK); + link.addAttribute(REL, "alternate"); + link.addAttribute(HREF, resource.getId().toString()); + entry.add(link); + + addTypes(entry, resource.getTypes()); + addMetadata(entry, resource.getMetadata()); + + feed.add(entry); + } + + return feed; + } + + private void addTypes(Element target, List list) { + for (Type type : list) { + Element element = DocumentHelper.createElement(TYPE); + element.setText(type.getValue()); + target.add(element); + } + } + + private void addMetadata(Element target, List list) { + for (Metadata metadata : list) { + Element element = DocumentHelper.createElement(metadata.getName()); + element.setText(metadata.getValue()); + target.add(element); + } + } + + protected String createAtomId() { + return "urn:uid:" + (int) (Math.random() * 1000); + } +} diff --git a/src/main/java/se/kb/oai/ore/impl/FactoryBase.java b/src/main/java/se/kb/oai/ore/impl/FactoryBase.java new file mode 100644 index 0000000..b2ca50e --- /dev/null +++ b/src/main/java/se/kb/oai/ore/impl/FactoryBase.java @@ -0,0 +1,44 @@ +package se.kb.oai.ore.impl; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +import org.dom4j.Document; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; + +import se.kb.oai.OAIException; +import se.kb.oai.ore.ResourceMap; +import se.kb.oai.ore.ResourceMapFactory; + +public abstract class FactoryBase implements ResourceMapFactory { + + public ResourceMap newResourceMap(String uri) throws URISyntaxException { + return new ResourceMap(uri); + } + + public ResourceMap newResourceMap(URI uri) { + return new ResourceMap(uri); + } + + public ResourceMap getResourceMap(URL url) throws OAIException { + try { + SAXReader reader = new SAXReader(); + Document document = reader.read(url); + return getResourceMap(document.getRootElement()); + } catch (Exception e) { + throw new OAIException(e); + } + } + + public ResourceMap getResourceMap(String url) throws OAIException { + try { + return getResourceMap(new URL(url)); + } catch (Exception e) { + throw new OAIException(e); + } + } + + public abstract ResourceMap getResourceMap(Element root) throws OAIException; +} \ No newline at end of file diff --git a/src/main/java/se/kb/oai/ore/impl/SerializerBase.java b/src/main/java/se/kb/oai/ore/impl/SerializerBase.java new file mode 100644 index 0000000..95896e2 --- /dev/null +++ b/src/main/java/se/kb/oai/ore/impl/SerializerBase.java @@ -0,0 +1,26 @@ +package se.kb.oai.ore.impl; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import org.dom4j.Element; + +import se.kb.oai.ore.ResourceMap; +import se.kb.oai.ore.ResourceMapSerializer; +import se.kb.xml.XMLUtils; + +public abstract class SerializerBase implements ResourceMapSerializer { + + public void serializeToFile(File file, ResourceMap map) throws IOException { + FileOutputStream out = new FileOutputStream(file); + XMLUtils.writeXmlTo(serializeToXml(map), out); + out.close(); + } + + public String serializeToString(ResourceMap map) throws IOException { + return XMLUtils.xmlToString(serializeToXml(map)); + } + + public abstract Element serializeToXml(ResourceMap map); +} diff --git a/src/main/java/se/kb/oai/pmh/Header.java b/src/main/java/se/kb/oai/pmh/Header.java new file mode 100644 index 0000000..8db4326 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/Header.java @@ -0,0 +1,65 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + + +import static se.kb.oai.pmh.ResponseBase.*; + +import java.util.List; +import java.util.LinkedList; + +import org.dom4j.Node; + +import se.kb.xml.XPathWrapper; + +public class Header { + + private static final String IDENTIFIER_XPATH = "oai:identifier"; + private static final String DATESTAMP_XPATH = "oai:datestamp"; + private static final String SETSPEC_XPATH = "oai:setSpec"; + + private String identifier; + private String datestamp; + private List setSpecs; + + public Header(Node node) { + XPathWrapper xpath = new XPathWrapper(node); + xpath.addNamespace(OAI_NS_PREFIX, OAI_NS_URI); + + this.identifier = xpath.valueOf(IDENTIFIER_XPATH); + this.datestamp = xpath.valueOf(DATESTAMP_XPATH); + this.setSpecs = new LinkedList(); + for(Node spec : xpath.selectNodes(SETSPEC_XPATH)) { + setSpecs.add(spec.getText()); + } + } + + public String getIdentifier() { + return identifier; + } + + public String getDatestamp() { + return datestamp; + } + + public List getSetSpecs() { + return setSpecs; + } +} diff --git a/src/main/java/se/kb/oai/pmh/Identification.java b/src/main/java/se/kb/oai/pmh/Identification.java new file mode 100644 index 0000000..325360f --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/Identification.java @@ -0,0 +1,108 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + +import java.util.LinkedList; +import java.util.List; + +import org.dom4j.Element; +import org.dom4j.Node; +import org.w3c.dom.Document; + +public class Identification extends ResponseBase { + + private static final String REPOSITORYNAME_XPATH = "oai:Identify/oai:repositoryName"; + private static final String BASEURL_XPATH = "oai:Identify/oai:baseURL"; + private static final String PROTOCOLVERSION_XPATH = "oai:Identify/oai:protocolVersion"; + private static final String EARLIESTDATESTAMP_XPATH = "oai:Identify/oai:earliestDatestamp"; + private static final String DELETEDRECORD_XPATH = "oai:Identify/oai:deletedRecord"; + private static final String GRANULARITY_XPATH = "oai:Identify/oai:granularity"; + private static final String COMPRESSION_XPATH = "oai:Identify/oai:compression"; + private static final String DESCRIPTION_XPATH = "oai:Identify/oai:description/*"; + private static final String ADMINEMAIL_XPATH = "oai:Identify/oai:adminEmail"; + + private String repositoryName; + private String baseUrl; + private String protocolVersion; + private String earliestDatestamp; + private String deletedRecord; + private String granularity; + private String compression; + private List descriptions; + private List adminEmails; + + public Identification(Document document) throws PMHErrorResponseException { + super(document); + + this.repositoryName = xpath.valueOf(REPOSITORYNAME_XPATH); + this.baseUrl = xpath.valueOf(BASEURL_XPATH); + this.protocolVersion = xpath.valueOf(PROTOCOLVERSION_XPATH); + this.earliestDatestamp = xpath.valueOf(EARLIESTDATESTAMP_XPATH); + this.deletedRecord = xpath.valueOf(DELETEDRECORD_XPATH); + this.granularity = xpath.valueOf(GRANULARITY_XPATH); + this.compression = xpath.valueOf(COMPRESSION_XPATH); + + this.descriptions = new LinkedList(); + for (Node description: xpath.selectNodes(DESCRIPTION_XPATH)) { + descriptions.add((Element) description); + } + + this.adminEmails = new LinkedList(); + for(Node adminEmail : xpath.selectNodes(ADMINEMAIL_XPATH)) { + adminEmails.add(adminEmail.getText()); + } + } + + public List getAdminEmails() { + return adminEmails; + } + + public String getBaseUrl() { + return baseUrl; + } + + public String getCompression() { + return compression; + } + + public String getDeletedRecord() { + return deletedRecord; + } + + public List getDescriptions() { + return descriptions; + } + + public String getEarliestDatestamp() { + return earliestDatestamp; + } + + public String getGranularity() { + return granularity; + } + + public String getProtocolVersion() { + return protocolVersion; + } + + public String getRepositoryName() { + return repositoryName; + } +} diff --git a/src/main/java/se/kb/oai/pmh/IdentifiersList.java b/src/main/java/se/kb/oai/pmh/IdentifiersList.java new file mode 100644 index 0000000..bd32c95 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/IdentifiersList.java @@ -0,0 +1,40 @@ +package se.kb.oai.pmh; + +import java.util.LinkedList; +import java.util.List; + +import org.dom4j.Node; +import org.w3c.dom.Document; + +public class IdentifiersList extends ResponseBase { + + private static final String HEADER_XPATH = "oai:ListIdentifiers/oai:header"; + + private List
headers; + + public IdentifiersList(Document document) throws PMHErrorResponseException { + super(document); + + this.headers = new LinkedList
(); + for(Node node : xpath.selectNodes(HEADER_XPATH)) { + headers.add(new Header(node)); + } + } + + public int size() { + return headers.size(); + } + + public List
asList() { + return headers; + } + + public ResumptionToken getResumptionToken() { + if (super.resumptionToken == null + || super.resumptionToken.getId() == null + || super.resumptionToken.getId().length() == 0) + return null; + + return super.resumptionToken; + } +} diff --git a/src/main/java/se/kb/oai/pmh/MetadataFormat.java b/src/main/java/se/kb/oai/pmh/MetadataFormat.java new file mode 100644 index 0000000..d8a7792 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/MetadataFormat.java @@ -0,0 +1,58 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + +import static se.kb.oai.pmh.ResponseBase.*; + +import org.dom4j.Node; + +import se.kb.xml.XPathWrapper; + +public class MetadataFormat { + + private static final String PREFIX_XPATH = "oai:metadataPrefix"; + private static final String SCHEMA_XPATH = "oai:schema"; + private static final String NAMESPACE_XPATH = "oai:metadataNamespace"; + + private String prefix; + private String schema; + private String namespace; + + public MetadataFormat(Node node) { + XPathWrapper xpath = new XPathWrapper(node); + xpath.addNamespace(OAI_NS_PREFIX, OAI_NS_URI); + + this.prefix = xpath.valueOf(PREFIX_XPATH); + this.schema = xpath.valueOf(SCHEMA_XPATH); + this.namespace = xpath.valueOf(NAMESPACE_XPATH); + } + + public String getPrefix() { + return prefix; + } + + public String getSchema() { + return schema; + } + + public String getNamespace() { + return namespace; + } +} diff --git a/src/main/java/se/kb/oai/pmh/MetadataFormatsList.java b/src/main/java/se/kb/oai/pmh/MetadataFormatsList.java new file mode 100644 index 0000000..95f7443 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/MetadataFormatsList.java @@ -0,0 +1,50 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + +import java.util.LinkedList; +import java.util.List; + +import org.dom4j.Node; +import org.w3c.dom.Document; + +public class MetadataFormatsList extends ResponseBase { + + private static final String METADATAFORMAT_XPATH = "oai:ListMetadataFormats/oai:metadataFormat"; + + private List metadataFormats; + + public MetadataFormatsList(Document document) throws PMHErrorResponseException { + super(document); + + this.metadataFormats = new LinkedList(); + for(Node metadataFormat : xpath.selectNodes(METADATAFORMAT_XPATH)) { + metadataFormats.add(new MetadataFormat(metadataFormat)); + } + } + + public int size() { + return metadataFormats.size(); + } + + public List asList() { + return metadataFormats; + } +} diff --git a/src/main/java/se/kb/oai/pmh/OaiPmhServer.java b/src/main/java/se/kb/oai/pmh/OaiPmhServer.java new file mode 100644 index 0000000..5c514b5 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/OaiPmhServer.java @@ -0,0 +1,148 @@ +package se.kb.oai.pmh; + +import java.net.URL; + +import se.kb.oai.OAIException; + +import ORG.oclc.oai.harvester2.verb.GetRecord; +import ORG.oclc.oai.harvester2.verb.Identify; +import ORG.oclc.oai.harvester2.verb.ListIdentifiers; +import ORG.oclc.oai.harvester2.verb.ListMetadataFormats; +import ORG.oclc.oai.harvester2.verb.ListRecords; +import ORG.oclc.oai.harvester2.verb.ListSets; + +/** + * Class that acts as a facade for an OAI-PMH server. + * + * Has methods that corresponds to the different verbs in the OAI-PMH + * specification and that will return appropriate objects based on + * the response. + * + * @author oskar + */ +public class OaiPmhServer { + + private String baseurl; + + /** + * Creates an OaiPmhServer with the given base URL. + * + * @param url Base URL that points to an OAI-PMH server. + */ + public OaiPmhServer(String url) { + this.baseurl = url; + } + + /** + * Creates an OaiPmhServer with the given base URL. + * + * @param url Base URL that points to an OAI-PMH server. + */ + public OaiPmhServer(URL url) { + this(url.toString()); + } + + public String getBaseUrl() { + return baseurl; + } + + public Record getRecord(String identifier, String metadataPrefix) throws OAIException { + try { + GetRecord getRecord = new GetRecord(baseurl, identifier, metadataPrefix); + return new Record(getRecord.getDocument()); + } catch (PMHErrorResponseException e) { + throw e; + } catch (Exception e) { + throw new OAIException(e); + } + } + + public Identification identify() throws OAIException { + try { + Identify identify = new Identify(baseurl); + return new Identification(identify.getDocument()); + } catch (PMHErrorResponseException e) { + throw e; + } catch (Exception e) { + throw new OAIException(e); + } + } + + public IdentifiersList listIdentifiers(String metadataPrefix) throws OAIException { + return listIdentifiers(null, null, null, metadataPrefix); + } + + public IdentifiersList listIdentifiers(String from, String until, String set, String metadataPrefix) throws OAIException { + try { + ListIdentifiers list = new ListIdentifiers(baseurl, from, until, set, metadataPrefix); + return new IdentifiersList(list.getDocument()); + } catch (PMHErrorResponseException e) { + throw e; + } catch (Exception e) { + throw new OAIException(e); + } + } + + public IdentifiersList listIdentifiers(ResumptionToken resumptionToken) throws OAIException { + try { + ListIdentifiers list = new ListIdentifiers(baseurl, resumptionToken.getId()); + return new IdentifiersList(list.getDocument()); + } catch (PMHErrorResponseException e) { + throw e; + } catch (Exception e) { + throw new OAIException(e); + } + } + + public RecordsList listRecords(String metadataPrefix) throws OAIException { + return listRecords(null, null, null, metadataPrefix); + } + + public RecordsList listRecords(String from, String until, String set, String metadataPrefix) throws OAIException { + try { + ListRecords list = new ListRecords(baseurl, from, until, set, metadataPrefix); + return new RecordsList(list.getDocument()); + } catch (PMHErrorResponseException e) { + throw e; + } catch (Exception e) { + throw new OAIException(e); + } + } + + public RecordsList listRecords(ResumptionToken resumptionToken) throws OAIException { + try { + ListRecords list = new ListRecords(baseurl, resumptionToken.getId()); + return new RecordsList(list.getDocument()); + } catch (PMHErrorResponseException e) { + throw e; + } catch (Exception e) { + throw new OAIException(e); + } + } + + public MetadataFormatsList listMetadataFormats() throws OAIException { + return listMetadataFormats(null); + } + + public MetadataFormatsList listMetadataFormats(String identifier) throws OAIException { + try { + ListMetadataFormats list = new ListMetadataFormats(baseurl, identifier); + return new MetadataFormatsList(list.getDocument()); + } catch (PMHErrorResponseException e) { + throw e; + } catch (Exception e) { + throw new OAIException(e); + } + } + + public SetsList listSets() throws OAIException { + try { + ListSets list = new ListSets(baseurl); + return new SetsList(list.getDocument()); + } catch (PMHErrorResponseException e) { + throw e; + } catch (Exception e) { + throw new OAIException(e); + } + } +} diff --git a/src/main/java/se/kb/oai/pmh/PMHErrorResponseException.java b/src/main/java/se/kb/oai/pmh/PMHErrorResponseException.java new file mode 100644 index 0000000..4f0ca02 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/PMHErrorResponseException.java @@ -0,0 +1,34 @@ +package se.kb.oai.pmh; + +import se.kb.oai.OAIException; + +public class PMHErrorResponseException extends OAIException { + + private static final long serialVersionUID = -2010182612617642664L; + + public static final String BAD_ARGUMENT = "badArgument"; + public static final String BAD_RESUMPTION_TOKEN = "badResumptionToken"; + public static final String BAD_VERB = "badVerb"; + public static final String CANNOT_DISSEMINATE_FORMAT = "cannotDisseminateFormat"; + public static final String ID_DOES_NOT_EXIST = "idDoesNotExist"; + public static final String NO_RECORDS_MATCH = "noRecordsMatch"; + public static final String NO_METADATA_FORMATS = "noMetadataFormats"; + public static final String NO_SET_HIERARCHY = "noSetHierarchy"; + + private String code; + private String message; + + public PMHErrorResponseException(String code, String message) { + super(); + this.code = code; + this.message = message; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/se/kb/oai/pmh/Record.java b/src/main/java/se/kb/oai/pmh/Record.java new file mode 100644 index 0000000..11758cb --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/Record.java @@ -0,0 +1,76 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + +import java.io.IOException; + +import org.dom4j.Element; +import org.dom4j.Node; +import org.w3c.dom.Document; + +import se.kb.xml.XMLUtils; +import se.kb.xml.XPathWrapper; + +public class Record extends ResponseBase { + + private static final String RECORD_XPATH = "oai:GetRecord/oai:record"; + private static final String HEADER_XPATH = "oai:header"; + private static final String METADATA_XPATH = "oai:metadata/*"; + private static final String ABOUT_XPATH = "oai:about/*"; + + private Header header; + private Element metadata; + private Element about; + + public Record(Document document) throws PMHErrorResponseException { + this(document, null); + } + + public Record(Document document, Node record) throws PMHErrorResponseException { + super(document); + + if (record == null) + this.xpath = new XPathWrapper(xpath.selectSingleNode(RECORD_XPATH)); + else + this.xpath = new XPathWrapper(record); + xpath.addNamespace(OAI_NS_PREFIX, OAI_NS_URI); + + Node headerNode = xpath.selectSingleNode(HEADER_XPATH); + this.header = new Header(headerNode); + this.metadata = xpath.selectSingleElement(METADATA_XPATH); + this.about = xpath.selectSingleElement(ABOUT_XPATH); + } + + public Header getHeader() { + return header; + } + + public Element getMetadata() { + return metadata; + } + + public String getMetadataAsString() throws IOException { + return XMLUtils.xmlToString(getMetadata()); + } + + public Element getAbout() { + return about; + } +} diff --git a/src/main/java/se/kb/oai/pmh/RecordsList.java b/src/main/java/se/kb/oai/pmh/RecordsList.java new file mode 100644 index 0000000..c7978b5 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/RecordsList.java @@ -0,0 +1,59 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + +import java.util.LinkedList; +import java.util.List; + +import org.dom4j.Node; +import org.w3c.dom.Document; + +public class RecordsList extends ResponseBase { + + private static final String RECORD_XPATH = "oai:ListRecords/oai:record"; + + private List records; + + public RecordsList(Document document) throws PMHErrorResponseException { + super(document); + + this.records = new LinkedList(); + for (Node record : xpath.selectNodes(RECORD_XPATH)) { + records.add(new Record(document, record)); + } + } + + public int size() { + return records.size(); + } + + public List asList() { + return records; + } + + public ResumptionToken getResumptionToken() { + if (super.resumptionToken == null + || super.resumptionToken.getId() == null + || super.resumptionToken.getId().length() == 0) + return null; + + return super.resumptionToken; + } +} diff --git a/src/main/java/se/kb/oai/pmh/ResponseBase.java b/src/main/java/se/kb/oai/pmh/ResponseBase.java new file mode 100644 index 0000000..ba895a3 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/ResponseBase.java @@ -0,0 +1,68 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + +import org.dom4j.Element; +import org.dom4j.io.DOMReader; +import org.w3c.dom.Document; + +import se.kb.xml.XPathWrapper; + +public abstract class ResponseBase { + + public static final String OAI_NS_PREFIX = "oai"; + public static final String OAI_NS_URI = "http://www.openarchives.org/OAI/2.0/"; + + private static final String RESPONSEDATE_XPATH = "oai:responseDate"; + private static final String RESUMPTIONTOKEN_XPATH = "*/oai:resumptionToken"; + private static final String ERROR_XPATH = "oai:error"; + + + protected Document response; + protected XPathWrapper xpath; + protected String responseDate; + protected ResumptionToken resumptionToken; + + public ResponseBase(Document document) throws PMHErrorResponseException { + DOMReader reader = new DOMReader(); + Element root = reader.read(document).getRootElement(); + + this.xpath = new XPathWrapper(root); + xpath.addNamespace(OAI_NS_PREFIX, OAI_NS_URI); + this.response = document; + this.responseDate = xpath.valueOf(RESPONSEDATE_XPATH); + + Element token = xpath.selectSingleElement(RESUMPTIONTOKEN_XPATH); + this.resumptionToken = token != null ? new ResumptionToken(token) : null; + + Element error = xpath.selectSingleElement(ERROR_XPATH); + if (error != null) { + throw new PMHErrorResponseException(error.attributeValue("code"), error.getTextTrim()); + } + } + + public Document getResponse() { + return response; + } + + public String getResponseDate() { + return responseDate; + } +} diff --git a/src/main/java/se/kb/oai/pmh/ResumptionToken.java b/src/main/java/se/kb/oai/pmh/ResumptionToken.java new file mode 100644 index 0000000..d550442 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/ResumptionToken.java @@ -0,0 +1,41 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + +import org.dom4j.Element; + +public class ResumptionToken { + + private String id; + private String expirationDate; + + public ResumptionToken(Element element) { + this.id = element.getTextTrim(); + this.expirationDate = element.attributeValue("expirationDate"); + } + + public String getId() { + return id; + } + + public String getExpirationDate() { + return expirationDate; + } +} diff --git a/src/main/java/se/kb/oai/pmh/Set.java b/src/main/java/se/kb/oai/pmh/Set.java new file mode 100644 index 0000000..f9e88b8 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/Set.java @@ -0,0 +1,65 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + +import static se.kb.oai.pmh.ResponseBase.*; + +import java.util.LinkedList; +import java.util.List; + +import org.dom4j.Element; +import org.dom4j.Node; + +import se.kb.xml.XPathWrapper; + +public class Set { + + private static final String SPEC_XPATH = "oai:setSpec"; + private static final String NAME_XPATH = "oai:setName"; + private static final String DESCRIPTION_XPATH = "oai:setDescription/*"; + + private String spec; + private String name; + private List descriptions; + + public Set(Node node) { + XPathWrapper xpath = new XPathWrapper(node); + xpath.addNamespace(OAI_NS_PREFIX, OAI_NS_URI); + + this.spec = xpath.valueOf(SPEC_XPATH); + this.name = xpath.valueOf(NAME_XPATH); + this.descriptions = new LinkedList(); + for (Node description : xpath.selectNodes(DESCRIPTION_XPATH)) { + descriptions.add((Element) description); + } + } + + public String getSpec() { + return spec; + } + + public String getName() { + return name; + } + + public List getDescriptions() { + return descriptions; + } +} diff --git a/src/main/java/se/kb/oai/pmh/SetsList.java b/src/main/java/se/kb/oai/pmh/SetsList.java new file mode 100644 index 0000000..4a927f1 --- /dev/null +++ b/src/main/java/se/kb/oai/pmh/SetsList.java @@ -0,0 +1,50 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.oai.pmh; + +import java.util.LinkedList; +import java.util.List; + +import org.dom4j.Node; +import org.w3c.dom.Document; + +public class SetsList extends ResponseBase { + + private static final String SET_XPATH = "oai:ListSets/oai:set"; + + private List sets; + + public SetsList(Document document) throws PMHErrorResponseException { + super(document); + + this.sets = new LinkedList(); + for (Node set : xpath.selectNodes(SET_XPATH)) { + sets.add(new Set(set)); + } + } + + public int size() { + return sets.size(); + } + + public List asList() { + return sets; + } +} diff --git a/src/main/java/se/kb/xml/XMLUtils.java b/src/main/java/se/kb/xml/XMLUtils.java new file mode 100644 index 0000000..f8c4972 --- /dev/null +++ b/src/main/java/se/kb/xml/XMLUtils.java @@ -0,0 +1,32 @@ +package se.kb.xml; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; + +import org.dom4j.Element; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.XMLWriter; + +public class XMLUtils { + + public static final String ENCODING = "UTF-8"; + + public static void writeXmlTo(Element element, OutputStream stream) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(stream, ENCODING); + OutputFormat format = OutputFormat.createPrettyPrint(); + format.setEncoding(ENCODING); + + XMLWriter xmlwriter = new XMLWriter(writer, format); + xmlwriter.write(element); + xmlwriter.flush(); + writer.flush(); + } + + public static String xmlToString(Element xml) throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + writeXmlTo(xml, stream); + return stream.toString(ENCODING); + } +} diff --git a/src/main/java/se/kb/xml/XPathWrapper.java b/src/main/java/se/kb/xml/XPathWrapper.java new file mode 100644 index 0000000..d560ae6 --- /dev/null +++ b/src/main/java/se/kb/xml/XPathWrapper.java @@ -0,0 +1,74 @@ +/* + * Created on 17 Aug 2007 + * + * Copyright (C) 2007 Royal Library of Sweden. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package se.kb.xml; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.dom4j.DocumentHelper; +import org.dom4j.Element; +import org.dom4j.Node; +import org.dom4j.XPath; + +public class XPathWrapper { + + private Node node; + private Map namespaces; + + public XPathWrapper(Node node) { + this(node, new HashMap()); + } + + public XPathWrapper(Node node, Map namespaces) { + this.node = node; + this.namespaces = namespaces; + } + + public void addNamespace(String prefix, String uri) { + namespaces.put(prefix, uri); + } + + public Node selectSingleNode(String xpathExpression) { + XPath xpath = createXPath(xpathExpression); + return xpath.selectSingleNode(node); + } + + @SuppressWarnings("unchecked") + public List selectNodes(String xpathExpression) { + XPath xpath = createXPath(xpathExpression); + return xpath.selectNodes(node); + } + + public Element selectSingleElement(String xpathExpression) { + return (Element) selectSingleNode(xpathExpression); + } + + public String valueOf(String xpathExpression) { + XPath xpath =createXPath(xpathExpression); + return xpath.valueOf(node); + } + + private XPath createXPath(String xpathExpression) { + XPath xpath = DocumentHelper.createXPath(xpathExpression); + xpath.setNamespaceURIs(namespaces); + return xpath; + } +} diff --git a/src/test/java/se/kb/oai/ore/ORETest.java b/src/test/java/se/kb/oai/ore/ORETest.java new file mode 100644 index 0000000..89cf242 --- /dev/null +++ b/src/test/java/se/kb/oai/ore/ORETest.java @@ -0,0 +1,21 @@ +package se.kb.oai.ore; + +import static org.junit.Assert.*; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class ORETest { + + @Test + public void testConstructor() throws URISyntaxException + { + ResourceMap map = new ResourceMap(new URI("http://test.kb.se/rem/")); + assertEquals("http://test.kb.se/rem/#aggregation", map.getAggregation().getId().toString()); + } +}