From 6bb3ade288edcf2b59024ea083caa4bec63c1c71 Mon Sep 17 00:00:00 2001 From: Christophe Carvalho Vilas-Boas Date: Thu, 18 Jun 2020 02:20:32 +0200 Subject: [PATCH 1/5] core: Call Actions automatically core: ReceivedMessageHelper and GenericHelper clean --- .../TouchPortalPluginAnnotationProcessor.java | 68 ++++----- .../TouchPortal/Helpers/GenericHelper.java | 86 +++++++++-- .../Helpers/ReceivedMessageHelper.java | 144 +++++++++++++++--- Library/build.gradle | 4 + .../TouchPortal/TouchPortalPlugin.java | 65 ++++++-- .../TouchPortal/test/LibraryTests.java | 57 ++++++- .../test/TouchPortalPluginTest.java | 4 +- .../TouchPortalPluginTest/plugin.config | 2 +- .../sample/TouchPortalPluginExample.java | 32 ++-- .../sample/TouchPortalKotlinPlugin.kt | 3 +- 10 files changed, 361 insertions(+), 104 deletions(-) diff --git a/AnnotationsProcessor/src/main/java/com/github/ChristopheCVB/TouchPortal/AnnotationsProcessor/TouchPortalPluginAnnotationProcessor.java b/AnnotationsProcessor/src/main/java/com/github/ChristopheCVB/TouchPortal/AnnotationsProcessor/TouchPortalPluginAnnotationProcessor.java index c92fc41..6538b40 100644 --- a/AnnotationsProcessor/src/main/java/com/github/ChristopheCVB/TouchPortal/AnnotationsProcessor/TouchPortalPluginAnnotationProcessor.java +++ b/AnnotationsProcessor/src/main/java/com/github/ChristopheCVB/TouchPortal/AnnotationsProcessor/TouchPortalPluginAnnotationProcessor.java @@ -125,9 +125,9 @@ public boolean process(Set annotations, RoundEnvironment * @param roundEnv RoundEnvironment * @param pluginElement Element * @return Pair pluginPair - * @throws TPTypeException If a used type is not Supported + * @throws GenericHelper.TPTypeException If a used type is not Supported */ - private Pair processPlugin(RoundEnvironment roundEnv, Element pluginElement) throws TPTypeException { + private Pair processPlugin(RoundEnvironment roundEnv, Element pluginElement) throws GenericHelper.TPTypeException { this.messager.printMessage(Diagnostic.Kind.NOTE, "Process Plugin: " + pluginElement.getSimpleName()); Plugin plugin = pluginElement.getAnnotation(Plugin.class); @@ -164,9 +164,9 @@ private Pair processPlugin(RoundEnvironment roundE * @param plugin {@link Plugin} * @param categoryElement Element * @return Pair categoryPair - * @throws TPTypeException If a used type is not Supported + * @throws GenericHelper.TPTypeException If a used type is not Supported */ - private Pair processCategory(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement) throws TPTypeException { + private Pair processCategory(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement) throws GenericHelper.TPTypeException { this.messager.printMessage(Diagnostic.Kind.NOTE, "Process Category: " + categoryElement.getSimpleName()); Category category = categoryElement.getAnnotation(Category.class); @@ -228,7 +228,7 @@ private Pair processCategory(RoundEnvironment roun * @param actionElement Element * @return Pair actionPair */ - private Pair processAction(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement, Category category, Element actionElement) { + private Pair processAction(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement, Category category, Element actionElement) throws GenericHelper.TPTypeException { this.messager.printMessage(Diagnostic.Kind.NOTE, "Process Action: " + actionElement.getSimpleName()); Action action = actionElement.getAnnotation(Action.class); @@ -270,29 +270,31 @@ private Pair processAction(RoundEnvironment roundE * @param category {@link Category} * @param stateElement Element * @return Pair statePair - * @throws TPTypeException If a used type is not Supported + * @throws GenericHelper.TPTypeException If a used type is not Supported */ - private Pair processState(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement, Category category, Element stateElement) throws TPTypeException { + private Pair processState(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement, Category category, Element stateElement) throws GenericHelper.TPTypeException { this.messager.printMessage(Diagnostic.Kind.NOTE, "Process State: " + stateElement.getSimpleName()); State state = stateElement.getAnnotation(State.class); TypeSpec.Builder stateTypeSpecBuilder = this.createStateTypeSpecBuilder(pluginElement, categoryElement, category, stateElement, state); + String className = stateElement.getEnclosingElement().getSimpleName() + "." + stateElement.getSimpleName(); + JsonObject jsonState = new JsonObject(); jsonState.addProperty(StateHelper.ID, StateHelper.getStateId(pluginElement, categoryElement, category, stateElement, state)); - String tpType = GenericHelper.getTouchPortalType(stateElement); - jsonState.addProperty(StateHelper.TYPE, tpType); + String desiredTPType = GenericHelper.getTouchPortalType(className, stateElement); + jsonState.addProperty(StateHelper.TYPE, desiredTPType); jsonState.addProperty(StateHelper.DESC, StateHelper.getStateDesc(stateElement, state)); jsonState.addProperty(StateHelper.DEFAULT, state.defaultValue()); - if (tpType.equals(StateHelper.TYPE_CHOICE)) { + if (desiredTPType.equals(StateHelper.TYPE_CHOICE)) { JsonArray stateValueChoices = new JsonArray(); for (String valueChoice : state.valueChoices()) { stateValueChoices.add(new JsonPrimitive(valueChoice)); } jsonState.add(StateHelper.VALUE_CHOICES, stateValueChoices); } - else if (!tpType.equals(StateHelper.TYPE_TEXT)) { - throw new TPTypeException(stateElement, "The type '" + tpType + "' is not supported for states, only '" + StateHelper.TYPE_CHOICE + "' and '" + StateHelper.TYPE_TEXT + "' are."); + else if (!desiredTPType.equals(StateHelper.TYPE_TEXT)) { + throw new GenericHelper.TPTypeException.Builder(className, GenericHelper.TPTypeException.ForAnnotation.STATE, desiredTPType).build(); } return Pair.create(jsonState, stateTypeSpecBuilder); @@ -308,23 +310,25 @@ else if (!tpType.equals(StateHelper.TYPE_TEXT)) { * @param category {@link Category} * @param eventElement Element * @return Pair eventPair - * @throws TPTypeException If any used type is not Supported + * @throws GenericHelper.TPTypeException If any used type is not Supported */ - private Pair processEvent(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement, Category category, Element eventElement) throws TPTypeException { + private Pair processEvent(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement, Category category, Element eventElement) throws GenericHelper.TPTypeException { this.messager.printMessage(Diagnostic.Kind.NOTE, "Process Event: " + eventElement.getSimpleName()); State state = eventElement.getAnnotation(State.class); Event event = eventElement.getAnnotation(Event.class); TypeSpec.Builder eventTypeSpecBuilder = this.createEventTypeSpecBuilder(pluginElement, categoryElement, category, eventElement, event); + String reference = eventElement.getEnclosingElement().getSimpleName() + "." + eventElement.getSimpleName(); + JsonObject jsonEvent = new JsonObject(); jsonEvent.addProperty(EventHelper.ID, EventHelper.getEventId(pluginElement, categoryElement, category, eventElement, event)); jsonEvent.addProperty(EventHelper.TYPE, EventHelper.TYPE_COMMUNICATE); jsonEvent.addProperty(EventHelper.NAME, EventHelper.getEventName(eventElement, event)); jsonEvent.addProperty(EventHelper.FORMAT, event.format()); - String tpType = GenericHelper.getTouchPortalType(eventElement); - jsonEvent.addProperty(EventHelper.VALUE_TYPE, tpType); - if (tpType.equals(EventHelper.VALUE_TYPE_CHOICE)) { + String desiredTPType = GenericHelper.getTouchPortalType(reference, eventElement); + jsonEvent.addProperty(EventHelper.VALUE_TYPE, desiredTPType); + if (desiredTPType.equals(EventHelper.VALUE_TYPE_CHOICE)) { JsonArray stateValueChoices = new JsonArray(); for (String valueChoice : state.valueChoices()) { stateValueChoices.add(new JsonPrimitive(valueChoice)); @@ -333,7 +337,7 @@ private Pair processEvent(RoundEnvironment roundEn jsonEvent.addProperty(EventHelper.VALUE_STATE_ID, StateHelper.getStateId(pluginElement, categoryElement, category, eventElement, state)); } else { - throw new TPTypeException(eventElement, "The type '" + tpType + "' is not supported for events, only '" + EventHelper.VALUE_TYPE_CHOICE + "' is."); + throw new GenericHelper.TPTypeException.Builder(reference, GenericHelper.TPTypeException.ForAnnotation.EVENT, desiredTPType).build(); } return Pair.create(jsonEvent, eventTypeSpecBuilder); @@ -353,19 +357,22 @@ private Pair processEvent(RoundEnvironment roundEn * @param dataElement Element * @return Pair dataPair */ - private Pair processActionData(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement, Category category, Element actionElement, Action action, JsonObject jsonAction, Element dataElement) { + private Pair processActionData(RoundEnvironment roundEnv, Element pluginElement, Plugin plugin, Element categoryElement, Category category, Element actionElement, Action action, JsonObject jsonAction, Element dataElement) throws GenericHelper.TPTypeException { this.messager.printMessage(Diagnostic.Kind.NOTE, "Process Action Data: " + dataElement.getSimpleName()); Data data = dataElement.getAnnotation(Data.class); TypeSpec.Builder actionDataTypeSpecBuilder = this.createActionDataTypeSpecBuilder(pluginElement, categoryElement, category, actionElement, action, dataElement, data); + Element method = dataElement.getEnclosingElement(); + String className = method.getEnclosingElement().getSimpleName() + "." + method.getSimpleName() + "(" + dataElement.getSimpleName() + ")"; + JsonObject jsonData = new JsonObject(); String dataId = DataHelper.getActionDataId(pluginElement, categoryElement, category, actionElement, action, dataElement, data); jsonData.addProperty(DataHelper.ID, dataId); - String tpType = GenericHelper.getTouchPortalType(dataElement); - jsonData.addProperty(DataHelper.TYPE, tpType); + String desiredTPType = GenericHelper.getTouchPortalType(className, dataElement); + jsonData.addProperty(DataHelper.TYPE, desiredTPType); jsonData.addProperty(DataHelper.LABEL, DataHelper.getActionDataLabel(dataElement, data)); - switch (tpType) { + switch (desiredTPType) { case GenericHelper.TP_TYPE_NUMBER: double defaultValue = 0; try { @@ -383,7 +390,7 @@ private Pair processActionData(RoundEnvironment ro jsonData.addProperty(DataHelper.DEFAULT, data.defaultValue()); break; } - if (tpType.equals(DataHelper.TYPE_CHOICE)) { + if (desiredTPType.equals(DataHelper.TYPE_CHOICE)) { JsonArray dataValueChoices = new JsonArray(); for (String valueChoice : data.valueChoices()) { dataValueChoices.add(new JsonPrimitive(valueChoice)); @@ -391,6 +398,7 @@ private Pair processActionData(RoundEnvironment ro jsonData.add(DataHelper.VALUE_CHOICES, dataValueChoices); } if (!action.format().isEmpty()) { + // Replace wildcards String rawFormat = jsonAction.get(ActionHelper.FORMAT).getAsString(); jsonAction.addProperty(ActionHelper.FORMAT, rawFormat.replace("{$" + (data.id().isEmpty() ? dataElement.getSimpleName().toString() : data.id()) + "$}", "{$" + dataId + "$}")); } @@ -525,18 +533,4 @@ private TypeSpec.Builder createEventTypeSpecBuilder(Element pluginElement, Eleme private FieldSpec getStaticFinalStringFieldSpec(String fieldName, String value) { return FieldSpec.builder(String.class, fieldName.toUpperCase()).addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC).initializer("$S", value).build(); } - - /** - * Touch Portal Type Exception - */ - private static class TPTypeException extends Exception { - /** - * Constructor - * - * @param message String - */ - public TPTypeException(Element element, String message) { - super(element.getEnclosingElement().getSimpleName() + "." + element.getSimpleName() + ": " + message); - } - } } diff --git a/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/GenericHelper.java b/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/GenericHelper.java index e203074..57ccb7f 100644 --- a/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/GenericHelper.java +++ b/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/GenericHelper.java @@ -42,22 +42,29 @@ public class GenericHelper { /** * Retrieve the internal Touch Portal type according to the Java's element type * - * @param element Element + * @param reference String + * @param element Element * @return String tpType */ - public static String getTouchPortalType(Element element) { + public static String getTouchPortalType(String reference, Element element) throws GenericHelper.TPTypeException { + return GenericHelper.getTouchPortalType(reference, element.asType().toString()); + } + + /** + * Retrieve the internal Touch Portal type according to the Java's type + * + * @param reference String + * @param rawType String + * @return String tpType + */ + public static String getTouchPortalType(String reference, String rawType) throws GenericHelper.TPTypeException { String tpType; - String elementType = element.asType().toString(); - switch (elementType) { - case "byte": - case "char": + switch (rawType) { case "short": case "int": case "long": case "float": case "double": - case "java.lang.Byte": - case "java.lang.Char": case "java.lang.Short": case "java.lang.Integer": case "java.lang.Long": @@ -71,15 +78,64 @@ public static String getTouchPortalType(Element element) { tpType = GenericHelper.TP_TYPE_SWITCH; break; - default: - if (elementType.endsWith("[]")) { - tpType = GenericHelper.TP_TYPE_CHOICE; - } - else { - tpType = GenericHelper.TP_TYPE_TEXT; - } + case "java.lang.String": + tpType = GenericHelper.TP_TYPE_TEXT; + break; + + case "java.lang.String[]": + tpType = GenericHelper.TP_TYPE_CHOICE; break; + + default: + throw new TPTypeException.Builder(reference, rawType).build(); } return tpType; } + + /** + * Touch Portal Type Exception + */ + public static class TPTypeException extends Exception { + + /** + * Constructor + * + * @param message String + */ + private TPTypeException(String message) { + super(message); + } + + public static class Builder { + private String message; + + public Builder(String reference, ForAnnotation forAnnotation, String tpType) { + this.message = reference + ": The type '" + tpType + "' is not supported"; + if (forAnnotation != null) { + switch (forAnnotation) { + case STATE: + this.message += " for states, only '" + StateHelper.TYPE_CHOICE + "' and '" + StateHelper.TYPE_TEXT + "' are."; + break; + + case EVENT: + this.message += " for events, only '" + EventHelper.VALUE_TYPE_CHOICE + "' is."; + break; + } + } + } + + public Builder(String reference, String rawType) { + this(reference, null, rawType); + } + + public TPTypeException build() { + return new TPTypeException(this.message); + } + } + + public enum ForAnnotation { + STATE, + EVENT + } + } } diff --git a/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/ReceivedMessageHelper.java b/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/ReceivedMessageHelper.java index bcc4950..3dff9cd 100644 --- a/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/ReceivedMessageHelper.java +++ b/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/ReceivedMessageHelper.java @@ -23,6 +23,9 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + /** * Touch Portal Plugin Received Message Helper */ @@ -56,10 +59,20 @@ public static String getType(JsonObject jsonMessage) { * @param jsonMessage JSONObject * @return boolean isMessageAnAction */ - public static boolean isAnAction(JsonObject jsonMessage) { + public static boolean isTypeAction(JsonObject jsonMessage) { return ReceivedMessageHelper.TYPE_ACTION.equals(ReceivedMessageHelper.getType(jsonMessage)); } + /** + * Return true if the received jsonMessage is a List Change + * + * @param jsonMessage JSONObject + * @return boolean isMessageAListChange + */ + public static boolean isTypeListChange(JsonObject jsonMessage) { + return ReceivedMessageHelper.TYPE_LIST_CHANGE.equals(ReceivedMessageHelper.getType(jsonMessage)); + } + /** * Retrieve the Action ID of a received Message * @@ -67,20 +80,37 @@ public static boolean isAnAction(JsonObject jsonMessage) { * @return String actionId */ public static String getActionId(JsonObject jsonMessage) { - return jsonMessage.has(ReceivedMessageHelper.ACTION_ID) ? jsonMessage.get(ReceivedMessageHelper.ACTION_ID).getAsString() : ""; + return jsonMessage.has(ReceivedMessageHelper.ACTION_ID) ? jsonMessage.get(ReceivedMessageHelper.ACTION_ID).getAsString() : null; } /** - * Retrieve an Action Data Value from a received Message + * Retrieve the List ID of a received Message * - * @param pluginClass Class - * @param jsonMessage JsonObject - * @param actionMethodName String - * @param actionParameterName String - * @return String dataValue + * @param jsonMessage {@link JsonObject} + * @return String listId */ - public static String getActionDataValue(Class pluginClass, JsonObject jsonMessage, String actionMethodName, String actionParameterName) { - return ReceivedMessageHelper.getActionDataValue(jsonMessage, DataHelper.getActionDataId(pluginClass, actionMethodName, actionParameterName)); + public static String getListId(JsonObject jsonMessage) { + return jsonMessage.has(ReceivedMessageHelper.LIST_ID) ? jsonMessage.get(ReceivedMessageHelper.LIST_ID).getAsString() : null; + } + + /** + * Retrieve the Instance ID of a received Message + * + * @param jsonMessage {@link JsonObject} + * @return String instanceId + */ + public static String getListInstanceId(JsonObject jsonMessage) { + return jsonMessage.has(ReceivedMessageHelper.INSTANCE_ID) ? jsonMessage.get(ReceivedMessageHelper.INSTANCE_ID).getAsString() : null; + } + + /** + * Retrieve the List Value of a received Message + * + * @param jsonMessage {@link JsonObject} + * @return String instanceId + */ + public static String getListValue(JsonObject jsonMessage) { + return jsonMessage.has(ReceivedMessageHelper.VALUE) ? jsonMessage.get(ReceivedMessageHelper.VALUE).getAsString() : null; } /** @@ -91,7 +121,7 @@ public static String getActionDataValue(Class pluginClass, JsonObject jsonMes * @return String dataValue */ public static String getActionDataValue(JsonObject jsonMessage, String actionDataId) { - String dataValue = ""; + String dataValue = null; if (jsonMessage.has(ActionHelper.DATA)) { JsonArray actionData = jsonMessage.getAsJsonArray(ActionHelper.DATA); @@ -108,6 +138,79 @@ public static String getActionDataValue(JsonObject jsonMessage, String actionDat return dataValue; } + /** + * Retrieve an Action Data Value from a received Message + * + * @param jsonMessage JsonObject + * @param pluginClass Class + * @param actionMethodName String + * @param actionParameterName String + * @return String dataValue + */ + public static String getActionDataValue(JsonObject jsonMessage, Class pluginClass, String actionMethodName, String actionParameterName) { + return ReceivedMessageHelper.getActionDataValue(jsonMessage, DataHelper.getActionDataId(pluginClass, actionMethodName, actionParameterName)); + } + + /** + * Retrieve an Action Data Value from a received Message for a specific Parameter + * + * @param jsonMessage JsonObject + * @param parameterDataId String + * @param parameterRawType String + * @return Object actionDataValue + */ + protected static Object getTypedActionDataValue(JsonObject jsonMessage, String parameterDataId, String parameterRawType) { + Object argumentValue = ReceivedMessageHelper.getActionDataValue(jsonMessage, parameterDataId); + if (argumentValue != null) { + switch (parameterRawType) { + case "short": + case "java.lang.Short": + argumentValue = ReceivedMessageHelper.getActionDataValueDouble((String) argumentValue).shortValue(); + break; + + case "int": + case "java.lang.Integer": + argumentValue = ReceivedMessageHelper.getActionDataValueDouble((String) argumentValue).intValue(); + break; + + case "float": + case "java.lang.Float": + argumentValue = ReceivedMessageHelper.getActionDataValueDouble((String) argumentValue).floatValue(); + break; + + case "double": + case "java.lang.Double": + argumentValue = ReceivedMessageHelper.getActionDataValueDouble((String) argumentValue); + break; + + case "long": + case "java.lang.Long": + argumentValue = ReceivedMessageHelper.getActionDataValueDouble((String) argumentValue).longValue(); + break; + + case "boolean": + case "java.lang.Boolean": + argumentValue = ReceivedMessageHelper.getActionDataValueBoolean(jsonMessage, parameterDataId); + break; + } + } + return argumentValue; + } + + /** + * Retrieve an Action Data Value from a received Message for a specific Parameter + * + * @param jsonMessage JsonObject + * @param pluginClass Class + * @param method Method + * @param parameter Parameter + * @return Object actionDataValue + */ + public static Object getTypedActionDataValue(JsonObject jsonMessage, Class pluginClass, Method method, Parameter parameter) { + String parameterDataId = DataHelper.getActionDataId(pluginClass, method.getName(), parameter.getName()); + return ReceivedMessageHelper.getTypedActionDataValue(jsonMessage, parameterDataId, parameter.getParameterizedType().getTypeName()); + } + /** * Retrieve an Action Data Value from a received Message as a Double * @@ -116,18 +219,21 @@ public static String getActionDataValue(JsonObject jsonMessage, String actionDat * @return Double dataValueDouble */ public static Double getActionDataValueDouble(JsonObject jsonMessage, String actionDataId) { - return Double.valueOf(ReceivedMessageHelper.getActionDataValue(jsonMessage, actionDataId)); + return ReceivedMessageHelper.getActionDataValueDouble(ReceivedMessageHelper.getActionDataValue(jsonMessage, actionDataId)); } /** - * Retrieve an Action Data Value from a received Message as a Long + * Retrieve an Action Data Value from a received Message as a Double * - * @param jsonMessage JsonObject - * @param actionDataId String - * @return Double dataValueLong + * @param actionDataValue String + * @return Double dataValueDouble */ - public static Long getActionDataValueLong(JsonObject jsonMessage, String actionDataId) { - return ReceivedMessageHelper.getActionDataValueDouble(jsonMessage, actionDataId).longValue(); + protected static Double getActionDataValueDouble(String actionDataValue) { + Double actionDataValueDouble = null; + if (actionDataValue != null) { + actionDataValueDouble = Double.valueOf(actionDataValue); + } + return actionDataValueDouble; } /** @@ -138,7 +244,7 @@ public static Long getActionDataValueLong(JsonObject jsonMessage, String actionD * @return Double dataValueLong */ public static Boolean getActionDataValueBoolean(JsonObject jsonMessage, String actionDataId) { - return ReceivedMessageHelper.getActionDataValue(jsonMessage, actionDataId).equals("On"); + return "On".equals(ReceivedMessageHelper.getActionDataValue(jsonMessage, actionDataId)); } /** diff --git a/Library/build.gradle b/Library/build.gradle index 4aa6b39..5570ed9 100644 --- a/Library/build.gradle +++ b/Library/build.gradle @@ -18,6 +18,10 @@ dependencies { testAnnotationProcessor project(':AnnotationsProcessor') } +compileTestJava { + options.compilerArgs.add('-parameters') +} + apply plugin: 'jacoco' jacocoTestReport { diff --git a/Library/src/main/java/com/github/ChristopheCVB/TouchPortal/TouchPortalPlugin.java b/Library/src/main/java/com/github/ChristopheCVB/TouchPortal/TouchPortalPlugin.java index 4d04be3..44ef26e 100644 --- a/Library/src/main/java/com/github/ChristopheCVB/TouchPortal/TouchPortalPlugin.java +++ b/Library/src/main/java/com/github/ChristopheCVB/TouchPortal/TouchPortalPlugin.java @@ -20,10 +20,9 @@ package com.github.ChristopheCVB.TouchPortal; -import com.github.ChristopheCVB.TouchPortal.Helpers.PluginHelper; -import com.github.ChristopheCVB.TouchPortal.Helpers.ReceivedMessageHelper; -import com.github.ChristopheCVB.TouchPortal.Helpers.SentMessageHelper; -import com.github.ChristopheCVB.TouchPortal.Helpers.StateHelper; +import com.github.ChristopheCVB.TouchPortal.Annotations.Action; +import com.github.ChristopheCVB.TouchPortal.Annotations.Data; +import com.github.ChristopheCVB.TouchPortal.Helpers.*; import com.github.ChristopheCVB.TouchPortal.model.TPInfo; import com.google.gson.JsonArray; import com.google.gson.JsonObject; @@ -31,6 +30,9 @@ import com.google.gson.JsonPrimitive; import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.net.InetAddress; import java.net.Socket; import java.nio.file.Paths; @@ -130,15 +132,15 @@ private Thread createListenerThread() { while (true) { try { if (TouchPortalPlugin.this.touchPortalSocket == null) { - throw new IOException("Can't Access Socket"); + throw new IOException("Socket Access lost"); } if (TouchPortalPlugin.this.bufferedReader == null) { TouchPortalPlugin.this.bufferedReader = new BufferedReader(new InputStreamReader(TouchPortalPlugin.this.touchPortalSocket.getInputStream())); } String socketMessage = TouchPortalPlugin.this.bufferedReader.readLine(); if (socketMessage != null && !socketMessage.isEmpty()) { - JsonObject jsonMessage = JsonParser.parseString(socketMessage).getAsJsonObject(); - String messageType = ReceivedMessageHelper.getType(jsonMessage); + final JsonObject jsonMessage = JsonParser.parseString(socketMessage).getAsJsonObject(); + final String messageType = ReceivedMessageHelper.getType(jsonMessage); if (messageType != null) { switch (messageType) { case ReceivedMessageHelper.TYPE_CLOSE_PLUGIN: @@ -151,13 +153,50 @@ private Thread createListenerThread() { break; default: - if (ReceivedMessageHelper.isMessageForPlugin(jsonMessage, TouchPortalPlugin.this.pluginClass)) { - System.out.println("Message Received"); - // TODO: Automatically Call Actions Methods (This require to Annotate an Interface that would be passed to the SDK) - if (TouchPortalPlugin.this.touchPortalPluginListener != null) { - TouchPortalPlugin.this.callbacksExecutor.submit(() -> TouchPortalPlugin.this.touchPortalPluginListener.onReceive(jsonMessage)); + this.callbacksExecutor.submit(() -> { + if (ReceivedMessageHelper.isMessageForPlugin(jsonMessage, TouchPortalPlugin.this.pluginClass)) { + boolean called = false; + if (messageType.equals(ReceivedMessageHelper.TYPE_ACTION)) { + String messageActionId = ReceivedMessageHelper.getActionId(jsonMessage); + if (messageActionId != null && !messageActionId.isEmpty()) { + for (Method method : TouchPortalPlugin.this.pluginClass.getDeclaredMethods()) { + if (method.isAnnotationPresent(Action.class)) { + String methodActionId = ActionHelper.getActionId(TouchPortalPlugin.this.pluginClass, method.getName()); + if (messageActionId.equals(methodActionId)) { + try { + Parameter[] parameters = method.getParameters(); + Object[] arguments = new Object[parameters.length]; + for (int parameterIndex = 0; parameterIndex < parameters.length; parameterIndex++) { + Parameter parameter = parameters[parameterIndex]; + if (parameter.isAnnotationPresent(Data.class)) { + arguments[parameterIndex] = ReceivedMessageHelper.getTypedActionDataValue(jsonMessage, TouchPortalPlugin.this.pluginClass, method, parameter); + } + if (arguments[parameterIndex] == null) { + throw new NoSuchFieldException("Impossible to retrieve Action Data Item for Method [" + method.getName() + "] and parameter [" + parameter.getName() + "]"); + } + } + method.setAccessible(true); + method.invoke(TouchPortalPlugin.this, arguments); + System.out.println("Auto Called Action"); + called = true; + } + catch (IllegalAccessException | InvocationTargetException | SecurityException | NoSuchFieldException e) { + e.printStackTrace(); + } + break; + } + } + } + } + } + if (!called) { + System.out.println("Message Received"); + if (TouchPortalPlugin.this.touchPortalPluginListener != null) { + TouchPortalPlugin.this.touchPortalPluginListener.onReceive(jsonMessage); + } + } } - } + }); break; } } diff --git a/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/LibraryTests.java b/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/LibraryTests.java index c96833f..0e6b025 100644 --- a/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/LibraryTests.java +++ b/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/LibraryTests.java @@ -202,6 +202,51 @@ public void testReceiveAction() throws IOException, InterruptedException { assertTrue(this.touchPortalPluginTest.isConnected()); } + @Test + public void testReceiveDummyWithDataAction() throws IOException, InterruptedException { + JsonObject jsonMessage = new JsonObject(); + jsonMessage.addProperty(ReceivedMessageHelper.PLUGIN_ID, TouchPortalPluginTestConstants.ID); + jsonMessage.addProperty(ReceivedMessageHelper.TYPE, ReceivedMessageHelper.TYPE_ACTION); + jsonMessage.addProperty(ReceivedMessageHelper.ACTION_ID, TouchPortalPluginTestConstants.BaseCategory.Actions.DummyWithData.ID); + JsonArray data = new JsonArray(); + JsonObject textDataItem = new JsonObject(); + textDataItem.addProperty(ReceivedMessageHelper.ACTION_DATA_ID, TouchPortalPluginTestConstants.BaseCategory.Actions.DummyWithData.Text.ID); + textDataItem.addProperty(ReceivedMessageHelper.ACTION_DATA_VALUE, "Text from Tests !"); + data.add(textDataItem); + JsonObject numberDataItem = new JsonObject(); + numberDataItem.addProperty(ReceivedMessageHelper.ACTION_DATA_ID, TouchPortalPluginTestConstants.BaseCategory.Actions.DummyWithData.Number.ID); + numberDataItem.addProperty(ReceivedMessageHelper.ACTION_DATA_VALUE, 42); + data.add(numberDataItem); + jsonMessage.add(ActionHelper.DATA, data); + PrintWriter out = new PrintWriter(this.serverSocketClient.getOutputStream(), true); + out.println(jsonMessage.toString()); + Thread.sleep(10); + assertTrue(this.touchPortalPluginTest.isConnected()); + } + + @Test + public void testReceiveDummyWithoutDataAction() throws IOException, InterruptedException { + JsonObject jsonMessage = new JsonObject(); + jsonMessage.addProperty(ReceivedMessageHelper.PLUGIN_ID, TouchPortalPluginTestConstants.ID); + jsonMessage.addProperty(ReceivedMessageHelper.TYPE, ReceivedMessageHelper.TYPE_ACTION); + jsonMessage.addProperty(ReceivedMessageHelper.ACTION_ID, TouchPortalPluginTestConstants.BaseCategory.Actions.DummyWithoutData.ID); + PrintWriter out = new PrintWriter(this.serverSocketClient.getOutputStream(), true); + out.println(jsonMessage.toString()); + Thread.sleep(10); + assertTrue(this.touchPortalPluginTest.isConnected()); + } + + @Test + public void testReceiveListChange() throws IOException, InterruptedException { + JsonObject jsonMessage = new JsonObject(); + jsonMessage.addProperty(ReceivedMessageHelper.PLUGIN_ID, TouchPortalPluginTestConstants.ID); + jsonMessage.addProperty(ReceivedMessageHelper.TYPE, ReceivedMessageHelper.TYPE_LIST_CHANGE); + PrintWriter out = new PrintWriter(this.serverSocketClient.getOutputStream(), true); + out.println(jsonMessage.toString()); + Thread.sleep(10); + assertTrue(this.touchPortalPluginTest.isConnected()); + } + @Test public void testReceiveActionNoListener() throws IOException, InterruptedException { this.touchPortalPluginTest.connectThenPairAndListen(null); @@ -225,6 +270,16 @@ public void testReceiveBadPlugin() throws IOException, InterruptedException { assertTrue(this.touchPortalPluginTest.isConnected()); } + @Test + public void testReceiveNoMessageType() throws IOException, InterruptedException { + JsonObject jsonMessage = new JsonObject(); + jsonMessage.addProperty(ReceivedMessageHelper.PLUGIN_ID, TouchPortalPluginTestConstants.ID); + PrintWriter out = new PrintWriter(this.serverSocketClient.getOutputStream(), true); + out.println(jsonMessage.toString()); + Thread.sleep(10); + assertTrue(this.touchPortalPluginTest.isConnected()); + } + @Test public void testReceiveInfo() throws IOException, InterruptedException { JsonObject jsonMessage = new JsonObject(); @@ -329,7 +384,7 @@ public void testEntryTP() throws IOException { // Base Category Action DummyWithData Data items JsonArray baseCategoryActionDummyWithDataItems = baseCategoryActionDummyWithData.getAsJsonArray(ActionHelper.DATA); - assertEquals(1, baseCategoryActionDummyWithDataItems.size()); + assertEquals(2, baseCategoryActionDummyWithDataItems.size()); // Base Category Action DummyWithData Data Text item JsonObject baseCategoryActionDummyWithDataItemText = baseCategoryActionDummyWithDataItems.get(0).getAsJsonObject(); diff --git a/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/TouchPortalPluginTest.java b/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/TouchPortalPluginTest.java index 53daa92..a1b969f 100644 --- a/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/TouchPortalPluginTest.java +++ b/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/TouchPortalPluginTest.java @@ -48,8 +48,8 @@ public TouchPortalPluginTest(String[] args) { * @param text String */ @Action(description = "Long Description of Dummy Action with Data", categoryId = "BaseCategory") - private void dummyWithData(@Data String text) { - System.out.println("Action dummyWithData received: " + text); + private void dummyWithData(@Data String text, @Data Integer number) { + System.out.println("Action dummyWithData received: text [" + text + "] number [" + number + "]"); } /** diff --git a/Library/src/test/resources/TouchPortalPluginTest/plugin.config b/Library/src/test/resources/TouchPortalPluginTest/plugin.config index c1f68fa..8d5bfcf 100644 --- a/Library/src/test/resources/TouchPortalPluginTest/plugin.config +++ b/Library/src/test/resources/TouchPortalPluginTest/plugin.config @@ -1,3 +1,3 @@ # -#Tue Jun 16 11:56:03 CEST 2020 +#Thu Jun 18 01:54:10 CEST 2020 samplekey=Sample Value diff --git a/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java b/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java index 99a402e..0d05813 100644 --- a/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java +++ b/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java @@ -111,25 +111,27 @@ public void onDisconnect(Exception exception) { @Override public void onReceive(JsonObject jsonMessage) { // Check if ReceiveMessage is an Action - if (ReceivedMessageHelper.isAnAction(jsonMessage)) { + if (ReceivedMessageHelper.isTypeAction(jsonMessage)) { // Get the Action ID String receivedActionId = ReceivedMessageHelper.getActionId(jsonMessage); - switch (receivedActionId) { - case TouchPortalPluginExampleConstants.BaseCategory.Actions.DummyWithData.ID: - // Example with IDs from Generated Constants Class - // Manually call the action method - this.dummyWithData(ReceivedMessageHelper.getActionDataValue(jsonMessage, TouchPortalPluginExampleConstants.BaseCategory.Actions.DummyWithData.Text.ID)); - break; + if (receivedActionId != null) { + switch (receivedActionId) { + case TouchPortalPluginExampleConstants.BaseCategory.Actions.DummyWithData.ID: + // Example with IDs from Generated Constants Class + // Manually call the action method + this.dummyWithData(ReceivedMessageHelper.getActionDataValue(jsonMessage, TouchPortalPluginExampleConstants.BaseCategory.Actions.DummyWithData.Text.ID)); + break; - case TouchPortalPluginExampleConstants.BaseCategory.Actions.DummyWithoutData.ID: - // Example with IDs from Helper - // Manually call the action method - this.dummyWithoutData(jsonMessage); - break; + case TouchPortalPluginExampleConstants.BaseCategory.Actions.DummyWithoutData.ID: + // Example with IDs from Helper + // Manually call the action method + this.dummyWithoutData(jsonMessage); + break; - case TouchPortalPluginExampleConstants.BaseCategory.Actions.DummySwitchAction.ID: - this.dummySwitchAction(ReceivedMessageHelper.getActionDataValueBoolean(jsonMessage, TouchPortalPluginExampleConstants.BaseCategory.Actions.DummySwitchAction.IsOn.ID)); - break; + case TouchPortalPluginExampleConstants.BaseCategory.Actions.DummySwitchAction.ID: + this.dummySwitchAction(ReceivedMessageHelper.getActionDataValueBoolean(jsonMessage, TouchPortalPluginExampleConstants.BaseCategory.Actions.DummySwitchAction.IsOn.ID)); + break; + } } } } diff --git a/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt b/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt index 6be6dcf..926e613 100644 --- a/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt +++ b/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt @@ -20,6 +20,7 @@ class TouchPortalKotlinPlugin(args: Array?) : TouchPortalPlugin(args // Initiate the connection with the Touch Portal Plugin System val connectedPairedAndListening = touchPortalPluginExample.connectThenPairAndListen(touchPortalPluginExample) + @Suppress("ControlFlowWithEmptyBody") if (connectedPairedAndListening) { // Let's go! } @@ -43,7 +44,7 @@ class TouchPortalKotlinPlugin(args: Array?) : TouchPortalPlugin(args } override fun onReceive(jsonMessage: JsonObject?) { - if (ReceivedMessageHelper.isAnAction(jsonMessage)) { + if (ReceivedMessageHelper.isTypeAction(jsonMessage)) { val actionId = ReceivedMessageHelper.getActionId(jsonMessage) when (actionId) { TouchPortalKotlinPluginConstants.BaseCategory.Actions.LogTime.ID -> logTime() From aec52986c1a82a8f54ac00c638ab2efa1e5a3d3b Mon Sep 17 00:00:00 2001 From: Christophe Carvalho Vilas-Boas Date: Thu, 18 Jun 2020 02:54:05 +0200 Subject: [PATCH 2/5] docs: Samples clean --- .../test/TouchPortalPluginTest.java | 3 ++- .../TouchPortalPluginTest/plugin.config | 2 +- Sample/build.gradle | 18 ++++++++++++++++++ .../sample/TouchPortalPluginExample.java | 3 ++- .../sample/TouchPortalKotlinPlugin.kt | 9 +++++---- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/TouchPortalPluginTest.java b/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/TouchPortalPluginTest.java index a1b969f..f6da5fc 100644 --- a/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/TouchPortalPluginTest.java +++ b/Library/src/test/java/com/github/ChristopheCVB/TouchPortal/test/TouchPortalPluginTest.java @@ -24,7 +24,8 @@ import com.github.ChristopheCVB.TouchPortal.TouchPortalPlugin; import com.google.gson.JsonObject; -@Plugin(version = 1000, colorDark = "#203060", colorLight = "#4070F0") +@SuppressWarnings("unused") +@Plugin(version = 4000, colorDark = "#203060", colorLight = "#4070F0") public class TouchPortalPluginTest extends TouchPortalPlugin { /** * State and Event definition example diff --git a/Library/src/test/resources/TouchPortalPluginTest/plugin.config b/Library/src/test/resources/TouchPortalPluginTest/plugin.config index 8d5bfcf..0aa9f92 100644 --- a/Library/src/test/resources/TouchPortalPluginTest/plugin.config +++ b/Library/src/test/resources/TouchPortalPluginTest/plugin.config @@ -1,3 +1,3 @@ # -#Thu Jun 18 01:54:10 CEST 2020 +#Thu Jun 18 02:49:28 CEST 2020 samplekey=Sample Value diff --git a/Sample/build.gradle b/Sample/build.gradle index 868e623..89f5d60 100644 --- a/Sample/build.gradle +++ b/Sample/build.gradle @@ -1,5 +1,13 @@ +buildscript { + repositories { + maven { + url 'https://plugins.gradle.org/m2/' + } + } +} plugins { id 'java' + id 'de.fuerstenau.buildconfig' version '1.1.8' } def versionMajor = 4 @@ -11,6 +19,16 @@ def mainClassPackage = 'com.github.ChristopheCVB.TouchPortal.sample' group mainClassPackage version "${versionMajor}.${versionMinor}.${versionPatch}" +buildConfig { + appName = project.name + version = project.version + + clsName = 'BuildConfig' + packageName = project.group + + buildConfigField 'int', 'VERSION_CODE', (versionMajor * 1000 + versionMinor * 100 + versionPatch) + '' +} + dependencies { compile project(':Library') compile project(':Annotations') diff --git a/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java b/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java index 0d05813..249745a 100644 --- a/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java +++ b/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java @@ -28,7 +28,8 @@ import java.io.IOException; -@Plugin(version = 1000, colorDark = "#203060", colorLight = "#4070F0", name = "Touch Portal Plugin Example") +@SuppressWarnings("unused") +@Plugin(version = BuildConfig.VERSION_CODE, colorDark = "#203060", colorLight = "#4070F0", name = "Touch Portal Plugin Example") public class TouchPortalPluginExample extends TouchPortalPlugin implements TouchPortalPlugin.TouchPortalPluginListener { /** * State and Event definition example diff --git a/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt b/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt index 926e613..3674b4d 100644 --- a/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt +++ b/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt @@ -7,8 +7,9 @@ import com.github.ChristopheCVB.TouchPortal.Helpers.PluginHelper import com.github.ChristopheCVB.TouchPortal.Helpers.ReceivedMessageHelper import com.github.ChristopheCVB.TouchPortal.TouchPortalPlugin import com.google.gson.JsonObject +import kotlin.system.exitProcess -@Plugin(version = 1, colorDark = "#556677", colorLight = "#112233") +@Plugin(version = 4000, colorDark = "#556677", colorLight = "#112233") class TouchPortalKotlinPlugin(args: Array?) : TouchPortalPlugin(args), TouchPortalPlugin.TouchPortalPluginListener { companion object { @JvmStatic @@ -29,6 +30,7 @@ class TouchPortalKotlinPlugin(args: Array?) : TouchPortalPlugin(args } } + @Suppress("unused") enum class Categories { @Category(imagePath = "images/icon-24.png") BaseCategory @@ -40,13 +42,12 @@ class TouchPortalKotlinPlugin(args: Array?) : TouchPortalPlugin(args } override fun onDisconnect(exception: Exception?) { - System.exit(0) + exitProcess(0) } override fun onReceive(jsonMessage: JsonObject?) { if (ReceivedMessageHelper.isTypeAction(jsonMessage)) { - val actionId = ReceivedMessageHelper.getActionId(jsonMessage) - when (actionId) { + when (ReceivedMessageHelper.getActionId(jsonMessage)) { TouchPortalKotlinPluginConstants.BaseCategory.Actions.LogTime.ID -> logTime() } } From 1ee144155044b1a0cc77d0bf7af01ce5f4b73dc8 Mon Sep 17 00:00:00 2001 From: Christophe Carvalho Vilas-Boas Date: Thu, 18 Jun 2020 03:25:58 +0200 Subject: [PATCH 3/5] core: Handle Auto Call Action with Data of type Choice --- .../TouchPortal/Helpers/ReceivedMessageHelper.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/ReceivedMessageHelper.java b/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/ReceivedMessageHelper.java index 3dff9cd..1b572f1 100644 --- a/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/ReceivedMessageHelper.java +++ b/Helpers/src/main/java/com/github/ChristopheCVB/TouchPortal/Helpers/ReceivedMessageHelper.java @@ -192,6 +192,10 @@ protected static Object getTypedActionDataValue(JsonObject jsonMessage, String p case "java.lang.Boolean": argumentValue = ReceivedMessageHelper.getActionDataValueBoolean(jsonMessage, parameterDataId); break; + + case "java.lang.String[]": + argumentValue = new String[]{(String) argumentValue}; + break; } } return argumentValue; From b9c18a63a5176330a2781af996ddc4cc8ec76e94 Mon Sep 17 00:00:00 2001 From: Christophe Carvalho Vilas-Boas Date: Thu, 18 Jun 2020 04:08:05 +0200 Subject: [PATCH 4/5] core: v4.1.0 docs: Update README --- Annotations/build.gradle | 2 +- AnnotationsProcessor/build.gradle | 2 +- Helpers/build.gradle | 2 +- Library/build.gradle | 2 +- .../TouchPortalPluginTest/plugin.config | 2 +- README.md | 80 +++++++++++++++++-- Sample/build.gradle | 2 +- .../sample/TouchPortalPluginExample.java | 36 +++++---- SampleKotlin/build.gradle | 2 +- 9 files changed, 100 insertions(+), 30 deletions(-) diff --git a/Annotations/build.gradle b/Annotations/build.gradle index 14c2546..5ff99e2 100644 --- a/Annotations/build.gradle +++ b/Annotations/build.gradle @@ -3,7 +3,7 @@ plugins { } def versionMajor = 4 -def versionMinor = 0 +def versionMinor = 1 def versionPatch = 0 group 'com.github.ChristopheCVB.TouchPortal.Annotations' diff --git a/AnnotationsProcessor/build.gradle b/AnnotationsProcessor/build.gradle index d6c9740..649b2b9 100644 --- a/AnnotationsProcessor/build.gradle +++ b/AnnotationsProcessor/build.gradle @@ -3,7 +3,7 @@ plugins { } def versionMajor = 4 -def versionMinor = 0 +def versionMinor = 1 def versionPatch = 0 group 'com.github.ChristopheCVB.TouchPortal.AnnotationsProcessor' diff --git a/Helpers/build.gradle b/Helpers/build.gradle index 547535e..8bd908c 100644 --- a/Helpers/build.gradle +++ b/Helpers/build.gradle @@ -3,7 +3,7 @@ plugins { } def versionMajor = 4 -def versionMinor = 0 +def versionMinor = 1 def versionPatch = 0 group 'com.github.ChristopheCVB.TouchPortal.Helpers' diff --git a/Library/build.gradle b/Library/build.gradle index 5570ed9..553d64a 100644 --- a/Library/build.gradle +++ b/Library/build.gradle @@ -3,7 +3,7 @@ plugins { } def versionMajor = 4 -def versionMinor = 0 +def versionMinor = 1 def versionPatch = 0 group 'com.github.ChristopheCVB.TouchPortal' diff --git a/Library/src/test/resources/TouchPortalPluginTest/plugin.config b/Library/src/test/resources/TouchPortalPluginTest/plugin.config index 0aa9f92..daaae95 100644 --- a/Library/src/test/resources/TouchPortalPluginTest/plugin.config +++ b/Library/src/test/resources/TouchPortalPluginTest/plugin.config @@ -1,3 +1,3 @@ # -#Thu Jun 18 02:49:28 CEST 2020 +#Thu Jun 18 03:58:47 CEST 2020 samplekey=Sample Value diff --git a/README.md b/README.md index 2858c32..6fadb51 100644 --- a/README.md +++ b/README.md @@ -21,29 +21,93 @@ Go to [releases](https://github.com/ChristopheCVB/TouchPortalPluginSDK/releases) ## Get Started -- Clone/Download this project +- Clone/Download/Fork this project - Create a new Gradle Java Module (i.e. `MyTPPlugin`) - Copy the `build.gradle` from the `Sample` module to your new module and remove unnecessary dependencies -- Create a class, in the package you chose, extending `TouchPortalPlugin` (i.e. `MyTouchPortalPlugin extends TouchPortalPlugin`) containing: -``` +- Create a class, in the package you chose, extending `TouchPortalPlugin` (i.e. `MyTouchPortalPlugin extends TouchPortalPlugin`) like the example below: +```java +public class MyTouchPortalPlugin extends TouchPortalPlugin { + /** + * Constructor calling super + * + * @param args String[] + */ + public MyTouchPortalPlugin(String[] args) { + super(args); + } + public static void main(String[] args) { if (args != null && args.length == 2) { if (PluginHelper.COMMAND_START.equals(args[0])) { - // Initialize the Plugin + // Initialize your Plugin MyTouchPortalPlugin myTouchPortalPlugin = new MyTouchPortalPlugin(args); // Initiate the connection with the Touch Portal Plugin System boolean connectedPairedAndListening = myTouchPortalPlugin.connectThenPairAndListen(myTouchPortalPlugin); } } } + + @Override + public void onDisconnect(Exception exception) { + // Socket connection is lost or plugin has received close message + if (exception != null) { + exception.printStackTrace(); + } + System.exit(0); + } + + @Override + public void onReceive(JsonObject jsonMessage) { + // Check if ReceiveMessage is an Action + if (ReceivedMessageHelper.isTypeAction(jsonMessage)) { + // Get the Action ID + String receivedActionId = ReceivedMessageHelper.getActionId(jsonMessage); + if (receivedActionId != null) { + // Manually call the action methods which not all parameters are annotated with @Data + switch (receivedActionId) { + // case ...: + // break; + } + } + } + // dummyWithData and dummySwitchAction are automatically called by the SDK + } + +} ``` - Edit the properties `mainClassPackage` and `mainClassSimpleName` in your `build.gradle` - Implement the interface methods -- Creating the `entry.tp` file - * **Highly recommended method**: Use Annotations (Example can be found in the Sample module) - * *Not recommended*: Create and edit manually the file `src/main/resources/entry.tp` of your module to add your actions, states and events +- Generating the `entry.tp` file using Annotations (More examples can be found in the Sample module) +```java +package com.github.ChristopheCVB.TouchPortal.sample; + +// import ... + +@Plugin(version = 1, colorDark = "#203060", colorLight = "#4070F0", name = "My Touch Portal Plugin") +public class MyTouchPortalPlugin extends TouchPortalPlugin { + //... + + /** + * Action example that contains a dynamic data text + * + * @param text String + */ + @Action(description = "Long Description of Dummy Action with Data", format = "Set text to {$text$}", categoryId = "BaseCategory") + private void dummyWithData(@Data String text) { + System.out.println("Action dummyWithData received: " + text); + } + private enum Categories { + /** + * Category definition example + */ + @Category(name = "My Touch Portal Plugin", imagePath = "images/icon-24.png") + BaseCategory + } + +} +``` - Add the Plugin icon into the following directory `src/main/resources/` of your module -- Start calling your actions in the `onReceive(JsonObject jsonMessage)` method +- If your declared Methods only contain `@Data` annotated parameter, it will be called automatically by the SDK, otherwise call your actions in the `onReceive(JsonObject jsonMessage)` method ## Build diff --git a/Sample/build.gradle b/Sample/build.gradle index 89f5d60..9cd29d0 100644 --- a/Sample/build.gradle +++ b/Sample/build.gradle @@ -11,7 +11,7 @@ plugins { } def versionMajor = 4 -def versionMinor = 0 +def versionMinor = 1 def versionPatch = 0 def mainClassSimpleName = 'TouchPortalPluginExample' diff --git a/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java b/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java index 249745a..b8d5fd9 100644 --- a/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java +++ b/Sample/src/main/java/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalPluginExample.java @@ -81,9 +81,20 @@ public static void main(String[] args) { * * @param text String */ - @Action(description = "Long Description of Dummy Action with Data", format = "Set text to {$text$}", categoryId = "BaseCategory") - private void dummyWithData(@Data String text) { - System.out.println("Action dummyWithData received: " + text); + @Action(description = "Long Description of Dummy Action with Data Text", format = "Set text to {$text$}", categoryId = "BaseCategory") + private void dummyWithDataText(@Data String text) { + System.out.println("Action dummyWithDataText received: " + text); + } + + /** + * Action example that contains a dynamic data text + * + * @param action String[] + */ + @Action(description = "Long Description of Dummy Action with Data Text", format = "Do action {$action$}", categoryId = "BaseCategory") + private void dummyWithDataChoice(@Data(valueChoices = {"Enable", "Disable", "Toggle"}, defaultValue = "Toggle") String[] action) { + // The selected value is passed at index 0 + System.out.println("Action dummyWithDataChoice received: " + action[0]); } /** @@ -101,6 +112,11 @@ private void dummySwitchAction(@Data(defaultValue = "false") boolean isOn) { System.out.println("Action dummySwitchAction received: " + isOn); } + @Action(description = "Long Description of Dummy Action", format = "Do a dummy action", categoryId = "BaseCategory") + private void dummyAction() { + System.out.println("Action dummyAction received"); + } + @Override public void onDisconnect(Exception exception) { // Socket connection is lost or plugin has received close message @@ -117,24 +133,14 @@ public void onReceive(JsonObject jsonMessage) { String receivedActionId = ReceivedMessageHelper.getActionId(jsonMessage); if (receivedActionId != null) { switch (receivedActionId) { - case TouchPortalPluginExampleConstants.BaseCategory.Actions.DummyWithData.ID: - // Example with IDs from Generated Constants Class - // Manually call the action method - this.dummyWithData(ReceivedMessageHelper.getActionDataValue(jsonMessage, TouchPortalPluginExampleConstants.BaseCategory.Actions.DummyWithData.Text.ID)); - break; - case TouchPortalPluginExampleConstants.BaseCategory.Actions.DummyWithoutData.ID: - // Example with IDs from Helper - // Manually call the action method + // Manually call the action method because the parameter jsonMessage is not annotated with @Data this.dummyWithoutData(jsonMessage); break; - - case TouchPortalPluginExampleConstants.BaseCategory.Actions.DummySwitchAction.ID: - this.dummySwitchAction(ReceivedMessageHelper.getActionDataValueBoolean(jsonMessage, TouchPortalPluginExampleConstants.BaseCategory.Actions.DummySwitchAction.IsOn.ID)); - break; } } } + // dummyWithDataText, dummyWithDataChoice, dummySwitchAction and dummyAction are automatically called by the SDK } private enum Categories { diff --git a/SampleKotlin/build.gradle b/SampleKotlin/build.gradle index ff09d19..2d1ef79 100644 --- a/SampleKotlin/build.gradle +++ b/SampleKotlin/build.gradle @@ -5,7 +5,7 @@ plugins { } def versionMajor = 4 -def versionMinor = 0 +def versionMinor = 1 def versionPatch = 0 def mainClassSimpleName = 'TouchPortalKotlinPlugin' From 1d4bb456124b5405ae09a02a32409ff438f007a3 Mon Sep 17 00:00:00 2001 From: Christophe Carvalho Vilas-Boas Date: Thu, 18 Jun 2020 04:21:05 +0200 Subject: [PATCH 5/5] fix: Kotlin Sample v4.1.0 --- .../ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt b/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt index 3674b4d..417976e 100644 --- a/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt +++ b/SampleKotlin/src/main/kotlin/com/github/ChristopheCVB/TouchPortal/sample/TouchPortalKotlinPlugin.kt @@ -9,7 +9,7 @@ import com.github.ChristopheCVB.TouchPortal.TouchPortalPlugin import com.google.gson.JsonObject import kotlin.system.exitProcess -@Plugin(version = 4000, colorDark = "#556677", colorLight = "#112233") +@Plugin(version = 4100, colorDark = "#556677", colorLight = "#112233") class TouchPortalKotlinPlugin(args: Array?) : TouchPortalPlugin(args), TouchPortalPlugin.TouchPortalPluginListener { companion object { @JvmStatic