Skip to content

Commit b2f73bd

Browse files
committed
initial working implementation of the pojo facade
1 parent 75cdc06 commit b2f73bd

File tree

10 files changed

+1087
-0
lines changed

10 files changed

+1087
-0
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright 2012-2014 MarkLogic Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.marklogic.client.impl;
17+
18+
import java.io.ByteArrayInputStream;
19+
import java.io.ByteArrayOutputStream;
20+
import java.io.IOException;
21+
import java.io.InputStream;
22+
import java.io.InputStreamReader;
23+
import java.io.OutputStream;
24+
import java.io.OutputStreamWriter;
25+
import java.io.UnsupportedEncodingException;
26+
27+
import com.fasterxml.jackson.core.JsonParser;
28+
import com.fasterxml.jackson.core.JsonGenerator;
29+
import com.fasterxml.jackson.core.JsonParseException;
30+
import com.fasterxml.jackson.databind.JsonMappingException;
31+
import com.fasterxml.jackson.databind.JsonNode;
32+
import com.fasterxml.jackson.databind.ObjectMapper;
33+
34+
import com.marklogic.client.MarkLogicIOException;
35+
import com.marklogic.client.io.BaseHandle;
36+
import com.marklogic.client.io.Format;
37+
import com.marklogic.client.io.OutputStreamSender;
38+
import com.marklogic.client.io.marker.BufferableHandle;
39+
import com.marklogic.client.io.marker.JSONReadHandle;
40+
import com.marklogic.client.io.marker.JSONWriteHandle;
41+
import com.marklogic.client.io.marker.StructureReadHandle;
42+
import com.marklogic.client.io.marker.StructureWriteHandle;
43+
44+
public abstract class JacksonBaseHandle
45+
extends BaseHandle<InputStream, OutputStreamSender>
46+
implements OutputStreamSender, BufferableHandle, JSONReadHandle, JSONWriteHandle,
47+
StructureReadHandle, StructureWriteHandle
48+
{
49+
private ObjectMapper mapper;
50+
51+
protected JacksonBaseHandle() {
52+
super();
53+
super.setFormat(Format.JSON);
54+
}
55+
56+
/**
57+
* Returns the mapper used to construct node objects from JSON.
58+
* @return the JSON mapper.
59+
*/
60+
public ObjectMapper getMapper() {
61+
if (mapper == null) {
62+
mapper = new ObjectMapper();
63+
mapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
64+
mapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
65+
}
66+
return mapper;
67+
}
68+
69+
/**
70+
* Restricts the format to JSON.
71+
*/
72+
@Override
73+
public void setFormat(Format format) {
74+
if (format != Format.JSON) {
75+
throw new IllegalArgumentException(
76+
"JacksonHandle supports the JSON format only");
77+
}
78+
super.setFormat(Format.JSON);
79+
}
80+
81+
@Override
82+
public byte[] toBuffer() {
83+
try {
84+
if ( ! hasContent() )
85+
return null;
86+
87+
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
88+
write(buffer);
89+
90+
return buffer.toByteArray();
91+
} catch (IOException e) {
92+
throw new MarkLogicIOException(e);
93+
}
94+
}
95+
96+
/**
97+
* Returns the JSON as a string.
98+
*/
99+
@Override
100+
public String toString() {
101+
try {
102+
return new String(toBuffer(),"UTF-8");
103+
} catch (UnsupportedEncodingException e) {
104+
throw new MarkLogicIOException(e);
105+
}
106+
}
107+
108+
@Override
109+
protected Class<InputStream> receiveAs() {
110+
return InputStream.class;
111+
}
112+
@Override
113+
protected OutputStreamSender sendContent() {
114+
if ( ! hasContent() ) {
115+
throw new IllegalStateException("No document to write");
116+
}
117+
return this;
118+
}
119+
120+
protected abstract boolean hasContent();
121+
122+
@Override
123+
public abstract void write(OutputStream out) throws IOException;
124+
}
125+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.marklogic.client.impl;
2+
3+
import java.util.Iterator;
4+
5+
import com.marklogic.client.Page;
6+
import com.marklogic.client.impl.BasicPage;
7+
import com.marklogic.client.io.JacksonPojoHandle;
8+
import com.marklogic.client.document.DocumentPage;
9+
import com.marklogic.client.pojo.PojoPage;
10+
11+
public class PojoPageImpl<T> extends BasicPage<T> implements PojoPage<T>, Iterator<T> {
12+
private Class<T> entityClass;
13+
private DocumentPage docPage;
14+
15+
public PojoPageImpl(DocumentPage docPage, Class<T> entityClass) {
16+
super(entityClass);
17+
setStart( docPage.getStart() );
18+
setPageSize( docPage.getPageSize() );
19+
setTotalSize( docPage.getTotalSize() );
20+
21+
this.docPage = docPage;
22+
this.entityClass = entityClass;
23+
}
24+
25+
@Override
26+
public Iterator<T> iterator() {
27+
return this;
28+
}
29+
30+
@Override
31+
public boolean hasNext() {
32+
return docPage.hasNext();
33+
}
34+
35+
@Override
36+
public T next() {
37+
return docPage.nextContent(new JacksonPojoHandle<T>(entityClass)).get();
38+
}
39+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package com.marklogic.client.impl;
2+
3+
import com.marklogic.client.pojo.PojoQueryBuilder;
4+
import com.marklogic.client.query.StructuredQueryBuilder;
5+
import com.marklogic.client.query.StructuredQueryBuilder.TextIndex;
6+
import com.marklogic.client.query.StructuredQueryDefinition;
7+
8+
import java.lang.reflect.Method;
9+
import java.lang.reflect.Modifier;
10+
import java.util.Date;
11+
import java.util.HashMap;
12+
13+
public class PojoQueryBuilderImpl<T> extends StructuredQueryBuilder implements PojoQueryBuilder<T> {
14+
private HashMap<String, Class> types = new HashMap<String, Class>();
15+
private HashMap<String, String> rangeIndextypes = new HashMap<String, String>();
16+
private Class<?> clazz;
17+
private String classWrapper;
18+
19+
public PojoQueryBuilderImpl(Class<T> clazz) {
20+
super();
21+
if ( clazz == null ) throw new IllegalArgumentException("clazz cannot be null");
22+
this.clazz = clazz;
23+
this.classWrapper = clazz.getName();
24+
}
25+
26+
private StructuredQueryBuilder.PathIndex pojoFieldPath(String pojoField) {
27+
return pathIndex(classWrapper + "/" + pojoField);
28+
}
29+
30+
public StructuredQueryDefinition containerQuery(String pojoField, StructuredQueryDefinition query) {
31+
return containerQuery(jsonProperty(pojoField), query);
32+
}
33+
@Override
34+
public StructuredQueryDefinition containerQuery(StructuredQueryDefinition query) {
35+
return containerQuery(jsonProperty(classWrapper), query);
36+
}
37+
public PojoQueryBuilder containerQuery(String pojoField) {
38+
return new PojoQueryBuilderImpl(getType(pojoField));
39+
}
40+
@Override
41+
public StructuredQueryBuilder.GeospatialIndex
42+
geoPair(String latitudeFieldName, String longitudeFieldName)
43+
{
44+
return geoElementPair(jsonProperty(classWrapper), jsonProperty(latitudeFieldName), jsonProperty(longitudeFieldName));
45+
}
46+
public StructuredQueryBuilder.GeospatialIndex geoField(String pojoField) {
47+
return geoElement(jsonProperty(pojoField));
48+
}
49+
public StructuredQueryBuilder.GeospatialIndex geoPath(String pojoField) {
50+
return geoPath(pojoFieldPath(pojoField));
51+
}
52+
public StructuredQueryDefinition range(String pojoField,
53+
StructuredQueryBuilder.Operator operator, Object... values) {
54+
return range(pojoFieldPath(pojoField), getRangeIndexType(pojoField), operator, values);
55+
}
56+
public StructuredQueryDefinition range(String pojoField, String[] options,
57+
StructuredQueryBuilder.Operator operator, Object... values)
58+
{
59+
return range(pojoFieldPath(pojoField), getRangeIndexType(pojoField), options,
60+
operator, values);
61+
}
62+
public StructuredQueryDefinition value(String pojoField, String... values) {
63+
return value(jsonProperty(pojoField), values);
64+
}
65+
public StructuredQueryDefinition value(String pojoField, String[] options,
66+
double weight, String... values)
67+
{
68+
return value(jsonProperty(pojoField), null, options, weight, values);
69+
}
70+
public StructuredQueryDefinition word(String pojoField, String... words) {
71+
return word(jsonProperty(pojoField), words);
72+
}
73+
public StructuredQueryDefinition word(String pojoField, String[] options,
74+
double weight, String... words)
75+
{
76+
return word(jsonProperty(pojoField), null, options, weight, words);
77+
}
78+
public StructuredQueryDefinition word(String... words) {
79+
return word(words);
80+
}
81+
public StructuredQueryDefinition word(String[] options, double weight, String... words) {
82+
return word(options, weight, words);
83+
}
84+
85+
public String getRangeIndexType(String fieldName) {
86+
// map java types to acceptable Range Index types
87+
String type = rangeIndextypes.get(fieldName);
88+
if ( type == null ) {
89+
Class fieldClass = getType(fieldName);
90+
if ( String.class.isAssignableFrom(fieldClass) ) {
91+
type = "string";
92+
} else if ( Integer.class.isAssignableFrom(fieldClass) ) {
93+
type = "int";
94+
} else if ( Long.class.isAssignableFrom(fieldClass) ) {
95+
type = "long";
96+
} else if ( Float.class.isAssignableFrom(fieldClass) ) {
97+
type = "float";
98+
} else if ( Double.class.isAssignableFrom(fieldClass) ) {
99+
type = "double";
100+
} else if ( Number.class.isAssignableFrom(fieldClass) ) {
101+
type = "decimal";
102+
} else if ( Date.class.isAssignableFrom(fieldClass) ) {
103+
type = "dateTime";
104+
}
105+
if ( type == null ) {
106+
throw new IllegalArgumentException("Field " + fieldName + " is not a native Java type");
107+
}
108+
rangeIndextypes.put(fieldName, type);
109+
}
110+
return type;
111+
}
112+
113+
public Class getType(String fieldName) {
114+
Class fieldClass = types.get(fieldName);
115+
if ( fieldClass == null ) {
116+
// figure out the type of the java field
117+
String initCapPojoField = fieldName.substring(1,2).toUpperCase() +
118+
fieldName.substring(2);
119+
try {
120+
fieldClass = clazz.getField(fieldName).getType();
121+
} catch(NoSuchFieldException e) {
122+
Method getMethod = null;
123+
try {
124+
getMethod = clazz.getMethod("get" + initCapPojoField);
125+
} catch (NoSuchMethodException e2) {
126+
try {
127+
getMethod = clazz.getMethod("is" + initCapPojoField);
128+
if ( ! Boolean.class.isAssignableFrom(getMethod.getReturnType()) ) {
129+
getMethod = null;
130+
}
131+
} catch (NoSuchMethodException e3) {}
132+
}
133+
if ( getMethod != null ) {
134+
if ( Modifier.isStatic(getMethod.getModifiers()) ) {
135+
throw new IllegalArgumentException("get" + initCapPojoField +
136+
" cannot be static");
137+
}
138+
fieldClass = getMethod.getReturnType();
139+
if ( fieldClass == Void.TYPE ) {
140+
throw new IllegalArgumentException("get" + initCapPojoField +
141+
" must not have return type void");
142+
}
143+
} else {
144+
String setMethodName = "set" + initCapPojoField;
145+
for ( Method method : clazz.getMethods() ) {
146+
if ( setMethodName.equals(method.getName()) ) {
147+
Class[] parameters = method.getParameterTypes();
148+
if ( parameters != null && parameters.length == 1 ) {
149+
fieldClass = parameters[0];
150+
break;
151+
}
152+
}
153+
}
154+
}
155+
}
156+
if ( fieldClass == null ) {
157+
throw new IllegalArgumentException("field " + fieldName + " not found, get" + initCapPojoField +
158+
" not found, and set" + initCapPojoField + " not found in class " + classWrapper);
159+
}
160+
types.put(fieldName, fieldClass);
161+
}
162+
return fieldClass;
163+
}
164+
}
165+
166+

0 commit comments

Comments
 (0)