diff --git a/pom.xml b/pom.xml index 96a649a5120..70f7b7f56c1 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,8 @@ cannot share a single property. --> 2.22.4 2.22 + + 2.2.30 33.7.2-jre 3.1.8 @@ -1989,6 +1991,13 @@ jackson-annotations ${jackson2.annotations.version} + + + + io.swagger.core.v3 + swagger-annotations-jakarta + ${swagger.version} + com.fasterxml.jackson.datatype diff --git a/src/prerna/openapi/Internal.java b/src/prerna/openapi/Internal.java new file mode 100644 index 00000000000..1d9d6b7dd5f --- /dev/null +++ b/src/prerna/openapi/Internal.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ +package prerna.openapi; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a REST operation or a reactor as internal: it is published in the + * OpenAPI document as {@code "x-internal": true}, and every SDK generated from + * the document tags it so its users know not to rely on it. It still works for + * everyone; this is a warning, not access control. + *

+ * Put it on a resource method, on a resource class (every operation in it), or on + * a reactor class. To leave something out of the document and + * the SDKs entirely, use swagger-core's {@code @Hidden} instead. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +public @interface Internal { + + /** + * Why it is internal, such as "Used by the admin console only". It is shown to + * SDK users next to the internal tag. + */ + String value() default ""; +} diff --git a/src/prerna/openapi/PixelInput.java b/src/prerna/openapi/PixelInput.java new file mode 100644 index 00000000000..8788d804c03 --- /dev/null +++ b/src/prerna/openapi/PixelInput.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ +package prerna.openapi; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Refines what is inferred for one of a reactor's inputs. Every input in + * {@code keysToGet} is published without it; use it where the inferred type, + * description or requiredness is not good enough. + * + *

{@code
+ * @PixelInput(name = "value", type = Object.class)
+ * @PixelInput(name = "limit", type = Integer.class, required = Requirement.OPTIONAL)
+ * public class EchoReactor extends AbstractReactor {
+ * }
+ * + * Naming a key the reactor does not declare fails the OpenAPI export. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Repeatable(PixelInputs.class) +public @interface PixelInput { + + /** Whether an input must be passed. */ + enum Requirement { + /** As {@code keyRequired} says. */ + INFERRED, + /** It must be passed. */ + REQUIRED, + /** It may be left out. */ + OPTIONAL + } + + /** The input's key, as in {@code keysToGet} (the canonical name, before any alias). */ + String name(); + + /** + * Its type: {@code String}, {@code Integer}, {@code Long}, {@code Double}, + * {@code Boolean}, an enum, {@code Map}, {@code List} (with {@link #items()}), + * or {@code Object} for any value. {@code Void}, the default, keeps the + * type inferred from {@code getKeyTypeForMCP}. + */ + Class type() default Void.class; + + /** The element type when {@link #type()} is {@code List}. */ + Class items() default Void.class; + + /** Its description. Empty, the default, keeps {@code getDescriptionForKey}. */ + String description() default ""; + + /** Whether it must be passed. {@code INFERRED}, the default, follows {@code keyRequired}. */ + Requirement required() default Requirement.INFERRED; +} diff --git a/src/prerna/openapi/PixelInputs.java b/src/prerna/openapi/PixelInputs.java new file mode 100644 index 00000000000..464031c6ac5 --- /dev/null +++ b/src/prerna/openapi/PixelInputs.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ +package prerna.openapi; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** Holds repeated {@link PixelInput} annotations. */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface PixelInputs { + PixelInput[] value(); +} diff --git a/src/prerna/openapi/PixelOutput.java b/src/prerna/openapi/PixelOutput.java new file mode 100644 index 00000000000..a3b63764ade --- /dev/null +++ b/src/prerna/openapi/PixelOutput.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ +package prerna.openapi; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Declares what a reactor returns, so the SDKs can type its output. Without it + * the output is published as any value: a reactor's code does not say what it + * returns, so it cannot be inferred. + * + *
{@code
+ * @PixelOutput(value = String.class, description = "The id of the current insight")
+ * public class GetCurrentInsightIdReactor extends AbstractReactor {
+ * }
+ */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface PixelOutput { + + /** + * The type of the output: {@code String}, {@code Integer}, {@code Long}, + * {@code Double}, {@code Boolean}, an enum, {@code Map}, {@code List} (with + * {@link #items()}), a record, or {@code Object} for any value. + */ + Class value(); + + /** The element type when {@link #value()} is {@code List}. */ + Class items() default Void.class; + + /** What the output is. */ + String description() default ""; +} diff --git a/src/prerna/reactor/EchoReactor.java b/src/prerna/reactor/EchoReactor.java index ef0d35fa01f..3a57ce4be4a 100644 --- a/src/prerna/reactor/EchoReactor.java +++ b/src/prerna/reactor/EchoReactor.java @@ -27,11 +27,13 @@ *******************************************************************************/ package prerna.reactor; +import prerna.openapi.PixelInput; import prerna.sablecc2.om.GenRowStruct; import prerna.sablecc2.om.PixelDataType; import prerna.sablecc2.om.ReactorKeysEnum; import prerna.sablecc2.om.nounmeta.NounMetadata; +@PixelInput(name = "value", type = Object.class) public class EchoReactor extends AbstractReactor { public EchoReactor() { diff --git a/src/prerna/reactor/ReactorContract.java b/src/prerna/reactor/ReactorContract.java new file mode 100644 index 00000000000..59718f9ef35 --- /dev/null +++ b/src/prerna/reactor/ReactorContract.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ +package prerna.reactor; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import prerna.openapi.Internal; +import prerna.openapi.PixelInput; +import prerna.openapi.PixelOutput; + +/** + * What a reactor declares about itself, read for the OpenAPI document the SDKs + * are generated from. + *

+ * Everything is inferred from what reactors already declare, so no reactor has + * to change to be published: + *

+ * {@link PixelInput} refines one input and {@link PixelOutput} declares the + * output, which cannot be inferred. Reading a contract constructs the reactor, + * since its constructor sets {@code keysToGet}; it never runs it. + * + * @param name the name it is called by in Pixel + * @param description its description, or a placeholder + * @param descriptionInferred whether the description is a placeholder + * @param inputs its inputs, in {@code keysToGet} order + * @param output its declared output, or null when undeclared + * @param internal its {@link Internal}, or null + */ +public record ReactorContract(String name, String description, boolean descriptionInferred, List inputs, + Output output, Internal internal) { + + /** + * One input. + * + * @param type {@code String}, {@code Integer}, {@code Double}, + * {@code Boolean}, {@code List}, {@code Map}, an enum, or + * {@code Object} for any value + * @param items the element type of a {@code List}, or {@code Void} + * @param typeInferred whether the type came from {@code getKeyTypeForMCP} + * rather than a {@link PixelInput} + */ + public record Input(String name, Class type, Class items, String description, boolean required, + boolean typeInferred, boolean descriptionInferred) { + } + + /** A declared output, from {@link PixelOutput}. */ + public record Output(Class type, Class items, String description) { + } + + /** Whether anything in the contract is inferred rather than declared. */ + public boolean inferred() { + return this.descriptionInferred || this.output == null + || this.inputs.stream().anyMatch(i -> i.typeInferred() || i.descriptionInferred()); + } + + /** The name a reactor class is called by in Pixel. */ + public static String pixelName(Class reactorClass) { + return ReactorNames.pixelName(reactorClass.getSimpleName()); + } + + /** Whether a reactor class is a general one rather than specific to one frame type. */ + public static boolean isGeneral(Class reactorClass) { + return ReactorNames.frameType(reactorClass.getPackageName()) == null; + } + + /** + * Reads a reactor's contract. + * + * @throws ReflectiveOperationException when the reactor cannot be constructed + * @throws IllegalArgumentException when it is not an {@code AbstractReactor}, + * or declares a key twice + * @throws IllegalStateException when a {@link PixelInput} names a key + * the reactor does not declare + */ + public static ReactorContract of(Class reactorClass) throws ReflectiveOperationException { + if (!AbstractReactor.class.isAssignableFrom(reactorClass)) { + throw new IllegalArgumentException(reactorClass.getName() + " is not an AbstractReactor"); + } + AbstractReactor reactor = (AbstractReactor) reactorClass.getDeclaredConstructor().newInstance(); + String name = pixelName(reactorClass); + + Map overrides = new LinkedHashMap<>(); + for (PixelInput input : reactorClass.getAnnotationsByType(PixelInput.class)) { + overrides.put(input.name(), input); + } + + List inputs = new ArrayList<>(); + Set seen = new LinkedHashSet<>(); + String[] keys = reactor.keysToGet == null ? new String[0] : reactor.keysToGet; + for (int i = 0; i < keys.length; i++) { + String key = keys[i] == null ? "" : keys[i].split(",", -1)[0].trim(); + if (key.isEmpty()) { + throw new IllegalArgumentException(name + " has an empty key at position " + i + " of keysToGet"); + } + if (!seen.add(key)) { + throw new IllegalArgumentException(name + " declares the key \"" + key + "\" twice"); + } + boolean required = reactor.keyRequired != null && i < reactor.keyRequired.length + && reactor.keyRequired[i] == 1; + + Class type = typeOf(reactor.getKeyTypeForMCP(key)); + Class items = Void.class; + boolean typeInferred = true; + String description = reactor.getDescriptionForKey(key); + boolean descriptionInferred = description == null || description.isBlank(); + if (descriptionInferred) { + description = "The " + key + " input"; + } + + PixelInput override = overrides.remove(key); + if (override != null) { + if (override.type() != Void.class) { + type = override.type(); + items = override.items(); + typeInferred = false; + } + if (!override.description().isBlank()) { + description = override.description(); + descriptionInferred = false; + } + if (override.required() == PixelInput.Requirement.REQUIRED) { + required = true; + } else if (override.required() == PixelInput.Requirement.OPTIONAL) { + required = false; + } + } + inputs.add(new Input(key, type, items, description, required, typeInferred, descriptionInferred)); + } + if (!overrides.isEmpty()) { + throw new IllegalStateException(reactorClass.getName() + " has @PixelInput for " + overrides.keySet() + + ", which are not in its keysToGet"); + } + + String description = reactor.getReactorDescription(); + boolean descriptionInferred = description == null || description.isBlank(); + if (descriptionInferred) { + description = name + " reactor"; + } + + PixelOutput declared = reactorClass.getAnnotation(PixelOutput.class); + Output output = declared == null ? null + : new Output(declared.value(), declared.items(), declared.description()); + + return new ReactorContract(name, description, descriptionInferred, List.copyOf(inputs), output, + reactorClass.getAnnotation(Internal.class)); + } + + /** Maps the type a reactor reports for MCP to a Java type. */ + private static Class typeOf(IReactor.MCP_KEY_TYPE type) { + if (type == null) { + return String.class; + } + return switch (type) { + case INTEGER -> Integer.class; + case NUMBER -> Double.class; + case BOOLEAN -> Boolean.class; + case ARRAY -> List.class; + case OBJECT -> Map.class; + default -> String.class; + }; + } +} diff --git a/src/prerna/reactor/ReactorFactory.java b/src/prerna/reactor/ReactorFactory.java index 13fd7baddc7..d44d5dd25da 100644 --- a/src/prerna/reactor/ReactorFactory.java +++ b/src/prerna/reactor/ReactorFactory.java @@ -501,44 +501,25 @@ private static void loadFromCP(String... packages) { // ignore abstract and engines if (!Modifier.isAbstract(actualClass.getModifiers()) && !Arrays.asList(actualClass.getInterfaces()).contains(IEngine.class)) { - String[] packagePaths = packageName.split("\\."); - // System.out.println("Package name " + packageName); - packageName = packagePaths[packagePaths.length - 1]; - boolean frame = false; - if (packagePaths.length > 2) { - frame = packagePaths[packagePaths.length - 2].equalsIgnoreCase("frame"); - } - // we will allow for 1 more level - // i.e. things of the form so *.frame.r.? - if (!frame && packagePaths.length > 3) { - packageName = packagePaths[packagePaths.length - 2]; - frame = packagePaths[packagePaths.length - 3].equalsIgnoreCase("frame"); - } - String reactorName = name; - final String REACTOR_KEY = "REACTOR"; - if (reactorName.toUpperCase().endsWith(REACTOR_KEY)) { - reactorName = reactorName.substring(0, reactorName.length() - REACTOR_KEY.length()); - } + // ReactorNames holds these rules so the OpenAPI export reads reactors the same way + String reactorName = ReactorNames.pixelName(name); + String frameType = ReactorNames.frameType(packageName); - if (frame) { - if (packageName.equalsIgnoreCase("rdbms")) { + if (frameType != null) { + if (frameType.equalsIgnoreCase("rdbms")) { h2FrameHash.put(reactorName, actualClass); - } else if (packageName.equalsIgnoreCase("r")) { + } else if (frameType.equalsIgnoreCase("r")) { rFrameHash.put(reactorName, actualClass); - } else if (packageName.equalsIgnoreCase("py")) { + } else if (frameType.equalsIgnoreCase("py")) { pandasFrameHash.put(reactorName, actualClass); - } else if (packageName.equalsIgnoreCase("tinker") || packageName.equalsIgnoreCase("graph")) { + } else { + // tinker or graph tinkerFrameHash.put(reactorName, actualClass); - } else {// nullify the package name - packageName = null; - // general reactor - // example - frame filters - reactorHash.put(reactorName, actualClass); - } - if (packageName != null) { - reactorName = packageName + "_" + reactorName; } + reactorName = frameType + "_" + reactorName; } else { + // general reactor, including those under a frame package that is + // not a frame type, such as frame filters reactorHash.put(reactorName, actualClass); } nmList.add(reactorName); diff --git a/src/prerna/reactor/ReactorNames.java b/src/prerna/reactor/ReactorNames.java new file mode 100644 index 00000000000..9629a8cfbae --- /dev/null +++ b/src/prerna/reactor/ReactorNames.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ +package prerna.reactor; + +import java.util.Set; + +/** + * How a reactor class is named in Pixel and whether it belongs to one frame + * type. {@link ReactorFactory} registers reactors with these rules, and the + * OpenAPI export reads contracts with them, so both always agree. + */ +public final class ReactorNames { + + private static final String REACTOR_SUFFIX = "REACTOR"; + private static final Set FRAME_TYPES = Set.of("rdbms", "r", "py", "tinker", "graph"); + + private ReactorNames() { + } + + /** The name a reactor is called by in Pixel: its class name without "Reactor". */ + public static String pixelName(String simpleClassName) { + if (simpleClassName.toUpperCase().endsWith(REACTOR_SUFFIX)) { + return simpleClassName.substring(0, simpleClassName.length() - REACTOR_SUFFIX.length()); + } + return simpleClassName; + } + + /** + * The frame type a reactor in this package is specific to, as written in the + * package (such as {@code r} for {@code prerna.reactor.frame.r}), or null for + * a general reactor. A package one level below {@code frame}, or two + * ({@code *.frame.r.util}), names its frame type. + */ + public static String frameType(String packageName) { + String[] packagePaths = packageName.split("\\."); + String last = packagePaths[packagePaths.length - 1]; + boolean frame = false; + if (packagePaths.length > 2) { + frame = packagePaths[packagePaths.length - 2].equalsIgnoreCase("frame"); + } + // we will allow for 1 more level + // i.e. things of the form so *.frame.r.? + if (!frame && packagePaths.length > 3) { + last = packagePaths[packagePaths.length - 2]; + frame = packagePaths[packagePaths.length - 3].equalsIgnoreCase("frame"); + } + if (frame && FRAME_TYPES.contains(last.toLowerCase())) { + return last; + } + // not under frame, or a general reactor under it (such as frame filters) + return null; + } +} diff --git a/src/prerna/reactor/StopPixelExecutionReactor.java b/src/prerna/reactor/StopPixelExecutionReactor.java index af9a740fdb7..c2c92307281 100644 --- a/src/prerna/reactor/StopPixelExecutionReactor.java +++ b/src/prerna/reactor/StopPixelExecutionReactor.java @@ -29,6 +29,7 @@ import java.util.Objects; +import prerna.openapi.PixelOutput; import prerna.auth.User; import prerna.auth.utils.SecurityAdminUtils; import prerna.reactor.agent.AgentCancelHook; @@ -42,6 +43,7 @@ import prerna.sablecc2.om.nounmeta.NounMetadata; import prerna.tcp.client.SocketClient; +@PixelOutput(value = String.class, description = "Whether the job was not found, asked to cancel, or already completed") public class StopPixelExecutionReactor extends AbstractReactor { public StopPixelExecutionReactor() { diff --git a/src/prerna/reactor/insights/GetCurrentInsightIdReactor.java b/src/prerna/reactor/insights/GetCurrentInsightIdReactor.java index 1ea0fb933d5..7abd704dfb2 100644 --- a/src/prerna/reactor/insights/GetCurrentInsightIdReactor.java +++ b/src/prerna/reactor/insights/GetCurrentInsightIdReactor.java @@ -27,10 +27,12 @@ *******************************************************************************/ package prerna.reactor.insights; +import prerna.openapi.PixelOutput; import prerna.reactor.AbstractReactor; import prerna.sablecc2.om.PixelDataType; import prerna.sablecc2.om.nounmeta.NounMetadata; +@PixelOutput(value = String.class, description = "The id of the current insight") public class GetCurrentInsightIdReactor extends AbstractReactor { @Override diff --git a/test/prerna/auth/utils/ModelUsageLimitColumnMigrationUnitTests.java b/test/prerna/auth/utils/ModelUsageLimitColumnMigrationUnitTests.java index c0e01e895d0..c240113fad8 100644 --- a/test/prerna/auth/utils/ModelUsageLimitColumnMigrationUnitTests.java +++ b/test/prerna/auth/utils/ModelUsageLimitColumnMigrationUnitTests.java @@ -1,3 +1,30 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ package prerna.auth.utils; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/test/prerna/collaboration/WorkRoutineDocumentsUnitTests.java b/test/prerna/collaboration/WorkRoutineDocumentsUnitTests.java index 803b8a60b50..b703f6c434b 100644 --- a/test/prerna/collaboration/WorkRoutineDocumentsUnitTests.java +++ b/test/prerna/collaboration/WorkRoutineDocumentsUnitTests.java @@ -1,3 +1,30 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ package prerna.collaboration; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/test/prerna/ds/py/PandasCompatibilityTests.java b/test/prerna/ds/py/PandasCompatibilityTests.java index d41bcafdbda..13611a4fe03 100644 --- a/test/prerna/ds/py/PandasCompatibilityTests.java +++ b/test/prerna/ds/py/PandasCompatibilityTests.java @@ -1,3 +1,30 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ package prerna.ds.py; import static org.junit.jupiter.api.Assertions.assertArrayEquals; diff --git a/test/prerna/engine/impl/model/ModelRouterEngineTurnRoutingUnitTests.java b/test/prerna/engine/impl/model/ModelRouterEngineTurnRoutingUnitTests.java index 0ff29188c7e..7fa9205c17b 100644 --- a/test/prerna/engine/impl/model/ModelRouterEngineTurnRoutingUnitTests.java +++ b/test/prerna/engine/impl/model/ModelRouterEngineTurnRoutingUnitTests.java @@ -1,3 +1,30 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ package prerna.engine.impl.model; import static org.junit.jupiter.api.Assertions.*; diff --git a/test/prerna/engine/impl/model/ModelRouterEngineTypeSafeUnitTests.java b/test/prerna/engine/impl/model/ModelRouterEngineTypeSafeUnitTests.java index cb46278ebd8..1db02e9cf31 100644 --- a/test/prerna/engine/impl/model/ModelRouterEngineTypeSafeUnitTests.java +++ b/test/prerna/engine/impl/model/ModelRouterEngineTypeSafeUnitTests.java @@ -1,3 +1,30 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ package prerna.engine.impl.model; import static org.junit.jupiter.api.Assertions.*; diff --git a/test/prerna/engine/impl/model/usage/ModelUsageBilledToUnitTests.java b/test/prerna/engine/impl/model/usage/ModelUsageBilledToUnitTests.java index 151987bd7a5..6a484322daa 100644 --- a/test/prerna/engine/impl/model/usage/ModelUsageBilledToUnitTests.java +++ b/test/prerna/engine/impl/model/usage/ModelUsageBilledToUnitTests.java @@ -1,3 +1,30 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ /******************************************************************************* ' * Copyright 2015 Defense Health Agency (DHA) * diff --git a/test/prerna/reactor/ReactorContractTest.java b/test/prerna/reactor/ReactorContractTest.java new file mode 100644 index 00000000000..1556f09fe3e --- /dev/null +++ b/test/prerna/reactor/ReactorContractTest.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ +package prerna.reactor; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import prerna.openapi.Internal; +import prerna.openapi.PixelInput; +import prerna.openapi.PixelOutput; +import prerna.reactor.insights.GetCurrentInsightIdReactor; +import prerna.sablecc2.om.ReactorKeysEnum; +import prerna.sablecc2.om.nounmeta.NounMetadata; + +class ReactorContractTest { + + /** Declares keys the way most reactors do, with no annotations. */ + static class PlainReactor extends AbstractReactor { + PlainReactor() { + this.keysToGet = new String[] { "name,alias", ReactorKeysEnum.LIMIT.getKey(), "notes" }; + this.keyRequired = new int[] { 1, 0, 0 }; + } + + @Override + public NounMetadata execute() { + return null; + } + + @Override + protected String getDescriptionForKey(String key) { + return key.equals("notes") ? null : super.getDescriptionForKey(key); + } + } + + /** No keyRequired: organizeKeys() requires nothing. */ + static class NoRequiredReactor extends AbstractReactor { + NoRequiredReactor() { + this.keysToGet = new String[] { "a", "b" }; + } + + @Override + public NounMetadata execute() { + return null; + } + + @Override + public String getReactorDescription() { + return "Has no required keys"; + } + } + + @PixelInput(name = "a", type = List.class, items = String.class, description = "Some names", required = PixelInput.Requirement.REQUIRED) + @PixelInput(name = "b", required = PixelInput.Requirement.OPTIONAL) + @PixelOutput(value = List.class, items = Integer.class, description = "Some counts") + @Internal("Testing only") + static class AnnotatedReactor extends NoRequiredReactor { + } + + @PixelInput(name = "missing", type = String.class) + static class BadOverrideReactor extends NoRequiredReactor { + } + + static class TwiceReactor extends AbstractReactor { + TwiceReactor() { + this.keysToGet = new String[] { "a", "a,alias" }; + } + + @Override + public NounMetadata execute() { + return null; + } + } + + private static ReactorContract.Input input(ReactorContract contract, String name) { + return contract.inputs().stream().filter(i -> i.name().equals(name)).findFirst().orElseThrow(); + } + + @Test + void infersInputsFromKeysRequirednessTypesAndDescriptions() throws Exception { + ReactorContract contract = ReactorContract.of(PlainReactor.class); + + assertEquals("Plain", contract.name()); + assertEquals(List.of("name", "limit", "notes"), contract.inputs().stream().map(ReactorContract.Input::name).toList()); + assertTrue(input(contract, "name").required()); + assertFalse(input(contract, "limit").required()); + assertEquals(Integer.class, input(contract, "limit").type(), "LIMIT is an integer for MCP"); + assertEquals(String.class, input(contract, "name").type()); + assertTrue(input(contract, "name").typeInferred()); + + assertEquals("The notes input", input(contract, "notes").description()); + assertTrue(input(contract, "notes").descriptionInferred()); + assertEquals("Plain reactor", contract.description()); + assertTrue(contract.descriptionInferred()); + assertNull(contract.output()); + assertTrue(contract.inferred()); + } + + @Test + void treatsMissingKeyRequiredAsNothingRequiredLikeOrganizeKeys() throws Exception { + ReactorContract contract = ReactorContract.of(NoRequiredReactor.class); + + assertFalse(input(contract, "a").required()); + assertFalse(input(contract, "b").required()); + assertEquals("Has no required keys", contract.description()); + assertFalse(contract.descriptionInferred()); + } + + @Test + void appliesPixelInputPixelOutputAndInternal() throws Exception { + ReactorContract contract = ReactorContract.of(AnnotatedReactor.class); + + ReactorContract.Input a = input(contract, "a"); + assertEquals(List.class, a.type()); + assertEquals(String.class, a.items()); + assertEquals("Some names", a.description()); + assertTrue(a.required()); + assertFalse(a.typeInferred()); + + ReactorContract.Input b = input(contract, "b"); + assertFalse(b.required()); + assertTrue(b.typeInferred(), "a @PixelInput without a type keeps the inferred one"); + + assertEquals(List.class, contract.output().type()); + assertEquals(Integer.class, contract.output().items()); + assertEquals("Some counts", contract.output().description()); + assertEquals("Testing only", contract.internal().value()); + } + + @Test + void rejectsAPixelInputForAKeyTheReactorDoesNotDeclare() { + IllegalStateException error = assertThrows(IllegalStateException.class, + () -> ReactorContract.of(BadOverrideReactor.class)); + assertTrue(error.getMessage().contains("[missing]"), error.getMessage()); + } + + @Test + void rejectsAKeyDeclaredTwice() { + assertThrows(IllegalArgumentException.class, () -> ReactorContract.of(TwiceReactor.class)); + } + + @Test + void namesAndFrameTypesFollowReactorFactory() { + assertEquals("StopPixelExecution", ReactorNames.pixelName("StopPixelExecutionReactor")); + assertEquals("Plain", ReactorNames.pixelName("Plain")); + assertEquals("r", ReactorNames.frameType("prerna.reactor.frame.r")); + assertEquals("py", ReactorNames.frameType("prerna.reactor.frame.py.util")); + assertEquals("rdbms", ReactorNames.frameType("prerna.reactor.frame.rdbms")); + assertNull(ReactorNames.frameType("prerna.reactor.frame.filter"), "frame filters are general"); + assertNull(ReactorNames.frameType("prerna.reactor.insights")); + assertTrue(ReactorContract.isGeneral(GetCurrentInsightIdReactor.class)); + } + + @Test + void readsThePilotReactors() throws Exception { + ReactorContract stop = ReactorContract.of(StopPixelExecutionReactor.class); + assertEquals(List.of("id"), stop.inputs().stream().map(ReactorContract.Input::name).toList()); + assertTrue(input(stop, "id").required()); + assertEquals(String.class, input(stop, "id").type()); + assertEquals(String.class, stop.output().type()); + assertEquals("Stop the current execution of a pixel job", stop.description()); + + ReactorContract echo = ReactorContract.of(EchoReactor.class); + assertEquals(Object.class, input(echo, "value").type()); + assertFalse(input(echo, "value").required()); + assertNull(echo.output()); + + ReactorContract insight = ReactorContract.of(GetCurrentInsightIdReactor.class); + assertTrue(insight.inputs().isEmpty()); + assertEquals(String.class, insight.output().type()); + } +} diff --git a/test/prerna/reactor/collaboration/WorkShowItemReactorUnitTests.java b/test/prerna/reactor/collaboration/WorkShowItemReactorUnitTests.java index fba17b350ce..734be95daaa 100644 --- a/test/prerna/reactor/collaboration/WorkShowItemReactorUnitTests.java +++ b/test/prerna/reactor/collaboration/WorkShowItemReactorUnitTests.java @@ -1,3 +1,30 @@ +/******************************************************************************* + * Copyright 2015 Defense Health Agency (DHA) + * + * If your use of this software does not include any GPLv2 components: + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ---------------------------------------------------------------------------- + * If your use of this software includes any GPLv2 components: + * 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 2 + * 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. + *******************************************************************************/ package prerna.reactor.collaboration; import static org.junit.jupiter.api.Assertions.assertEquals;