Skip to content

Commit

Permalink
Add support for handling JSON input.
Browse files Browse the repository at this point in the history
  • Loading branch information
mnlipp committed May 2, 2024
1 parent cb8c255 commit 9c1fb7e
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 0 deletions.
1 change: 1 addition & 0 deletions org.jgrapes.io/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
dependencies {
api project(':org.jgrapes.core')
api project(':org.jgrapes.util')
api 'com.fasterxml.jackson.core:jackson-databind:[2.13,3)'
}

sourceSets {
Expand Down
74 changes: 74 additions & 0 deletions org.jgrapes.io/src/org/jgrapes/io/util/JsonReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* JGrapes Event Driven Framework
* Copyright (C) 2022 Michael N. Lipp
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 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 General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/

package org.jgrapes.io.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.jgrapes.core.Channel;
import org.jgrapes.core.EventPipeline;
import org.jgrapes.io.util.events.DataInput;
import org.jgrapes.io.util.events.JsonParsingError;

/**
* A {@link ManagedBufferStreamer} that feeds the data to a JSON parser.
* When the data is fully parsed, it is made available by firing a
* {@link DataInput} event.
*
* @since 2.8
*/
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
public class JsonReader extends ManagedBufferStreamer {

/**
* Instantiates a new JSON reader.
*
* @param <R> the result data type
* @param mapper the mapper
* @param resultType the result type
* @param pipeline the pipeline to use for sending the
* {@link DataInput} event
* @param channel the channel to use for sending the
* {@link DataInput} event
*/
public <R> JsonReader(ObjectMapper mapper, Class<R> resultType,
EventPipeline pipeline, Channel channel) {
super(r -> {
try {
pipeline.fire(new DataInput<R>(mapper.readValue(r, resultType)),
channel);
} catch (Exception e) {
pipeline.fire(new JsonParsingError(e), channel);
}
});
}

/**
* Instantiates a new JSON reader that uses a default object mapper.
*
* @param <R> the result data type
* @param resultType the result type
* @param pipeline the pipeline to use for sending the
* {@link DataInput} event
* @param channel the channel to use for sending the
* {@link DataInput} event
*/
public <R> JsonReader(Class<R> resultType, EventPipeline pipeline,
Channel channel) {
this(new ObjectMapper(), resultType, pipeline, channel);
}
}
50 changes: 50 additions & 0 deletions org.jgrapes.io/src/org/jgrapes/io/util/events/DataInput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* JGrapes Event Driven Framework
* Copyright (C) 2024 Michael N. Lipp
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 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 Affero General Public License
* for more details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/

package org.jgrapes.io.util.events;

import org.jgrapes.core.Event;

/**
* Signals that some data is available for handling.
*
* @param <T>
*/
public class DataInput<T> extends Event<Void> {

private T data;

/**
* Instantiates a new data input providing the given data.
*
* @param data the data
*/
public DataInput(T data) {
this.data = data;
}

/**
* Gets the data.
*
* @return the data
*/
public T data() {
return data;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* JGrapes Event Driven Framework
* Copyright (C) 2024 Michael N. Lipp
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 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 Affero General Public License
* for more details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/

package org.jgrapes.io.util.events;

import org.jgrapes.core.events.Error;

/**
* Signals an error that occurred while parsing JSON.
*/
public class JsonParsingError extends Error {

/**
* Instantiates a new JSON parsing error.
*
* @param throwable the throwable
*/
public JsonParsingError(Throwable throwable) {
super(null, throwable);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Events associated with classes from {@link org.jgrapes.io.util}.
*/

package org.jgrapes.io.util.events;
69 changes: 69 additions & 0 deletions org.jgrapes.io/test/org/jgrapes/io/test/JsonReaderTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.jgrapes.io.test;

import java.io.IOException;
import java.nio.CharBuffer;
import java.util.Map;
import org.jgrapes.core.Channel;
import org.jgrapes.core.Component;
import org.jgrapes.core.Components;
import org.jgrapes.core.annotation.Handler;
import org.jgrapes.core.events.Started;
import org.jgrapes.io.util.JsonReader;
import org.jgrapes.io.util.ManagedBuffer;
import org.jgrapes.io.util.ManagedBufferPool;
import org.jgrapes.io.util.events.DataInput;
import static org.junit.Assert.*;
import org.junit.Test;

public class JsonReaderTests {

public class TestApp extends Component {

@Handler
public void onStarted(Started event, Channel channel)
throws InterruptedException, IOException {
registerAsGenerator();
var charBufferPool = new ManagedBufferPool<>(ManagedBuffer::new,
() -> CharBuffer.allocate(4096), 2).setName("Test");

// Create reader
JsonReader rdr
= new JsonReader(Object.class, activeEventPipeline(), this);

// Feed
var data = charBufferPool.acquire();
data.backingBuffer().append("{\"hello\": \"world\"}");
data.backingBuffer().flip();
rdr.feed(data);
data.unlockBuffer();

// End of feed
rdr.feed(null);
}

@Handler
public void onJson(DataInput<Object> event, Channel channel) {
result = event.data();
unregisterAsGenerator();
}
}

private Object result;

@SuppressWarnings("unchecked")
@Test(timeout = 1000)
public void test() throws InterruptedException, IOException {

var app = new TestApp();
Components.start(app);

while (result == null) {
Thread.sleep(10);
}
assertTrue(result instanceof Map);
assertEquals("world", ((Map<String, String>) result).get("hello"));

Components.awaitExhaustion();
}

}

0 comments on commit 9c1fb7e

Please sign in to comment.