Let's take a look how to setup MarkLogic database instance on a local machine and write a simple application that will perform CRUD and searching operations on XML documents.
First of all, we will need to download MarkLogic server (account is required).
Installation and starting procedures are described here - they're pretty straightforward.
When server is already started, we need to create a new database with REST API instance and a user having write access - follow this link.
REST is used by the Java client as a communication protocol but we can also use it manually in our browser.
Once database is created we can start writing the client code.
Let's start with setting up required dependencies:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<dependencies> | |
<dependency> | |
<groupId>com.marklogic</groupId> | |
<artifactId>client-api-java</artifactId> | |
<version>1.0-2</version> | |
</dependency> | |
<dependency> | |
<groupId>junit</groupId> | |
<artifactId>junit</artifactId> | |
<version>4.11</version> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.xmlmatchers</groupId> | |
<artifactId>xml-matchers</artifactId> | |
<version>0.10</version> | |
<scope>test</scope> | |
</dependency> | |
</dependencies> | |
<repositories> | |
<repository> | |
<id>dmc</id> | |
<name>MarkLogic Developer Community</name> | |
<url>http://developer.marklogic.com/maven2/</url> | |
</repository> | |
</repositories> |
Here's an example of XML document that will be representing person:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<person> | |
<name>Robin van Persie</name> | |
<age>29</age> | |
</person> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface PersonRepository { | |
void addPerson(String id, String person); | |
String getPerson(String id); | |
void removePerson(String id); | |
List<String> findByName(String name); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MarkLogicPersonRepository implements PersonRepository { | |
private XMLDocumentManager documentManager; | |
private QueryManager queryManager; | |
public MarkLogicPersonRepository(XMLDocumentManager documentManager, QueryManager queryManager) { | |
this.documentManager = documentManager; | |
this.queryManager = queryManager; | |
} | |
public void addPerson(String id, String person) { | |
StringHandle handle = new StringHandle(person); | |
documentManager.write(id, handle); | |
} | |
public String getPerson(String personId) { | |
StringHandle handle = new StringHandle(); | |
documentManager.read(personId, handle); | |
return handle.get(); | |
} | |
public void removePerson(String personId) { | |
documentManager.delete(personId); | |
} | |
public List<String> findByName(String name) { | |
KeyValueQueryDefinition query = queryManager.newKeyValueDefinition(); | |
queryManager.setPageLength(10); // LIMIT RESULT | |
query.put(queryManager.newElementLocator(new QName("name")), name); | |
SearchHandle resultsHandle = new SearchHandle(); | |
queryManager.search(query, resultsHandle); | |
return getResultListFor(resultsHandle); | |
} | |
private List<String> getResultListFor(SearchHandle resultsHandle) { | |
List<String> result = new ArrayList<String>(); | |
for (MatchDocumentSummary summary : resultsHandle.getMatchResults()) { | |
StringHandle content = new StringHandle(); | |
documentManager.read(summary.getUri(), content); | |
result.add(content.get()); | |
} | |
return result; | |
} | |
} |
To do query operations QueryManager is required. There are many types of queries, we'll use searching by element value.
It's a little bit more complicated than simple CRUD operations - SearchHandle object is initially populated by running the query on query manager.
Then we're iterating over each SearchHandle's result represented by MatchDocumentSummary object and retrieve its URI, that is given to DocumentManager that reads full document.
Please note that the number of returned documents has been limited to 10.
The integration test (it requires running MarkLogic server):
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MarkLogicPersonRepositoryIntegrationTest { | |
private static final String NAME = "Robin van Persie"; | |
private static final String SAMPLE_PERSON = "<person><name>" + NAME + "</name><age>29</age></person>"; | |
private MarkLogicPersonRepository personRepository; | |
@Before | |
public void setUp() { | |
DatabaseClient client = DatabaseClientFactory.newClient("localhost", 8003, "rest-writer", "x", DIGEST); | |
personRepository = new MarkLogicPersonRepository(client.newXMLDocumentManager(), client.newQueryManager()); | |
} | |
@Test | |
public void shouldAddAndRetrievePersonAsXmlDocument() { | |
// given | |
String personId = randomUUID().toString(); | |
personRepository.addPerson(personId, SAMPLE_PERSON); | |
// when | |
String result = personRepository.getPerson(personId); | |
// then | |
assertThat(the(result), isEquivalentTo(the(SAMPLE_PERSON))); | |
} | |
@Test(expected = ResourceNotFoundException.class) | |
public void shouldRemovePerson() { | |
// given | |
String personId = randomUUID().toString(); | |
personRepository.addPerson(personId, SAMPLE_PERSON); | |
// when | |
personRepository.removePerson(personId); | |
// then | |
personRepository.getPerson(personId); | |
} | |
@Test | |
public void shouldFindPersonByName() { | |
// given | |
personRepository.addPerson(randomUUID().toString(), SAMPLE_PERSON); | |
// when | |
List<String> result = personRepository.findByName(NAME); | |
// then | |
assertThat(the(result.get(0)), isEquivalentTo(the(SAMPLE_PERSON))); | |
} | |
} |
In setUp() method DatabaseClientFactory creates DatabaseClient based on the given credentials (they need to be the same as the one used during setting up the database).
Once we have the client we can create managers needed by the implementation.
One thing to note: when manager cannot find the document it throws ResourceNotFoundException.
The whole project can be found at github.