Skip to content

Commit 973ea40

Browse files
author
ehennum
committed
Bug:25862 shortcut for raw IO object or class when handle is registered
git-svn-id: svn+ssh://svn.marklogic.com/project/engsvn/client-api/java/branches/b2_0@162606 62cac252-8da6-4816-9e9d-6dc37b19578c
1 parent 8d2c3df commit 973ea40

File tree

4 files changed

+230
-20
lines changed

4 files changed

+230
-20
lines changed

src/main/java/com/marklogic/client/impl/QueryManagerImpl.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ public <T extends SearchReadHandle> T search(QueryDefinition querydef, T searchH
176176
HandleImplementation searchBase = HandleAccessor.checkHandle(searchHandle, "search");
177177

178178
if (searchHandle instanceof SearchHandle) {
179-
((SearchHandle) searchHandle).setQueryCriteria(querydef);
179+
SearchHandle responseHandle = (SearchHandle) searchHandle;
180+
responseHandle.setHandleRegistry(getHandleRegistry());
181+
responseHandle.setQueryCriteria(querydef);
180182
}
181183

182184
Format searchFormat = searchBase.getFormat();

src/main/java/com/marklogic/client/io/SearchHandle.java

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.ArrayList;
2020
import java.util.Calendar;
2121
import java.util.Collection;
22+
import java.util.Collections;
2223
import java.util.Iterator;
2324
import java.util.LinkedHashMap;
2425
import java.util.List;
@@ -40,8 +41,10 @@
4041
import org.slf4j.LoggerFactory;
4142
import org.w3c.dom.Document;
4243

44+
import com.marklogic.client.DatabaseClientFactory.HandleFactoryRegistry;
4345
import com.marklogic.client.MarkLogicIOException;
4446
import com.marklogic.client.impl.Utilities;
47+
import com.marklogic.client.io.marker.ContentHandle;
4548
import com.marklogic.client.io.marker.OperationNotSupported;
4649
import com.marklogic.client.io.marker.SearchReadHandle;
4750
import com.marklogic.client.io.marker.XMLReadHandle;
@@ -76,7 +79,8 @@ public class SearchHandle
7679
static private String SEARCH_NS = "http://marklogic.com/appservices/search";
7780
static private String QUERY_NS = "http://marklogic.com/cts/query";
7881

79-
private QueryDefinition querydef;
82+
private QueryDefinition querydef;
83+
private HandleFactoryRegistry registry;
8084

8185
private MatchDocumentSummary[] summary;
8286
private SearchMetrics metrics;
@@ -204,7 +208,6 @@ public void setQueryCriteria(QueryDefinition querydef) {
204208
qtext = null;
205209
queryEvents = null;
206210
}
207-
208211
/**
209212
* Returns the query definition used for the search represented by this handle.
210213
* @return The query definition.
@@ -214,6 +217,18 @@ public QueryDefinition getQueryCriteria() {
214217
return querydef;
215218
}
216219

220+
/**
221+
* Makes the handle registry for this database client available
222+
* to this SearchHandle during processing of the search response.
223+
* @param registry the registry of IO representation classes for this database client
224+
*/
225+
final public void setHandleRegistry(HandleFactoryRegistry registry) {
226+
this.registry = registry;
227+
}
228+
private HandleFactoryRegistry getHandleRegistry() {
229+
return this.registry;
230+
}
231+
217232
/**
218233
* Returns the total number of results in this search.
219234
* @return The number of results.
@@ -534,8 +549,17 @@ public String getPath() {
534549
}
535550

536551
@Override
537-
public Document[] getSnippets() {
538-
return getEventDocuments(events, snippetEvents);
552+
public <T> T getFirstSnippetAs(Class<T> as) {
553+
ContentHandle<T> handle = getHandleRegistry().makeHandle(as);
554+
if (!XMLReadHandle.class.isAssignableFrom(handle.getClass())) {
555+
throw new IllegalArgumentException("cannot read snippet from XML with "+handle.getClass());
556+
}
557+
558+
if (null == getFirstSnippet((XMLReadHandle) handle)) {
559+
return null;
560+
}
561+
562+
return handle.get();
539563
}
540564
@Override
541565
public <T extends XMLReadHandle> T getFirstSnippet(T handle) {
@@ -557,6 +581,11 @@ public String getFirstSnippetText() {
557581
getSlice(events, snippetEvents.get(0))
558582
);
559583
}
584+
585+
@Override
586+
public Document[] getSnippets() {
587+
return getEventDocuments(events, snippetEvents);
588+
}
560589
@Override
561590
public <T extends XMLReadHandle> Iterator<T> getSnippetIterator(T handle) {
562591
if (snippetEvents == null || snippetEvents.size() < 1) {
@@ -581,6 +610,18 @@ public Document getMetadata() {
581610
return (handle == null) ? null : handle.get();
582611
}
583612
@Override
613+
public <T> T getMetadataAs(Class<T> as) {
614+
ContentHandle<T> handle = getHandleRegistry().makeHandle(as);
615+
616+
if (!XMLReadHandle.class.isAssignableFrom(handle.getClass())) {
617+
throw new IllegalArgumentException("cannot read metadata from XML with "+handle.getClass());
618+
}
619+
620+
getMetadata((XMLReadHandle) handle);
621+
622+
return handle.get();
623+
}
624+
@Override
584625
public <T extends XMLReadHandle> T getMetadata(T handle) {
585626
return Utilities.exportToHandle(
586627
getSlice(events, metadataEvents), handle
@@ -893,6 +934,7 @@ public T next() {
893934
if (!hasNext()) {
894935
return null;
895936
}
937+
896938
EventRange eventRange = rangeList.get(nextEvent++);
897939
return Utilities.exportToHandle(
898940
getSlice(eventList, eventRange), handle

src/main/java/com/marklogic/client/query/MatchDocumentSummary.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,22 @@ public interface MatchDocumentSummary {
8888
public <T extends XMLReadHandle> Iterator<T> getSnippetIterator(T handle);
8989

9090
/**
91-
* Returns the content of the first snippet as a convenience,
92-
* especially for a raw snippet that contains the entire document.
91+
* Reads the content of the first snippet for the matched result document
92+
* in the representation specified by the IO class. This method provides
93+
* particular convenience for a raw snippet that contains the entire
94+
* result document.
95+
*
96+
* The IO class must have been registered before creating the database client.
97+
* By default, standard Java IO classes for document content are registered.
98+
*
99+
* @param as the IO class for reading the first snippet for the result
100+
* @return an object of the IO class with the content of the document in the first snippet
101+
*/
102+
public <T> T getFirstSnippetAs(Class<T> as);
103+
/**
104+
* Returns the content of the first snippet for the matched result document
105+
* as a convenience, especially for a raw snippet that contains the entire
106+
* result document.
93107
* @param handle An XML handle for reading the first snippet.
94108
* @return The handle populated with the first snippet.
95109
*/
@@ -109,9 +123,20 @@ public interface MatchDocumentSummary {
109123
* @return the metadata
110124
*/
111125
public Document getMetadata();
112-
126+
127+
/**
128+
* Reads the metadata extracted from the matched result document
129+
* in the representation specified by the IO class.
130+
*
131+
* The IO class must have been registered before creating the database client.
132+
* By default, standard Java IO classes for document content are registered.
133+
*
134+
* @param as the IO class for reading the metadata for the result
135+
* @return an object of the IO class with the extracted result document metadata
136+
*/
137+
public <T> T getMetadataAs(Class<T> as);
113138
/**
114-
* Returns the metadata for the result.
139+
* Returns the metadata extracted from the result document.
115140
* @param handle An XML handle for reading the metadata.
116141
* @return The handle on the metadata.
117142
*/

src/test/java/com/marklogic/client/test/HandleAsTest.java

Lines changed: 152 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@
2828
import java.io.InputStreamReader;
2929
import java.io.Reader;
3030
import java.io.StringReader;
31+
import java.util.HashSet;
3132
import java.util.Set;
3233

34+
import javax.xml.bind.JAXBException;
35+
import javax.xml.bind.annotation.XmlRootElement;
3336
import javax.xml.parsers.DocumentBuilder;
3437
import javax.xml.parsers.DocumentBuilderFactory;
3538
import javax.xml.parsers.ParserConfigurationException;
@@ -56,17 +59,24 @@
5659

5760
import com.marklogic.client.DatabaseClient;
5861
import com.marklogic.client.DatabaseClientFactory;
62+
import com.marklogic.client.DatabaseClientFactory.Authentication;
63+
import com.marklogic.client.DatabaseClientFactory.HandleFactoryRegistry;
5964
import com.marklogic.client.FailedRequestException;
6065
import com.marklogic.client.ForbiddenUserException;
6166
import com.marklogic.client.ResourceNotFoundException;
62-
import com.marklogic.client.DatabaseClientFactory.Authentication;
63-
import com.marklogic.client.DatabaseClientFactory.HandleFactoryRegistry;
6467
import com.marklogic.client.document.BinaryDocumentManager;
6568
import com.marklogic.client.document.TextDocumentManager;
6669
import com.marklogic.client.document.XMLDocumentManager;
6770
import com.marklogic.client.io.BaseHandle;
71+
import com.marklogic.client.io.Format;
72+
import com.marklogic.client.io.JAXBHandle;
73+
import com.marklogic.client.io.SearchHandle;
6874
import com.marklogic.client.io.marker.ContentHandle;
6975
import com.marklogic.client.io.marker.ContentHandleFactory;
76+
import com.marklogic.client.query.DeleteQueryDefinition;
77+
import com.marklogic.client.query.MatchDocumentSummary;
78+
import com.marklogic.client.query.QueryDefinition;
79+
import com.marklogic.client.query.QueryManager;
7080

7181
public class HandleAsTest {
7282
@BeforeClass
@@ -198,19 +208,112 @@ public void testBuiltinReadWrite()
198208
assertEquals("StreamReader difference in document read/write as", beforeText, afterText);
199209
}
200210

211+
@Test
212+
public void testSearch() throws JAXBException {
213+
DatabaseClientFactory.Bean clientFactoryBean = makeClientFactory();
214+
215+
clientFactoryBean.getHandleRegistry().register(
216+
JAXBHandle.newFactory(Product.class)
217+
);
218+
219+
DatabaseClient client = clientFactoryBean.newClient();
220+
221+
XMLDocumentManager docMgr = client.newXMLDocumentManager();
222+
223+
QueryManager queryMgr = client.newQueryManager();
224+
225+
String basedir = "/tmp/jaxb/test/";
226+
227+
Product product1 = new Product();
228+
product1.setName("Widgetry");
229+
product1.setIndustry("IT");
230+
product1.setDescription("More widgets than you can shake a stick at");
231+
232+
Product product2 = new Product();
233+
product2.setName("AppExcess");
234+
product2.setIndustry("IT");
235+
product2.setDescription("There's an app for that.");
236+
237+
Product[] products = {product1, product2};
238+
239+
// setup
240+
Set<String> prodNames = new HashSet<String>(products.length);
241+
for (Product product: products) {
242+
String prodName = product.getName();
243+
prodNames.add(prodName);
244+
String docId = basedir+prodName+".xml";
245+
docMgr.writeAs(docId, product);
246+
}
247+
248+
// test
249+
String rawQuery = new StringBuilder()
250+
.append("<search:search xmlns:search=\"http://marklogic.com/appservices/search\">")
251+
.append("<search:qtext>IT</search:qtext>")
252+
.append("<search:options>")
253+
.append("<search:transform-results apply=\"raw\"/> ")
254+
.append("</search:options>")
255+
.append("</search:search>")
256+
.toString();
257+
258+
QueryDefinition queryDef =
259+
queryMgr.newRawCombinedQueryDefinitionAs(Format.XML, rawQuery);
260+
queryDef.setDirectory(basedir);
261+
262+
SearchHandle handle = queryMgr.search(queryDef, new SearchHandle());
263+
264+
MatchDocumentSummary[] summaries = handle.getMatchResults();
265+
assertEquals("raw query should retrieve all products", products.length, summaries.length);
266+
for (MatchDocumentSummary summary: summaries) {
267+
Product product = summary.getFirstSnippetAs(Product.class);
268+
assertTrue("raw product should exist", product != null);
269+
assertTrue("raw product name should be preserved", prodNames.contains(product.getName()));
270+
}
271+
272+
rawQuery = new StringBuilder()
273+
.append("<search:search xmlns:search=\"http://marklogic.com/appservices/search\">")
274+
.append("<search:qtext>IT</search:qtext>")
275+
.append("<search:options>")
276+
.append("<search:extract-metadata>")
277+
.append("<search:qname elem-ns=\"\" elem-name=\"name\"/>")
278+
.append("<search:qname elem-ns=\"\" elem-name=\"industry\"/>")
279+
.append("</search:extract-metadata>")
280+
.append("</search:options>")
281+
.append("</search:search>")
282+
.toString();
283+
284+
queryDef =
285+
queryMgr.newRawCombinedQueryDefinitionAs(Format.XML, rawQuery);
286+
queryDef.setDirectory(basedir);
287+
288+
handle = queryMgr.search(queryDef, new SearchHandle());
289+
290+
summaries = handle.getMatchResults();
291+
assertEquals("metadata query should retrieve all products", products.length, summaries.length);
292+
for (MatchDocumentSummary summary: summaries) {
293+
Document productDoc = summary.getMetadataAs(Document.class);
294+
295+
Element name = (Element) productDoc.getElementsByTagName("name").item(0);
296+
assertTrue("metadata product name should exist", name != null);
297+
assertTrue("metadata product name should be preserved", prodNames.contains(name.getTextContent()));
298+
299+
Element industry = (Element) productDoc.getElementsByTagName("industry").item(0);
300+
assertTrue("metadata product industry should exist", industry != null);
301+
}
302+
303+
// cleanup
304+
DeleteQueryDefinition deleteDef = queryMgr.newDeleteDefinition();
305+
deleteDef.setDirectory(basedir);
306+
307+
queryMgr.delete(deleteDef);
308+
309+
client.release();
310+
}
311+
201312
@Test
202313
public void testHandleRegistry() {
203314
int[] iterations = {1,2};
204315
for (int i: iterations) {
205-
DatabaseClientFactory.Bean clientFactoryBean = null;
206-
if (i == 2) {
207-
clientFactoryBean = new DatabaseClientFactory.Bean();
208-
clientFactoryBean.setHost(Common.HOST);
209-
clientFactoryBean.setPort(Common.PORT);
210-
clientFactoryBean.setUser(Common.USERNAME);
211-
clientFactoryBean.setPassword(Common.PASSWORD);
212-
clientFactoryBean.setAuthentication(Authentication.DIGEST);
213-
}
316+
DatabaseClientFactory.Bean clientFactoryBean = (i == 1) ? null : makeClientFactory();
214317

215318
HandleFactoryRegistry registry =
216319
(i == 1) ? DatabaseClientFactory.getHandleRegistry()
@@ -268,6 +371,16 @@ public void testHandleRegistry() {
268371
}
269372
}
270373

374+
private DatabaseClientFactory.Bean makeClientFactory() {
375+
DatabaseClientFactory.Bean clientFactoryBean = new DatabaseClientFactory.Bean();
376+
clientFactoryBean.setHost(Common.HOST);
377+
clientFactoryBean.setPort(Common.PORT);
378+
clientFactoryBean.setUser(Common.USERNAME);
379+
clientFactoryBean.setPassword(Common.PASSWORD);
380+
clientFactoryBean.setAuthentication(Authentication.DIGEST);
381+
return clientFactoryBean;
382+
}
383+
271384
static public class BufferHandle
272385
extends BaseHandle<String, String>
273386
implements ContentHandle<StringBuilder> {
@@ -317,4 +430,32 @@ public <C> ContentHandle<C> newHandle(Class<C> type) {
317430
return handle;
318431
}
319432
}
433+
434+
@XmlRootElement
435+
static public class Product {
436+
private String name;
437+
private String industry;
438+
private String description;
439+
public Product() {
440+
super();
441+
}
442+
public String getName() {
443+
return name;
444+
}
445+
public void setName(String name) {
446+
this.name = name;
447+
}
448+
public String getIndustry() {
449+
return industry;
450+
}
451+
public void setIndustry(String industry) {
452+
this.industry = industry;
453+
}
454+
public String getDescription() {
455+
return description;
456+
}
457+
public void setDescription(String description) {
458+
this.description = description;
459+
}
460+
}
320461
}

0 commit comments

Comments
 (0)