I am trying to perform logging of SOAPMessage.
This object contains both wrapper classes and JAXBElements, I am doing something like this
#Before("soapRequest()")
public void logBefore(JoinPoint joinPoint) {
Object[] signatureArgs = joinPoint.getArgs();
System.out.println("\n\n\n");
for (Object signatureArg : signatureArgs) {
StringBuilder sb = new StringBuilder();
try {
Field[] aClassFields = signatureArg.getClass().getDeclaredFields();
sb.append(signatureArg.getClass().getSimpleName() + " [ ");
for (Field f : aClassFields) {
f.setAccessible(true);
String fName = f.getName();
String value = "";
if(f.get(signatureArg) instanceof JAXBElement) {
log.info("is instance of");
JAXBElement val = (JAXBElement) f.get(signatureArg);
log.info(val.toString());
value = val.getValue().toString();
} else {
value = f.get(signatureArg).toString();
}
sb.append("(" + f.getType() + ") " + fName + " = " + value + ", ");
}
sb.append("]");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(sb.toString());
}
}
However this line throws NPE:
if(f.get(signatureArg) instanceof JAXBElement) {
log.info("is instance of");
JAXBElement val = (JAXBElement) f.get(signatureArg);
log.info(val.toString());
value = val.getValue().toString();
}
How Can I check if the field is instance of JAXBElement and extract value from it?
Actually I think your NPE occurs in the then block at this line of code:
value = f.get(signatureArg).toString();
It happens if the field value is null because on null you cannot call toString(). By the way, this should happen for any null field, not just for JAXBElement. You do not need toString(), you can just remove it because when you print any object, it will automatically use its toString() representation where applicable.
In my opinion your code is also more complicated than necessary and with some restructuring and renaming variables the then block is no longer necessary at all. Here is my MCVE in plain Java + AspectJ (no Spring) for you:
package de.scrum_master.app;
import javax.xml.bind.JAXBElement;
public class Container {
private String name;
private JAXBElement jaxbElement;
public Container(String name, JAXBElement jaxbElement) {
this.name = name;
this.jaxbElement = jaxbElement;
}
}
package de.scrum_master.app;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
public class Application {
public void doSomething(int number, String text, Container myContainer) {}
public static void main(String[] args) {
Application application = new Application();
application.doSomething(11, "foo", new Container("bar", new JAXBElement(new QName("local"), String.class, "dummy")));
application.doSomething(11, "foo", new Container("bar", null));
}
}
package de.scrum_master.aspect;
import java.lang.reflect.Field;
import javax.xml.bind.JAXBElement;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class MyAspect {
#Pointcut("execution(* doSomething(..))")
private void soapRequest() {}
#Before("soapRequest()")
public void logBefore(JoinPoint joinPoint) {
System.out.println(joinPoint);
for (Object methodArg : joinPoint.getArgs()) {
StringBuilder sb = new StringBuilder();
try {
sb.append(methodArg.getClass().getSimpleName() + " [ ");
for (Field field : methodArg.getClass().getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
Object value = field.get(methodArg);
if (value instanceof JAXBElement) {
System.out.println(" -> is instance of");
JAXBElement jaxbElement = (JAXBElement) value;
System.out.println(" -> " + jaxbElement);
value = jaxbElement.getValue();
}
// Un-comment this in order to see the NPE
//else {
// value = field.get(methodArg).toString();
//}
sb.append("(" + field.getType() + ") " + fieldName + " = " + value + ", ");
}
sb.append("]");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(" " + sb);
}
}
}
The console log looks like this:
execution(void de.scrum_master.app.Application.doSomething(int, String, Container))
Integer [ (int) MIN_VALUE = -2147483648, (int) MAX_VALUE = 2147483647, (class java.lang.Class) TYPE = int, (class [C) digits = [C#8efb846, (class [C) DigitTens = [C#2a84aee7, (class [C) DigitOnes = [C#a09ee92, (class [I) sizeTable = [I#30f39991, (int) value = 11, (int) SIZE = 32, (int) BYTES = 4, (long) serialVersionUID = 1360826667806852920, ]
String [ (class [C) value = [C#4a574795, (int) hash = 0, (long) serialVersionUID = -6849794470754667710, (class [Ljava.io.ObjectStreamField;) serialPersistentFields = [Ljava.io.ObjectStreamField;#f6f4d33, (interface java.util.Comparator) CASE_INSENSITIVE_ORDER = java.lang.String$CaseInsensitiveComparator#23fc625e, ]
-> is instance of
-> javax.xml.bind.JAXBElement#4f023edb
Container [ (class java.lang.String) name = bar, (class javax.xml.bind.JAXBElement) jaxbElement = dummy, ]
execution(void de.scrum_master.app.Application.doSomething(int, String, Container))
Integer [ (int) MIN_VALUE = -2147483648, (int) MAX_VALUE = 2147483647, (class java.lang.Class) TYPE = int, (class [C) digits = [C#8efb846, (class [C) DigitTens = [C#2a84aee7, (class [C) DigitOnes = [C#a09ee92, (class [I) sizeTable = [I#30f39991, (int) value = 11, (int) SIZE = 32, (int) BYTES = 4, (long) serialVersionUID = 1360826667806852920, ]
String [ (class [C) value = [C#4a574795, (int) hash = 0, (long) serialVersionUID = -6849794470754667710, (class [Ljava.io.ObjectStreamField;) serialPersistentFields = [Ljava.io.ObjectStreamField;#f6f4d33, (interface java.util.Comparator) CASE_INSENSITIVE_ORDER = java.lang.String$CaseInsensitiveComparator#23fc625e, ]
Container [ (class java.lang.String) name = bar, (class javax.xml.bind.JAXBElement) jaxbElement = null, ]
See? Your error has gone. Un-comment the else block in order to see it re-appear, then remove the .toString() from the line and it goes away again. Maybe it helps you understand your error better.
By the way, I think the log output looks kinda ugly. Did you also notice that you print static fields too? You should probably filter them out. But I did not want to change more of your code because I still want you to recognise it.
The short version of your aspect without the additional debug logging for JAXBElement and without try - catch but a declared exception instead would be:
package de.scrum_master.aspect;
import java.lang.reflect.Field;
import javax.xml.bind.JAXBElement;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class MyAspect {
#Pointcut("execution(* doSomething(..))")
private void soapRequest() {}
#Before("soapRequest()")
public void logBefore(JoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint);
for (Object methodArg : joinPoint.getArgs()) {
StringBuilder sb = new StringBuilder();
sb.append(methodArg.getClass().getSimpleName() + " [ ");
for (Field field : methodArg.getClass().getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
Object value = field.get(methodArg);
if (value instanceof JAXBElement)
value = ((JAXBElement) value).getValue();
sb.append("(" + field.getType() + ") " + fieldName + " = " + value + ", ");
}
sb.append("]");
System.out.println(" " + sb);
}
}
}
Related
Could someone give me an example of how to extract coordinates for a 'word' with PDFBox
I am using this link to extract positions of individual characters:
https://www.tutorialkart.com/pdfbox/how-to-extract-coordinates-or-position-of-characters-in-pdf/
I am using this link to extract words:
https://www.tutorialkart.com/pdfbox/extract-words-from-pdf-document/
I am stuck getting coordinates for whole words.
You can extract the coordinates of words by collecting all the TextPosition objects building a word and combining their bounding boxes.
Implementing this along the lines of the two tutorials you referenced, you can extend PDFTextStripper like this:
public class GetWordLocationAndSize extends PDFTextStripper {
public GetWordLocationAndSize() throws IOException {
}
#Override
protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
String wordSeparator = getWordSeparator();
List<TextPosition> word = new ArrayList<>();
for (TextPosition text : textPositions) {
String thisChar = text.getUnicode();
if (thisChar != null) {
if (thisChar.length() >= 1) {
if (!thisChar.equals(wordSeparator)) {
word.add(text);
} else if (!word.isEmpty()) {
printWord(word);
word.clear();
}
}
}
}
if (!word.isEmpty()) {
printWord(word);
word.clear();
}
}
void printWord(List<TextPosition> word) {
Rectangle2D boundingBox = null;
StringBuilder builder = new StringBuilder();
for (TextPosition text : word) {
Rectangle2D box = new Rectangle2D.Float(text.getXDirAdj(), text.getYDirAdj(), text.getWidthDirAdj(), text.getHeightDir());
if (boundingBox == null)
boundingBox = box;
else
boundingBox.add(box);
builder.append(text.getUnicode());
}
System.out.println(builder.toString() + " [(X=" + boundingBox.getX() + ",Y=" + boundingBox.getY()
+ ") height=" + boundingBox.getHeight() + " width=" + boundingBox.getWidth() + "]");
}
}
(ExtractWordCoordinates inner class)
and run it like this:
PDDocument document = PDDocument.load(resource);
PDFTextStripper stripper = new GetWordLocationAndSize();
stripper.setSortByPosition( true );
stripper.setStartPage( 0 );
stripper.setEndPage( document.getNumberOfPages() );
Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream());
stripper.writeText(document, dummy);
(ExtractWordCoordinates test testExtractWordsForGoodJuJu)
Applied to the apache.pdf example the tutorials use you get:
2017-8-6 [(X=26.004425048828125,Y=22.00372314453125) height=5.833024024963379 width=36.31868362426758]
Welcome [(X=226.44479370117188,Y=22.00372314453125) height=5.833024024963379 width=36.5999755859375]
to [(X=265.5881652832031,Y=22.00372314453125) height=5.833024024963379 width=8.032623291015625]
The [(X=276.1641845703125,Y=22.00372314453125) height=5.833024024963379 width=14.881439208984375]
Apache [(X=293.5890197753906,Y=22.00372314453125) height=5.833024024963379 width=29.848846435546875]
Software [(X=325.98126220703125,Y=22.00372314453125) height=5.833024024963379 width=35.271636962890625]
Foundation! [(X=363.7962951660156,Y=22.00372314453125) height=5.833024024963379 width=47.871429443359375]
Custom [(X=334.0334777832031,Y=157.6195068359375) height=4.546705722808838 width=25.03936767578125]
Search [(X=360.8929138183594,Y=157.6195068359375) height=4.546705722808838 width=22.702728271484375]
You can create CustomPDFTextStripper which extends PDFTextStripper and override protected void writeString(String text, List<TextPosition> textPositions). In this overriden method you need to split textPositions by the word separator to get List<TextPosition> for each word. After that you can join each character and compute bounding box.
Full example below which contains also drawing of the resulting bounding boxes.
package com.example;
import lombok.Value;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
import org.junit.Ignore;
import org.junit.Test;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class PdfBoxTest {
private static final String BASE_DIR_PATH = "C:\\Users\\Milan\\50330484";
private static final String INPUT_FILE_PATH = "input.pdf";
private static final String OUTPUT_IMAGE_PATH = "output.jpg";
private static final String OUTPUT_BBOX_IMAGE_PATH = "output-bbox.jpg";
private static final float FROM_72_TO_300_DPI = 300.0f / 72.0f;
#Test
public void run() throws Exception {
pdfToImage();
drawBoundingBoxes();
}
#Ignore
#Test
public void pdfToImage() throws IOException {
PDDocument document = PDDocument.load(new File(BASE_DIR_PATH, INPUT_FILE_PATH));
PDFRenderer renderer = new PDFRenderer(document);
BufferedImage image = renderer.renderImageWithDPI(0, 300);
ImageIO.write(image, "JPEG", new File(BASE_DIR_PATH, OUTPUT_IMAGE_PATH));
}
#Ignore
#Test
public void drawBoundingBoxes() throws IOException {
PDDocument document = PDDocument.load(new File(BASE_DIR_PATH, INPUT_FILE_PATH));
List<WordWithBBox> words = getWords(document);
draw(words);
}
private List<WordWithBBox> getWords(PDDocument document) throws IOException {
CustomPDFTextStripper customPDFTextStripper = new CustomPDFTextStripper();
customPDFTextStripper.setSortByPosition(true);
customPDFTextStripper.setStartPage(0);
customPDFTextStripper.setEndPage(1);
Writer writer = new OutputStreamWriter(new ByteArrayOutputStream());
customPDFTextStripper.writeText(document, writer);
List<WordWithBBox> words = customPDFTextStripper.getWords();
return words;
}
private void draw(List<WordWithBBox> words) throws IOException {
BufferedImage bufferedImage = ImageIO.read(new File(BASE_DIR_PATH, OUTPUT_IMAGE_PATH));
Graphics2D graphics = bufferedImage.createGraphics();
graphics.setColor(Color.GREEN);
List<Rectangle> rectangles = words.stream()
.map(word -> new Rectangle(word.getX(), word.getY(), word.getWidth(), word.getHeight()))
.collect(Collectors.toList());
rectangles.forEach(graphics::draw);
graphics.dispose();
ImageIO.write(bufferedImage, "JPEG", new File(BASE_DIR_PATH, OUTPUT_BBOX_IMAGE_PATH));
}
private class CustomPDFTextStripper extends PDFTextStripper {
private final List<WordWithBBox> words;
public CustomPDFTextStripper() throws IOException {
this.words = new ArrayList<>();
}
public List<WordWithBBox> getWords() {
return new ArrayList<>(words);
}
#Override
protected void writeString(String text, List<TextPosition> textPositions) throws IOException {
String wordSeparator = getWordSeparator();
List<TextPosition> wordTextPositions = new ArrayList<>();
for (TextPosition textPosition : textPositions) {
String str = textPosition.getUnicode();
if (wordSeparator.equals(str)) {
if (!wordTextPositions.isEmpty()) {
this.words.add(createWord(wordTextPositions));
wordTextPositions.clear();
}
} else {
wordTextPositions.add(textPosition);
}
}
super.writeString(text, textPositions);
}
private WordWithBBox createWord(List<TextPosition> wordTextPositions) {
String word = wordTextPositions.stream()
.map(TextPosition::getUnicode)
.collect(Collectors.joining());
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int maxY = Integer.MIN_VALUE;
for (TextPosition wordTextPosition : wordTextPositions) {
minX = Math.min(minX, from72To300Dpi(wordTextPosition.getXDirAdj()));
minY = Math.min(minY, from72To300Dpi(wordTextPosition.getYDirAdj() - wordTextPosition.getHeightDir()));
maxX = Math.max(maxX, from72To300Dpi(wordTextPosition.getXDirAdj() + wordTextPosition.getWidthDirAdj()));
maxY = Math.max(maxY, from72To300Dpi(wordTextPosition.getYDirAdj()));
}
return new WordWithBBox(word, minX, minY, maxX - minX, maxY - minY);
}
}
private int from72To300Dpi(float f) {
return Math.round(f * FROM_72_TO_300_DPI);
}
#Value
private class WordWithBBox {
private final String word;
private final int x;
private final int y;
private final int width;
private final int height;
}
}
Note:
If you are interested in other options, you can check also Poppler
PDF to image
pdftoppm -r 300 -jpeg input.pdf output
Generate an XHTML file containing bounding box information for each word in the file.
pdftotext -r 300 -bbox input.pdf
Mybatis can set value with reflection?
I have a class , and it has a property , it's setter is protected . So I have to use reflection to set this value ? Mybatis can work ?
yes, mybatis use reflect to set value.
in Reflator.java(mybatis 3.3.0), mybatis will config set method.
private void addSetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingSetters = new HashMap<String, List<Method>>();
Method[] methods = getClassMethods(cls);
for (Method method : methods) {
String name = method.getName();
if (name.startsWith("set") && name.length() > 3) {
if (method.getParameterTypes().length == 1) {
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingSetters, name, method);
}
}
}
resolveSetterConflicts(conflictingSetters);
}
if your class do not have set method, when addSetFields it will add new SetInvoker for the field:
private void addSetField(Field field) {
if (isValidPropertyName(field.getName())) {
setMethods.put(field.getName(), new SetFieldInvoker(field));
setTypes.put(field.getName(), field.getType());
}
}
and the SetFieldInvoker is like this:
/**
* #author Clinton Begin
*/
public class SetFieldInvoker implements Invoker {
private Field field;
public SetFieldInvoker(Field field) {
this.field = field;
}
#Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
field.set(target, args[0]);
return null;
}
#Override
public Class<?> getType() {
return field.getType();
}
}
the DefaultResultSetHandler calls BeanWrapper's setBeanProperty method will call getSetInvoker
private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
try {
Invoker method = metaClass.getSetInvoker(prop.getName());
Object[] params = {value};
try {
method.invoke(object, params);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} catch (Throwable t) {
throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);
}
}
the whole call chain maybe like this:
DefaultSqlSession##selectList -->SimpleExecutor##doQuery --> SimpleStatementHandler##query --> DefaultResultSetHandler##handleResultSets
I have each record spread across multiple lines in the input file(Very huge file).
Ex:
Id: 2
ASIN: 0738700123
title: Test tile for this product
group: Book
salesrank: 168501
similar: 5 0738700811 1567184912 1567182813 0738700514 0738700915
categories: 2
|Books[283155]|Subjects[1000]|Religion & Spirituality[22]|Earth-Based Religions[12472]|Wicca[12484]
|Books[283155]|Subjects[1000]|Religion & Spirituality[22]|Earth-Based Religions[12472]|Witchcraft[12486]
reviews: total: 12 downloaded: 12 avg rating: 4.5
2001-12-16 cutomer: A11NCO6YTE4BTJ rating: 5 votes: 5 helpful: 4
2002-1-7 cutomer: A9CQ3PLRNIR83 rating: 4 votes: 5 helpful: 5
How to identify and process each multi line record in spark?
If the multi-line data has a defined record separator, you could use the hadoop support for multi-line records, providing the separator through a hadoop.Configuration object:
Something like this should do:
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.io.{LongWritable, Text}
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat
val conf = new Configuration
conf.set("textinputformat.record.delimiter", "id:")
val dataset = sc.newAPIHadoopFile("/path/to/data", classOf[TextInputFormat], classOf[LongWritable], classOf[Text], conf)
val data = dataset.map(x=>x._2.toString)
This will provide you with an RDD[String] where each element corresponds to a record. Afterwards you need to parse each record following your application requirements.
I have done this by implementing custom input format and record reader.
public class ParagraphInputFormat extends TextInputFormat {
#Override
public RecordReader<LongWritable, Text> createRecordReader(InputSplit inputSplit, TaskAttemptContext taskAttemptContext) {
return new ParagraphRecordReader();
}
}
public class ParagraphRecordReader extends RecordReader<LongWritable, Text> {
private long end;
private boolean stillInChunk = true;
private LongWritable key = new LongWritable();
private Text value = new Text();
private FSDataInputStream fsin;
private DataOutputBuffer buffer = new DataOutputBuffer();
private byte[] endTag = "\n\r\n".getBytes();
public void initialize(InputSplit inputSplit, TaskAttemptContext taskAttemptContext) throws IOException, InterruptedException {
FileSplit split = (FileSplit) inputSplit;
Configuration conf = taskAttemptContext.getConfiguration();
Path path = split.getPath();
FileSystem fs = path.getFileSystem(conf);
fsin = fs.open(path);
long start = split.getStart();
end = split.getStart() + split.getLength();
fsin.seek(start);
if (start != 0) {
readUntilMatch(endTag, false);
}
}
public boolean nextKeyValue() throws IOException {
if (!stillInChunk) return false;
boolean status = readUntilMatch(endTag, true);
value = new Text();
value.set(buffer.getData(), 0, buffer.getLength());
key = new LongWritable(fsin.getPos());
buffer.reset();
if (!status) {
stillInChunk = false;
}
return true;
}
public LongWritable getCurrentKey() throws IOException, InterruptedException {
return key;
}
public Text getCurrentValue() throws IOException, InterruptedException {
return value;
}
public float getProgress() throws IOException, InterruptedException {
return 0;
}
public void close() throws IOException {
fsin.close();
}
private boolean readUntilMatch(byte[] match, boolean withinBlock) throws IOException {
int i = 0;
while (true) {
int b = fsin.read();
if (b == -1) return false;
if (withinBlock) buffer.write(b);
if (b == match[i]) {
i++;
if (i >= match.length) {
return fsin.getPos() < end;
}
} else i = 0;
}
}
}
endTag identifies the end of each record.
I was using this Jersey annotated Rest consumer POJO without any issue over http, but then we had to start deploying our app over HTTPS.
I am getting a big fat 404, and I concluded, that everything else worked in the code (which is running over MULE beautifully btw) and my POJO simply doesn't consume HTTPS requests.
I suspect that
I am out of luck and Jersey doesn't speak https and I have to redo something here or revert back the part to http
There is a pretty little annotation that i add and voiala! all good.
Obviously, hoping for 2. here.
Here is the code:
package org.acme.api;
import java.net.UnknownHostException;
import java.util.List;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.POST;
import javax.ws.rs.PathParam;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBList;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
import com.mongodb.DBObject;
import com.mongodb.WriteResult;
import com.mongodb.util.JSON;
import com.mongodb.DB;
/**
REST Web service implementation.
#author menashe#acme.org
*/
#Path("/")
public class Product {
MongoClient client = null;
DB db = null;
DBCollection products = null;
public Product() throws UnknownHostException {
this.client = new MongoClient(new ServerAddress("localhost", 27027));
this.db = this.client.getDB("dailysale");
this.products = this.db.getCollection("products");
}
#GET
#Produces("application/json")
#Path("/product/{productId}")
public String retrieveProduct(#PathParam("productId") Integer productId) {
String product;
try{
DBObject query = new BasicDBObject("productId", String.valueOf(productId));
product = this.products.findOne(query).toString();
} catch(Exception e) {
product = "{ error: 'We were not able to find product with Id: '" + productId + ". " + e.getLocalizedMessage() + " }";
}
return product;
}
#GET
#Produces("application/json")
#Path("/product/grid/{query}")
#HeaderParam("range")
public Response listProducts(#HeaderParam("range") String range, #PathParam("query") String query) {
Integer pageNum = 1;
Integer pageSize = 10;
Integer resultCount = null;
BasicDBList result = new BasicDBList();
Integer firstItem = (pageNum - 1 ) * pageSize;
Long allProductsCount = null;
Integer lastItem = null;
DBObject searchQuery = new BasicDBObject("$regex", query);
try {
DBCursor productListCursor = products.find(searchQuery).skip(firstItem).limit( pageSize );
List<DBObject> productList = productListCursor.toArray();
for(DBObject product : productList) {
result.add(this.itemToGridConverter(product));
}
resultCount = productList.size();
allProductsCount = products.count();
lastItem = firstItem + resultCount - 1;
} catch(Exception e) {
result = new BasicDBList();
result.add(new BasicDBObject("error", "We were not able to retrieve all products with pageSize: " + pageSize + " and pageNumber " + pageNum + ". " + e.getLocalizedMessage() ));
}
return Response.ok(result).header("Content-Range", "items " + firstItem + "-" + lastItem + "/" + allProductsCount).build();
}
#GET
#Produces("application/json")
#Path("/product/grid/")
#HeaderParam("range")
public Response listProducts(#HeaderParam("range") String range) {
Integer pageNum = 1;
Integer pageSize = 10;
Integer resultCount = null;
BasicDBList result = new BasicDBList();
Integer firstItem = (pageNum - 1 ) * pageSize;
Long allProductsCount = null;
Integer lastItem = null;
try {
DBCursor productListCursor = products.find().skip(firstItem).limit( pageSize ).sort( new BasicDBObject( "sku", 1)) ;
List<DBObject> productList = productListCursor.toArray();
for(DBObject product : productList) {
result.add(this.itemToGridConverter(product));
}
resultCount = productList.size();
allProductsCount = products.count();
lastItem = firstItem + resultCount - 1;
} catch(Exception e) {
result = new BasicDBList();
result.add(new BasicDBObject("error", "We were not able to retrieve all products with pageSize: " + pageSize + " and pageNumber " + pageNum + ". " + e.getLocalizedMessage() ));
}
return Response.ok( result ).header("Content-Range", "items " + firstItem + "-" + lastItem + "/" + allProductsCount).build();
}
#GET
#Produces("application/json")
#Path("/product/grid/?{sort}")
#HeaderParam("range")
public Response listProductsWithSort(#HeaderParam("range") String range, #PathParam("sort") String sorting) {
Response response = null;
return response;
}
#PUT
#Produces("application/json")
#Path("/product")
public String createProduct(String productJson) {
DBObject product = null;
String result;
try{
product = (DBObject)JSON.parse(productJson);
WriteResult wResult =this.products.insert(product);
result = wResult.toString();
}
catch(Exception e){
result = "{ error: 'We were not able to insert the product.' " + e.getLocalizedMessage() + " }";
}
return result;
}
#POST
#Produces("application/json")
#Path("/product/{productId}")
public String updateProduct(#PathParam("productId") Integer productId, String productJson) {
DBObject product = null;
DBObject query = new BasicDBObject();
String result = null;
try{
product = (DBObject)JSON.parse(productJson);
query.put("productId", productId.toString());
WriteResult wResult = this.products.update(query, product);
result = wResult.toString();
}
catch(Exception e){
result = "{ error: 'We were not able to update the product.' " + e.getLocalizedMessage() + " }";
}
return result;
}
#DELETE
#Produces("application/json")
#Path("/product/{productId}")
public String deleteProduct(#PathParam("productId") Integer productId) {
return "{ error: 'This function is not implemented [delete].' }";
}
private DBObject itemToGridConverter(DBObject product) {
DBObject item = new BasicDBObject();
BasicDBList images = (BasicDBList)product.get("images");
BasicDBObject firstImage = (BasicDBObject)images.get(0);
item.put("productId", product.get("productId"));
item.put("sku", product.get("sku"));
item.put("image", firstImage.get("imageurl"));
BasicDBList spec = (BasicDBList)product.get("productSpecifics");
BasicDBObject firstSpec = (BasicDBObject)spec.get(0);
BasicDBObject attributes = (BasicDBObject)product.get("productAttributes");
item.put("name", firstSpec.get("title"));
item.put("cost", "no source");
item.put("list_price", attributes.get("defaultsalePrice"));
item.put("qty_available", product.get("qtyonHand"));
item.put("condition", "no source");
item.put("active", "true".equals(product.get("active")) ? "Yes" : "No");
item.put("manufacturer", attributes.get("manufacturer"));
item.put("part_number", attributes.get("manufacturerPartNumber"));
item.put("date_created", product.get("_id"));
return item;
}
}
Thanks much.
UPDATE:
I fixed the issue by fixing the path. The issue was how MULE resolves scope boundaries and here the original #Path / was actually in the previous scope. Now that we changed the flow the #Path became /controllers/.
Uyodiin Mevin.
I came across an odd occurrence while using mongodb + their java driver.
When I do a grouping query the datatype for the key changes from an int to a double.
(ie. I am grouping on a key for 'hours', which is stored as an int within all the objects, but the key changes into a double type in the results I get back).
It isn't a huge issue...but it is weird that it would just arbitrarily change the datatype of a key-value pair like that. Has anyone else had this come up? is this normal behaviour?
Thanks,
p.s. Doing a regular .find() query returns correct datatype, fyi.
Edit:
Some example code:
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.QueryOperators;
public class MongoTestQueries {
private static final String TESTDBNAME = "badgerbadgerbadger";
private static final String TESTCOLNAME = "mushroom";
private static final Long TESTMAX = 50L;
private static final String KEY1 = "a";
private static final String KEY2 = "snake";
private static final String KEY3 = "plane";
/**
* This starts running it.
*
* #param args
* the arguments.
*/
public static void main(final String[] args) {
//You'll need to write your own code here for connecting to db as you see fit.
MongoConnection mc = new MongoConnection("someserver.com", TESTDBNAME);
mc.setCurCol(TESTCOLNAME);
mc.getCurCol().drop();
mc.setCurCol(TESTCOLNAME);
DBCollection col = mc.getCurCol();
populateCollection(col);
System.out.println(col.count() + " inserted into db.");
regGroupSearch(col);
}
private static void populateCollection(DBCollection col) {
for (Long l = 0L; l < TESTMAX; l++) {
col.insert(new BasicDBObject(KEY1, new Integer(l.intValue())).append(KEY2,
Math.random()).append(KEY3, (TESTMAX - l) + "a string"));
}
}
private static void regGroupSearch(final DBCollection col) {
System.out.println("Group Search:");
DBObject key = new BasicDBObject(KEY1, true).append(KEY3, true);
DBObject cond = new BasicDBObject().append(KEY1, new BasicDBObject(QueryOperators.GT, 4.0));
DBObject initial = new BasicDBObject("count", 0).append("sum", 0);
String reduce = "function(obj,prev){prev.sum+=obj." + KEY2 + ",prev.count+=1}";
String finalize = "function(obj){obj.ave = obj.sum/obj.count}";
DBObject groupResult = col.group(key, cond, initial, reduce, finalize);
printDBObject(groupResult);
System.out.println("Done.");
}
private static void printDBObject(final DBObject toPrint) {
for (String k : toPrint.keySet()) {
System.out.println(k + ": " + toPrint.get(k));
}
}
}