Skip to content

Commit

Permalink
feat: Add JSON/HTTP method to JsonRequest
Browse files Browse the repository at this point in the history
This makes the method available through the entire request-handling chain for JSON requests, allowing (for example), when PUTing (creating) a Turnout that uses a feedback Sensor, to include the JSON for that Sensor in the Turnout's sensor property (instead of just refering to it by name).
  • Loading branch information
rhwood committed Mar 7, 2020
1 parent fb5a4a8 commit c56084b
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 35 deletions.
4 changes: 2 additions & 2 deletions java/src/jmri/server/json/JsonClientHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void onMessage(JsonNode root) throws IOException {
String type = root.path(TYPE).asText();
int id = root.path(ID).asInt(0);
JsonNode data = root.path(DATA);
JsonRequest request = new JsonRequest(connection.getLocale(), connection.getVersion(), id);
JsonRequest request = new JsonRequest(connection.getLocale(), connection.getVersion(), method, id);
try {
if (preferences.getValidateClientMessages()) {
schemas.validateMessage(root, false, request);
Expand Down Expand Up @@ -159,7 +159,7 @@ public void onMessage(JsonNode root) throws IOException {
setVersion(data.path(VERSION).asText(connection.getVersion()), id);
// since locale or version may have changed, ensure any
// response is using new version and locale
request = new JsonRequest(connection.getLocale(), connection.getVersion(), id);
request = new JsonRequest(connection.getLocale(), connection.getVersion(), method, id);
}
if (services.get(type) != null) {
for (JsonSocketService<?> service : services.get(type)) {
Expand Down
2 changes: 1 addition & 1 deletion java/src/jmri/server/json/JsonConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public void sendMessage(@Nonnull JsonNode message, @Nonnull JsonRequest request)
* @throws IOException if unable to send the message
*/
public void sendMessage(@Nonnull JsonNode message, int id) throws IOException {
sendMessage(message, new JsonRequest(getLocale(), getVersion(), id));
sendMessage(message, new JsonRequest(getLocale(), getVersion(), JSON.GET, id));
}

public String getVersion() {
Expand Down
14 changes: 7 additions & 7 deletions java/src/jmri/server/json/JsonHttpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public abstract JsonNode doGet(@Nonnull String type, @Nonnull String name, @Nonn
public JsonNode doGet(@Nonnull String type, @Nonnull String name, @Nonnull JsonNode data,
@Nonnull Locale locale, int id)
throws JsonException {
return doGet(type, name, data, new JsonRequest(locale, JSON.V5, id));
return doGet(type, name, data, new JsonRequest(locale, JSON.V5, JSON.GET, id));
}

/**
Expand Down Expand Up @@ -146,7 +146,7 @@ public abstract JsonNode doPost(@Nonnull String type, @Nonnull String name, @Non
@Nonnull
public JsonNode doPost(@Nonnull String type, @Nonnull String name, @Nonnull JsonNode data,
@Nonnull Locale locale, int id) throws JsonException {
return doPost(type, name, data, new JsonRequest(locale, JSON.V5, id));
return doPost(type, name, data, new JsonRequest(locale, JSON.V5, JSON.POST, id));
}

/**
Expand Down Expand Up @@ -193,7 +193,7 @@ public JsonNode doPut(@Nonnull String type, @Nonnull String name, @Nonnull JsonN
public JsonNode doPut(@Nonnull String type, @Nonnull String name, @Nonnull JsonNode data, @Nonnull Locale locale,
int id)
throws JsonException {
return doPut(type, name, data, new JsonRequest(locale, JSON.V5, id));
return doPut(type, name, data, new JsonRequest(locale, JSON.V5, JSON.PUT, id));
}

/**
Expand Down Expand Up @@ -239,7 +239,7 @@ public void doDelete(@Nonnull String type, @Nonnull String name, @Nonnull JsonNo
public void doDelete(@Nonnull String type, @Nonnull String name, @Nonnull JsonNode data, @Nonnull Locale locale,
int id)
throws JsonException {
doDelete(type, name, data, new JsonRequest(locale, JSON.V5, id));
doDelete(type, name, data, new JsonRequest(locale, JSON.V5, JSON.DELETE, id));
}

/**
Expand Down Expand Up @@ -287,7 +287,7 @@ public abstract JsonNode doGetList(@Nonnull String type, @Nonnull JsonNode data,
@Nonnull
public JsonNode doGetList(@Nonnull String type, @Nonnull JsonNode data, @Nonnull Locale locale, int id)
throws JsonException {
return doGetList(type, data, new JsonRequest(locale, JSON.V5, id));
return doGetList(type, data, new JsonRequest(locale, JSON.V5, JSON.GET, id));
}

/**
Expand Down Expand Up @@ -353,7 +353,7 @@ public abstract JsonNode doSchema(@Nonnull String type, boolean server, @Nonnull
@Nonnull
public JsonNode doSchema(@Nonnull String type, boolean server, @Nonnull Locale locale, int id)
throws JsonException {
return doSchema(type, server, new JsonRequest(locale, JSON.V5, id));
return doSchema(type, server, new JsonRequest(locale, JSON.V5, JSON.GET, id));
}

/**
Expand Down Expand Up @@ -479,7 +479,7 @@ public final void throwDeleteConflictException(@Nonnull String type, @Nonnull St
public final void throwDeleteConflictException(@Nonnull String type, @Nonnull String name,
@Nonnull ArrayNode conflicts,
@Nonnull Locale locale, int id) throws JsonException {
throwDeleteConflictException(type, name, conflicts, new JsonRequest(locale, JSON.V5, id));
throwDeleteConflictException(type, name, conflicts, new JsonRequest(locale, JSON.V5, JSON.DELETE, id));
}

/**
Expand Down
15 changes: 11 additions & 4 deletions java/src/jmri/server/json/JsonNamedBeanHttpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,15 @@ protected abstract ObjectNode doGet(T bean, @Nonnull String name, @Nonnull Strin
*/
@Override
@CheckForNull
public T getNamedBean(@Nonnull String name, @Nonnull String type, @Nonnull JsonRequest request) throws JsonException {
public T getNamedBean(@Nonnull String type, @Nonnull String name, @Nonnull JsonNode data, @Nonnull JsonRequest request) throws JsonException {
try {
if (!data.isEmpty() && !data.isNull()) {
if (JSON.PUT.equals(request.method)) {
doPut(type, name, data, request);
} else if (JSON.POST.equals(request.method)) {
doPost(type, name, data, request);
}
}
return getManager().getBySystemName(name);
} catch (IllegalArgumentException ex) {
throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, Bundle.getMessage(request.locale, "ErrorInvalidSystemName", name, type), request.id);
Expand Down Expand Up @@ -194,7 +201,7 @@ protected void doDelete(@CheckForNull T bean, @Nonnull String name, @Nonnull Str
@Nonnull
protected ObjectNode doPost(T bean, @Nonnull String name, @Nonnull String type, @Nonnull JsonNode data, @Nonnull Locale locale, int id)
throws JsonException {
return doPost(bean, name, type, data, new JsonRequest(locale, JSON.V5, id));
return doPost(bean, name, type, data, new JsonRequest(locale, JSON.V5, JSON.POST, id));
}

/**
Expand All @@ -215,7 +222,7 @@ protected ObjectNode doPost(T bean, @Nonnull String name, @Nonnull String type,
*/
@Deprecated
protected void doDelete(@CheckForNull T bean, @Nonnull String name, @Nonnull String type, @Nonnull JsonNode data, @Nonnull Locale locale, int id) throws JsonException {
doDelete(type, name, data, new JsonRequest(locale, JSON.V5, id));
doDelete(type, name, data, new JsonRequest(locale, JSON.V5, JSON.DELETE, id));
}

/**
Expand Down Expand Up @@ -263,7 +270,7 @@ protected final void deleteBean(@CheckForNull T bean, @Nonnull String name, @Non
*/
@Deprecated
protected final void deleteBean(@CheckForNull T bean, @Nonnull String name, @Nonnull String type, @Nonnull JsonNode data, @Nonnull Locale locale, int id) throws JsonException {
deleteBean(bean, name, type, data, new JsonRequest(locale, JSON.V5, id));
deleteBean(bean, name, type, data, new JsonRequest(locale, JSON.V5, JSON.DELETE, id));
}

/**
Expand Down
4 changes: 2 additions & 2 deletions java/src/jmri/server/json/JsonNamedBeanSocketService.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public NamedBeanListener(T bean) {
@Override
public void propertyChange(PropertyChangeEvent evt) {
try {
connection.sendMessage(service.doGet(this.bean, this.bean.getSystemName(), service.getType(), new JsonRequest(getLocale(), getVersion(), 0)), 0);
connection.sendMessage(service.doGet(this.bean, this.bean.getSystemName(), service.getType(), new JsonRequest(getLocale(), getVersion(), JSON.GET, 0)), 0);
} catch (
IOException |
JsonException ex) {
Expand Down Expand Up @@ -150,7 +150,7 @@ private void handleChange(PropertyChangeEvent evt) throws IOException {
try {
// send the new list
connection.sendMessage(service.doGetList(service.getType(),
service.getObjectMapper().createObjectNode(), new JsonRequest(getLocale(), getVersion(), 0)), 0);
service.getObjectMapper().createObjectNode(), new JsonRequest(getLocale(), getVersion(), JSON.GET, 0)), 0);
//child added or removed, reset listeners
if (evt.getPropertyName().equals("length")) { // NOI18N
removeListenersFromRemovedBeans();
Expand Down
24 changes: 15 additions & 9 deletions java/src/jmri/server/json/JsonNonProvidedNamedBeanHttpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ protected final JsonNode doGetList(Manager<T> manager, String type, JsonNode dat
@Nonnull
protected final JsonNode doGetList(Manager<T> manager, String type, JsonNode data, Locale locale, int id)
throws JsonException {
return doGetList(manager, type, data, new JsonRequest(locale, JSON.V5, id));
return doGetList(manager, type, data, new JsonRequest(locale, JSON.V5, JSON.GET, id));
}

/**
Expand Down Expand Up @@ -129,20 +129,26 @@ protected abstract ObjectNode doGet(T bean, @Nonnull String name, @Nonnull Strin
protected ObjectNode doGet(T bean, @Nonnull String name, @Nonnull String type, @Nonnull Locale locale,
int id)
throws JsonException {
return doGet(bean, name, type, new JsonRequest(locale, JSON.V5, id));
return doGet(bean, name, type, new JsonRequest(locale, JSON.V5, JSON.GET, id));
}

/**
* Get the NamedBean matching name and type.
* Get the NamedBean matching name and type. If the request has a method
* other than GET, this may modify or create the NamedBean requested. Note
* that name or data may be null, but it is an error to have both be null.
*
* @param name the name of the requested object
* @param type the type of the requested object
* @param name the name of the requested object
* @param type the type of the requested object
* @param data the JsonNode containing the JSON representation of the
* bean to get
* @param request the JSON request
* @return the matching NamedBean or null if there is no match
* @throws JsonException if the name is invalid for the type
* @throws JsonException if the name is invalid for the type
* @throws IllegalArgumentException if both name is null and data is empty
*/
@CheckForNull
protected abstract T getNamedBean(@Nonnull String name, @Nonnull String type, @Nonnull JsonRequest request) throws JsonException;
protected abstract T getNamedBean(@Nonnull String type, @Nonnull String name, @Nonnull JsonNode data,
@Nonnull JsonRequest request) throws JsonException;

/**
* Create the JsonNode for a {@link jmri.NamedBean} object.
Expand Down Expand Up @@ -196,7 +202,7 @@ public ObjectNode getNamedBean(T bean, @Nonnull String name, @Nonnull String typ
protected ObjectNode getNamedBean(T bean, @Nonnull String name, @Nonnull String type, @Nonnull Locale locale,
int id)
throws JsonException {
return getNamedBean(bean, name, type, new JsonRequest(locale, JSON.V5, id));
return getNamedBean(bean, name, type, new JsonRequest(locale, JSON.V5, JSON.GET, id));
}

/**
Expand Down Expand Up @@ -254,6 +260,6 @@ protected T postNamedBean(T bean, @Nonnull JsonNode data, @Nonnull String name,
@Nonnull
protected T postNamedBean(T bean, @Nonnull JsonNode data, @Nonnull String name, @Nonnull String type,
@Nonnull Locale locale, int id) throws JsonException {
return postNamedBean(bean, data, name, type, new JsonRequest(locale, JSON.V5, id));
return postNamedBean(bean, data, name, type, new JsonRequest(locale, JSON.V5, JSON.POST, id));
}
}
21 changes: 21 additions & 0 deletions java/src/jmri/server/json/JsonRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,34 @@ public class JsonRequest {

public final int id;
public final Locale locale;
public final String method;
public final String version;

/**
* Create a JSON request container with the method {@value JSON#GET}.
*
* @param locale the request locale
* @param version the JSON version to use
* @param id the ID of the request
*/
public JsonRequest(@Nonnull Locale locale, @Nonnull String version, int id) {
this(locale, version, JSON.GET, id);
}

/**
* Create a JSON request container.
*
* @param locale the request locale
* @param version the JSON version to use
* @param method the JSON method to use
* @param id the ID of the request
*/
public JsonRequest(@Nonnull Locale locale, @Nonnull String version, @Nonnull String method, int id) {
Objects.requireNonNull(locale, "Locale must be non-null");
Objects.requireNonNull(version, "Version must be specified");
this.locale = locale;
this.version = version;
this.method = method;
this.id = id;
}
}
4 changes: 2 additions & 2 deletions java/src/jmri/server/json/JsonSocketService.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public abstract void onMessage(@Nonnull String type, @Nonnull JsonNode data, @No
@Deprecated
public void onMessage(@Nonnull String type, @Nonnull JsonNode data, @Nonnull String method,
@Nonnull Locale locale, int id) throws IOException, JmriException, JsonException {
onMessage(type, data, method, new JsonRequest(locale, JSON.V5, id));
onMessage(type, data, method, new JsonRequest(locale, JSON.V5, method, id));
}

/**
Expand Down Expand Up @@ -136,7 +136,7 @@ public abstract void onList(@Nonnull String type, @Nonnull JsonNode data, @Nonnu
@Deprecated
public void onList(@Nonnull String type, @Nonnull JsonNode data, @Nonnull Locale locale, int id)
throws IOException, JmriException, JsonException {
onList(type, data, new JsonRequest(locale, JSON.V5, id));
onList(type, data, new JsonRequest(locale, JSON.V5, JSON.GET, id));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,15 @@ public JsonNode doSchema(String type, boolean server, JsonRequest request) throw
}

@Override
public LayoutBlock getNamedBean(String name, String type, JsonRequest request) throws JsonException {
public LayoutBlock getNamedBean(String type, String name, JsonNode data, JsonRequest request) throws JsonException {
try {
if (!data.isEmpty() && !data.isNull()) {
if (JSON.PUT.equals(request.method)) {
doPut(type, name, data, request);
} else if (JSON.POST.equals(request.method)) {
doPost(type, name, data, request);
}
}
return InstanceManager.getDefault(LayoutBlockManager.class).getBySystemName(name);
} catch (IllegalArgumentException ex) {
throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, Bundle.getMessage(request.locale, "ErrorInvalidSystemName", name, type), request.id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import jmri.InstanceManager;
import jmri.SignalHead;
import jmri.SignalHeadManager;
import jmri.server.json.JSON;
import jmri.server.json.JsonException;
import jmri.server.json.JsonNonProvidedNamedBeanHttpService;
import jmri.server.json.JsonRequest;
Expand Down Expand Up @@ -110,8 +111,15 @@ public JsonNode doSchema(String type, boolean server, JsonRequest request) throw
}

@Override
public SignalHead getNamedBean(String name, String type, JsonRequest request) throws JsonException {
public SignalHead getNamedBean(String type, String name, JsonNode data, JsonRequest request) throws JsonException {
try {
if (!data.isEmpty() && !data.isNull()) {
if (JSON.PUT.equals(request.method)) {
doPut(type, name, data, request);
} else if (JSON.POST.equals(request.method)) {
doPost(type, name, data, request);
}
}
return InstanceManager.getDefault(SignalHeadManager.class).getBySystemName(name);
} catch (IllegalArgumentException ex) {
throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, Bundle.getMessage(request.locale, "ErrorInvalidSystemName", name, type), request.id);
Expand Down
15 changes: 10 additions & 5 deletions java/src/jmri/server/json/turnout/JsonTurnoutHttpService.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,22 @@ public ObjectNode doPost(Turnout turnout, String name, String type, JsonNode dat
return this.doGet(turnout, name, type, request);
}

private void addSensorToTurnout(@Nonnull Turnout turnout, @Nonnull JsonNode node, int number, @Nonnull JsonRequest request) throws JsonException {
private void addSensorToTurnout(@Nonnull Turnout turnout, @Nonnull JsonNode data, int number, @Nonnull JsonRequest request) throws JsonException {
try {
if (node.isNull()) {
if (data.isNull()) {
turnout.provideFeedbackSensor(null, number);
} else if (node.isTextual()) {
Sensor sensor = sensorService.getNamedBean(node.asText(), SENSOR, request);
} else {
Sensor sensor = null;
if (data.isTextual()) {
sensor = sensorService.getNamedBean(SENSOR, data.asText(), mapper.nullNode(), request);
} else if (data.isObject()) {
sensor = sensorService.getNamedBean(SENSOR, data.path(JSON.NAME).asText(), data, request);
}
if (sensor != null) {
turnout.provideFeedbackSensor(sensor.getSystemName(), number);
} else {
throw new JsonException(404,
Bundle.getMessage(request.locale, "ErrorNotFound", SENSOR, node.asText()), request.id);
Bundle.getMessage(request.locale, "ErrorNotFound", SENSOR, data.asText()), request.id);
}
}
} catch (JmriException ex) {
Expand Down
2 changes: 1 addition & 1 deletion java/src/jmri/web/servlet/json/JsonServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ private JsonRequest createJsonRequest(HttpServletRequest request) {
if (path.length > 1 && VERSIONS.stream().anyMatch(v -> v.equals(path[1]))) {
version = path[1];
}
return new JsonRequest(request.getLocale(), version, id);
return new JsonRequest(request.getLocale(), version, request.getMethod().toLowerCase(), id);
}

/**
Expand Down

0 comments on commit c56084b

Please sign in to comment.