├── .gitignore ├── .whitesource ├── LICENSE-2.0.txt ├── README.md ├── actions-basic.md ├── advanced-actions.md ├── creating-dialogs.md ├── dev-guidelines.md ├── import-and-discovery.md ├── listeners.md ├── pom.xml ├── ready-api-plugin-archetype ├── README.md ├── pom.xml └── src │ └── main │ └── resources │ ├── META-INF │ └── maven │ │ └── archetype-metadata.xml │ ├── archetype-resources │ ├── pom.xml │ └── src │ │ └── main │ │ └── __language__ │ │ ├── ActionGroups.__language__ │ │ ├── My__type__.__language__ │ │ └── PluginConfig.__language__ │ ├── common │ └── ActionGroups.txt │ ├── groovy │ ├── Action.inc │ ├── Assertion.inc │ ├── Discovery.inc │ ├── Import.inc │ ├── Listener.inc │ ├── Panelbuilder.inc │ ├── Prefs.inc │ ├── RequestEditor.inc │ ├── RequestFilter.inc │ ├── RequestInspector.inc │ ├── ResponseEditor.inc │ ├── ResponseInspector.inc │ ├── SubReport.inc │ ├── TestStep.inc │ ├── ToolbarAction.inc │ ├── Transport.inc │ └── ValueProvider.inc │ └── java │ ├── Action.inc │ ├── Assertion.inc │ ├── Discovery.inc │ ├── Import.inc │ ├── Listener.inc │ ├── PanelBuilder.inc │ ├── Prefs.inc │ ├── RequestEditor.inc │ ├── RequestFilter.inc │ ├── RequestInspector.inc │ ├── ResponseEditor.inc │ ├── ResponseInspector.inc │ ├── SubReport.inc │ ├── TestStep.inc │ ├── ToolbarAction.inc │ ├── Transport.inc │ └── ValueProvider.inc ├── ready-api-plugin-template-test ├── pom.xml └── src │ └── test │ └── java │ └── com │ └── smartbear │ └── ready │ └── template │ └── TestPluginTemplate.java └── ready-api-plugin-template ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── smartbear │ └── ready │ └── plugin │ └── template │ ├── PluginConfig.java │ ├── actions │ ├── SampleJavaAction.java │ └── SampleToolbarAction.java │ ├── factories │ ├── SampleDiscoveryMethod.java │ ├── SampleImportMethod.java │ ├── SamplePanelBuilder.java │ ├── SamplePrefs.java │ ├── SampleRequestEditorView.java │ ├── SampleRequestFilter.java │ ├── SampleRequestInspector.java │ ├── SampleRequestTransport.java │ ├── SampleResponseEditorView.java │ ├── SampleResponseInspector.java │ ├── SampleSubReport.java │ ├── SampleTestAssertion.java │ ├── SampleTestStep.java │ └── SampleValueProvider.java │ └── listeners │ └── SampleJavaListener.java └── resources └── com └── smartbear └── ready └── plugin └── template ├── GroovyAction.groovy ├── TemplateScript.groovy └── factories └── SampleGroovyTestStep.groovy /.gitignore: -------------------------------------------------------------------------------- 1 | # Project files 2 | *.iml 3 | *.idea 4 | .settings/ 5 | .classpath 6 | .project 7 | *-ide-plugin.xml 8 | 9 | # Logs 10 | *.log 11 | 12 | # Build folders 13 | target/ 14 | 15 | # plugin / extension folders 16 | soapui/ext 17 | soapui/plugins 18 | 19 | # Altered tests 20 | soapui-pro/test/ 21 | soapui-pro/ext 22 | 23 | # Misc 24 | proguard-mapping.txt 25 | 26 | ready-api-ui/src/.install4j -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "settingsInheritedFrom": "SmartBear/whitesource-config@main" 3 | } -------------------------------------------------------------------------------- /LICENSE-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ReadyAPI Plugin Development Kit 2 | ================================== 3 | 4 | Here you'll find everything needed to get started with building plugins for SmartBear's ReadyAPI Platform. 5 | 6 | * Go to https://support.smartbear.com/readyapi/docs/configure/plugins/dev/index.html for documentation, samples, etc 7 | * Check out and build this project locally (with ```mvn install```) to get access to the [maven archetype](https://github.com/SmartBear/ready-api-plugins/tree/master/ready-api-plugin-archetype) and [plugin template](https://github.com/SmartBear/ready-api-plugins/tree/master/ready-api-plugin-template) for getting started 8 | quickly with building plugins. 9 | 10 | We've also included documentation on how to build different plugin components. 11 | 12 | * [Actions](actions-basic.md) - how to add menu and toolbar items 13 | * [Listeners](listeners.md) - how to handle events occurring during the usage of ReadyAPI, for example test-executions, 14 | project changes, etc. 15 | * [Import and Discovery methods](import-and-discovery.md) - how to add new ways of creating ReadyAPI projects from 16 | external data 17 | 18 | And some general guidelines for ReadyAPI plugin development. 19 | 20 | * [General Guidelines](dev-guidelines.md) (Logging, Analytics, etc...) 21 | * [Creating dialogs](creating-dialogs.md) 22 | 23 | If you're looking for some specific content - please don't hesitate to 24 | [open an issue](https://github.com/SmartBear/ready-api-plugins/issues/new)! 25 | 26 | ##Existing Plugins 27 | 28 | Many of the existing plugins are open-sourced here at GitHub and make use of the above outlined extension points and 29 | concepts. Have a look at them to get an understanding of how to add similar features to your plugins: 30 | 31 | * [Swagger Plugin](https://github.com/olensmar/soapui-swagger-plugin) Adds functionality for importing and exporting 32 | Swagger definitions to/from REST APIs, 33 | * [RAML Plugin](https://github.com/olensmar/soapui-raml-plugin) Adds functionality for importing and exporting RAML 34 | definitions to/from REST APIs. Also has an action to browser the Mulesoft ApiHub API directory and import API definitions 35 | directly from there. 36 | * [API Blueprint Plugin](https://github.com/olensmar/soapui-blueprint-plugin) Adds functionality for importing and exporting 37 | API-Blueprint definitions to/from REST APIs. 38 | * [Groovy Console Plugin](https://github.com/olensmar/soapui-groovy-console-plugin) Adds an interactive Groovy Console for 39 | trying out groovy scripts dynamically within ReadyAPI 40 | * [3Scale Plugin](https://github.com/SmartBear/ready-3scale-plugin) Allows you to import APIs directly from a 3Scale hosted developer portal. 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /actions-basic.md: -------------------------------------------------------------------------------- 1 | ## How to create Actions in Ready! API 2 | Ready! API defines the concepts of Actions, ActionGroups and ActionMappings; 3 | 4 | - Actions are singleton functions most commonly invoked through some UI component (toolbar buttons, menu items, etc) on a target [ModelItem](https://github.com/SmartBear/soapui/blob/next/ready-api-core/src/main/java/com/eviware/soapui/model/ModelItem.java) object 5 | - ActionGroups are groups of actions that together form top-level/popup menus, toolbars, etc. 6 | - ActionMappings define the relationship between an Action and a specific ActionGroup; a single Action can be mapped to multiple ActionGroups, and have different names, descriptions, keyboard-shortcuts, etc. For example, a generic "Rename" Action could be mapped into multiple menus/popup/etc. 7 | 8 | ### Implementation and Action loading 9 | 10 | The [SoapUIAction](https://github.com/SmartBear/soapui/blob/next/soapui/src/main/java/com/eviware/soapui/support/action/SoapUIAction.java), [SoapUIActionGroup](https://github.com/SmartBear/soapui/blob/next/soapui/src/main/java/com/eviware/soapui/support/action/SoapUIActionMapping.java) correspondingly define java interfaces for these three concepts - and in SoapUI/SoapUI-Pro the whole action hierarchy was read from [soapui-actions.xml](https://github.com/SmartBear/axm/blob/next/soapui/src/main/resources/com/eviware/soapui/resources/conf/soapui-actions.xml)/[soapui-pro-actions.xml](https://github.com/SmartBear/axm/blob/next/soapui-pro/src/main/resources/com/eviware/soapui/resources/conf/soapui-pro-actions.xml) files which were loaded at startup. Plugins could add their own actions by providing their own XML files, and recently the Plugin architecture was improved to allows actions to be added solely via the ActionConfiguration and ActionConfigurations annotations. 11 | 12 | Both Actions and ActionGroups are internally identified by unique ID:s, which are used for referencing them in related objects, methods and annotations. 13 | 14 | If you use the Maven Archetype to generate a stub for your plugin code, the Java source file ActionGroups.java will be generated for you, with constants holding the names of existing action groups in Ready API 15 | 16 | The template used to generate this file can be found [here](ready-api-plugin-archetype/src/main/resources/common/ActionGroups.txt). 17 | 18 | ### Defining an Action 19 | To define an action in a plugin, all you need to do the following: 20 | 21 | 1. Create a class extending AbstractSoapUIAction, where T is the type of model item you want to perform the action for, such as RestService or TestSuite. 22 | 2. Define a constructor calling the constructor AbstractSoapUIAction(String, String). The first argument will be used as the text for the action in the menu etc; the second argument will be used as the tooltip text. 23 | 3. Annotate the class with @ActionConfiguration, setting the attribute actionGroup to the ID of the Action group (i.e. the menu) you want the action to appear in. 24 | 25 | Here is an example, taken from the [Retrofit Plugin](https://github.com/olensmar/soapui-retrofit-plugin): 26 | ```java 27 | @ActionConfiguration( actionGroup = "RestServiceActions" ) 28 | public class GenerateRetrofitAction extends AbstractSoapUIAction { 29 | 30 | 31 | public GenerateRetrofitAction() 32 | { 33 | super( "Generate Retrofit Interface", "Generates a Retrofit Java Interface for this REST API"); 34 | } 35 | 36 | ``` 37 | 38 | This action will add the item Generate Retrofit Interface to the context menu for a REST Service, shown in the Projects Tool. When the menu item is clicked, the perform() method of the action class will be invoked, and the REST service will be passed as a parameter. 39 | 40 | 41 | ### Ready! API Actions and Guice 42 | 43 | Actions contained in a auto-scanned Ready! API Guice Module that created through any of the aforementioned annotations are all instantiated via Guice, and can thus inject any other Ready! API objects they may need access to to perform their work. 44 | 45 | 46 | ### Things to remember 47 | Actions are singletons - which means that they will be invoked for different target objects - make sure to clear an target-object-specific content (for example in a dialog field) each time an action is invoked. If possible, don't share any state whatsoever across invocations. 48 | 49 | [This page](advanced-actions.md) contains more advanced information about developing actions. 50 | -------------------------------------------------------------------------------- /advanced-actions.md: -------------------------------------------------------------------------------- 1 | ## Advanced action topics 2 | 3 | ### The TargetProvider interface 4 | 5 | In SoapUI, action-groups were dynamically transformed into popup-menus for a selected ModelItem (allowing all actions in an ActionGroup to work on the same type and instance of a ModelItem) - in Ready! API this changes as top-level menus and toolbars can contain Actions that target different ModelItems - requiring an extension of the underlying Action mechanism. 6 | 7 | The most notable addition to achieve this is the TargetProvider interface; 8 | 9 | ```java 10 | package com.eviware.soapui.support.action.swing; 11 | 12 | import com.eviware.soapui.model.ModelItem; 13 | 14 | /** 15 | * Defers the selection of an action target until when the action is actually invoked 16 | */ 17 | 18 | public interface TargetProvider { 19 | T getTargetModelItem(); 20 | 21 | public static class StaticTargetProvider implements TargetProvider { 22 | private final T target; 23 | 24 | public StaticTargetProvider(T target) { 25 | this.target = target; 26 | } 27 | 28 | @Override 29 | public T getTargetModelItem() { 30 | return target; 31 | } 32 | } 33 | 34 | } 35 | ``` 36 | Internally created action mappings now hold a reference to a TargetProvider instead of a static target ModelItem object, which provides the target object for an Action when the action is invoked. 37 | 38 | As you can see a StaticTargetProvider is available for action mappings that work on a fixed object (for example top-level Workspace actions). 39 | 40 | ### Enabling/Disabling menu/toolbar actions 41 | 42 | The ActionConfiguration annotation has been extended with targetType- if specified in conjunction with building top level menus and toolbars with the corresponding ReadyApiModuleMenu objects - the corresponding menu-items and toolbar items will get enabled/disabled as their corresponding target objects are selected in the Ready! API user interface. 43 | 44 | For example, the following action: 45 | 46 | ```java 47 | ActionConfiguration(actionGroup = ApisActionGroups.APIS_MODULE_TOP_LEVEL_PROJECT_ACTIONS, 48 | targetType = Interface.class) 49 | public class ShowInterfaceNameAction extends AbstractSoapUIAction { 50 | 51 | public ShowInterfaceNameAction() { 52 | super("ShowInterfaceNameAction", "Show Interface Name", "Shows the name of this interface"); 53 | } 54 | 55 | @Override 56 | public void perform(Interface target, Object param) { 57 | UISupport.showInfoMessage("The name of this interface is " + target.getName()); 58 | } 59 | } 60 | ``` 61 | Will only be enabled if an Interface or one of its contained objects is in focus. 62 | 63 | Sometimes this is not enough though; perhaps an action should be enabled based on some state of the target object - which is where the TargetProvider interface (shown above) come into play. Action should implement TargetProvider interface in that case and override method 'getTargetModelItem()' to return an instance of model item only when conditions are met otherwise it should return null. Implementing this interface will cause the ReadyApiModuleMenu class to query the action itself for target model item and it will enable it if model item is not null. For example following action 64 | ```java 65 | @ActionConfiguration(actionGroup = ApisActionGroups.APIS_MODULE_TOP_LEVEL_PROJECT_ACTIONS, targetType = Interface.class) 66 | public class ShowInterfaceNameAction extends AbstractSoapUIAction implements TargetProvider { 67 | private ContextModelItemProvider contextModelItemProvider; 68 | 69 | public ShowInterfaceNameAction() { 70 | super("ShowInterfaceNameAction", "Show Interface Name", "Shows the name of this interface"); 71 | contextModelItemProvider = new ContextModelItemProvider(Interface.class); 72 | } 73 | 74 | @Override 75 | public void perform(Interface target, Object param) { 76 | UISupport.showInfoMessage("The name of this interface is " + target.getName()); 77 | } 78 | 79 | @Override 80 | public Interface getTargetModelItem() { 81 | Interface targetModelItem = contextModelItemProvider.getTargetModelItem(); 82 | return targetModelItem.getName().startsWith("A") ? targetModelItem: null; 83 | } 84 | } 85 | 86 | ``` 87 | The above will result in an action which will only be enabled for interfaces having names starting with 'A'. 88 | 89 | ### ActionGroup and ActionMapping Annotations 90 | 91 | Ready! API further extends the Action annotation possibility to include not only actions (which was done via the afore mentioned annotations), but also entire action groups via the ActionGroup and ActionMapping annotations, which allows Ready! API modules to define all their menus and toolbars via annotations only, for example; 92 | 93 | ```java 94 | package com.smartbear.ready.ui.actions.file; 95 | 96 | import com.eviware.soapui.actions.SoapUIPreferencesAction; 97 | import com.eviware.soapui.model.workspace.Workspace; 98 | import com.eviware.soapui.plugins.ActionGroup; 99 | import com.eviware.soapui.plugins.ActionMapping; 100 | import com.eviware.soapui.support.action.support.DefaultSoapUIActionGroup; 101 | import com.smartbear.ready.ui.actions.ReadyApiCommonActionGroups; 102 | 103 | @ActionGroup(actions = { 104 | @ActionMapping(groupId = "WorkspaceImplActions", type = ActionMapping.Type.INSERT), 105 | @ActionMapping(type = ActionMapping.Type.SEPARATOR), 106 | @ActionMapping(actionClass = SoapUIPreferencesAction.class), 107 | @ActionMapping(actionClass = SavePreferencesAction.class), 108 | @ActionMapping(actionClass = ImportPreferencesAction.class), 109 | @ActionMapping(type = ActionMapping.Type.SEPARATOR), 110 | @ActionMapping(actionClass = ExitAction.class), 111 | }) 112 | public class FileMenuActionGroup extends DefaultSoapUIActionGroup { 113 | public FileMenuActionGroup() { 114 | super(ReadyApiCommonActionGroups.READY_API_FILE_ACTIONS, "File"); 115 | } 116 | } 117 | ``` 118 | Here you can see several features in action; 119 | - the first @ActionMapping inserts an entire action group into this group, allowing for re-usable groups of actions to be defined. Using the ActionMapping.Type.GROUP type would have resulted in a sub-menu instead. 120 | - two separators are added by setting the type of mapping to ActionMapping.Type.Separator 121 | - the actionClasses defined can be either SoapUIActions or regular Swing Actions - the later will get the current target object specified as the source object of the corresponding ActionEvent. 122 | 123 | The annotation is applied to classes that implements the SoapUIActionGroup interface - the DefaultSoapUIActionGroup class can be used in most cases as super-class, which only requires you to specify an ID and Name for the group. If you want to customize how actions in an action group are translated into ActionMapping objects you can override the getActionMappings(...) method in SoapUIActionGroup, you could for example return different mappings based on which license(s) a user. 124 | 125 | -------------------------------------------------------------------------------- /creating-dialogs.md: -------------------------------------------------------------------------------- 1 | #Creating Dialogs 2 | 3 | Ready! API has a rather elaborate framework for building dialogs that look and behave consistently, relieving you 4 | of having to write code specifically for Swing components, layouts, etc. Using the framework is achieved by the 5 | following steps: 6 | 7 | 1. Define an annotated interface with constant members for each field in the form 8 | 2. When you need the dialog - build an instance of it using the ADialogBuilder and set initial values, 9 | validators and listeners 10 | 3. Show the dialog and process its "results" when it is closed 11 | 12 | Let's walk through a simple example taken from the [ExportSwaggerAction](https://github.com/olensmar/soapui-swagger-plugin/blob/master/src/main/groovy/com/smartbear/restplugin/ExportSwaggerAction.java) in the 13 | tex[Swagger Plugin](https://github.com/olensmar/soapui-swagger-plugin). 14 | 15 | ## 1. Define the interface 16 | 17 | The ExportSwaggerAction prompts you to export a Swagger definition from a REST API in Ready! API. The Form for this 18 | is defined as follows: 19 | 20 | ```java 21 | @AForm( name = "Export Swagger Definition", description = "Creates a Swagger definition for selected REST APIs in this project" ) 22 | public interface Form 23 | { 24 | @AField( name = "APIs", description = "Select which REST APIs to include in the Swagger definition", type = AFieldType.MULTILIST ) 25 | public final static String APIS = "APIs"; 26 | 27 | @AField( name = "Target Folder", description = "Where to save the Swagger definition", type = AFieldType.FOLDER ) 28 | public final static String FOLDER = "Target Folder"; 29 | 30 | @AField( name = "API Version", description = "API Version", type = AFieldType.STRING ) 31 | public final static String VERSION = "API Version"; 32 | 33 | @AField( name = "Base Path", description = "Base Path that the Swagger definition will be hosted on", type = AFieldType.STRING ) 34 | public final static String BASEPATH = "Base Path"; 35 | 36 | @AField(name = "Swagger Version", description = "Select Swagger version", type = AFieldType.RADIOGROUP, values = {"1.2", "2.0"}) 37 | public final static String SWAGGER_VERSION = "Swagger Version"; 38 | 39 | @AField(name = "Format", description = "Select Swagger format", type = AFieldType.RADIOGROUP, values = {"json", "yaml", "xml"}) 40 | public final static String FORMAT = "Format"; 41 | } 42 | ``` 43 | 44 | The key points being: 45 | 46 | - The interface is annotated with the @AForm annotation which has attributes for the name and description of the dialog 47 | - The interface contains a number of ```public final static String``` constants which are annotated with a corresponding 48 | @AField annotation. Note the following: 49 | - the name attribute *has* to have the exact same value as the value of the constant itself 50 | - the type attribute specifies which type of field to show - the default type is AFieldType.String 51 | - values can optionally be specified at design time using the values attribute 52 | 53 | 54 | ## 2. Build the dialog and set initial values, validators and listeners 55 | 56 | When we need to display the actual dialog - we use the ADialogBuilder to build and initialize it; 57 | 58 | ```java 59 | XFormDialog dialog = ADialogBuilder.buildDialog( Form.class ); 60 | 61 | dialog.setValue(Form.FORMAT, settings.getString(FORMAT, "json")); 62 | dialog.setValue(Form.VERSION, settings.getString(VERSION, "1.0")); 63 | dialog.setValue(Form.BASEPATH, settings.getString(BASE_PATH, "" )); 64 | dialog.setValue(Form.FOLDER, settings.getString(TARGET_PATH, "" )); 65 | dialog.setValue(Form.SWAGGER_VERSION, settings.getString(SWAGGER_VERSION, "2.0")); 66 | 67 | XFormOptionsField apis = (XFormOptionsField) dialog.getFormField(Form.APIS); 68 | apis.setOptions(...); 69 | ``` 70 | 71 | Note that the first argument to the setValue method is the constant for the corresponding field. Furthermore the 72 | actual field for the Form.APIS constant is retrieved and configured via the XFormOptionsField.setOptions(...) method. 73 | 74 | We could further add XFormFieldValidators and XFormFieldListeners to desired fields to handle field-specific logic, for 75 | example enable/disable other fields if a certain value is selected - or validate the input of a desired field to be 76 | in line with our requirements. 77 | 78 | ## 3. Show the dialog and "use" its results 79 | 80 | Once the dialog has been set up correctly - show it with 81 | 82 | ```java 83 | if( dialog.show()) { 84 | // user pressed ok - get values and do something with them 85 | String version = dialog.getStringValue( Form.VERSION ); 86 | ... 87 | } 88 | ``` 89 | 90 | By default a dialog contains OK and Cancel buttons - if the user presses OK the dialog.show() method returns true. If 91 | you want to customize the actions of a dialog you can use the dialog.addAction(...) and dialog.getActionList() methods 92 | accordingly. 93 | 94 | 95 | -------------------------------------------------------------------------------- /dev-guidelines.md: -------------------------------------------------------------------------------- 1 | #General Guidelines 2 | 3 | General topics to help you build your plugins: 4 | 5 | - [UISupport](#uisupport) 6 | - [Logging](#logging) 7 | - [Usage Analytics](#usage-analytics) 8 | - [The Event Bus](#the-event-bus) 9 | 10 | ## UISupport 11 | 12 | [UISupport](http://www.soapui.org/apidocs/com/eviware/soapui/support/UISupport.html) contains a large number of static general UI-related utilities, including methods for 13 | 14 | - Showing popup alerts and prompts 15 | - Building common UI elements (toolbars, splitters, panels) 16 | - Opening windows for objects from the Ready! API object model 17 | 18 | ##Logging 19 | 20 | Due to backwards compatibility requirements with the old SoapUI Pro codebase we still use log4j under the hood, but we use slf4j for the actual logging calls in new Ready! API code - using the log4j bridge for slf4j underneath. For classes created with Guice you can create a looger with: 21 | 22 | ``` 23 | @ReadyApiLogger Logger logger; 24 | ``` 25 | 26 | This makes it possible for us to change how loggers are created centrally should we want to. 27 | 28 | > You must make sure your package contains a logger configured in `soapui-log4j.xml` for it to work! 29 | 30 | > LIMITATION: You must not try to use the logger in the constructor, either directly or indirectly, 31 | because currently, only field injection is supported (so the object must be created before the field 32 | can be injected). 33 | 34 | Currently the injector just does the same as `LoggerFactory.getLogger( )` 35 | 36 | ##Usage Analytics 37 | 38 | Ready! API provides an analytics API to track a users actions anonymously as they use the application. Adding your 39 | own counters is extremely easy, and SmartBear can provide you with data on the values of these counters over time. 40 | 41 | Tracking is done by calling the trackAction static method in the Analytics class: 42 | 43 | ```java 44 | 45 | import com.smartbear.analytics.Analytics; 46 | 47 | // log an action without parameters 48 | Analytics.trackAction( Category.CUSTOM_PLUGIN_ACTION, "DoSomething" ); 49 | 50 | // log an action with parameters 51 | Analytics.trackAction( Category.CUSTOM_PLUGIN_ACTION, "DoSomethingWithParameters", "Type", "VeryCool" ); 52 | ``` 53 | 54 | The first call above simply logs the that user has used the "DoSomething" action, after which a variable number of 55 | arguments are optional - but always need to be added in pairs (name,value); the second call above adds a "Type" parameter 56 | with the value "VeryCool" - use this possibility where you have a limited set of possible values, for example an enumeration. 57 | 58 | ##The Event Bus 59 | 60 | Ready! API internally uses an event-bus for triggering/handling both synchronous and asynchronous events. This is meant to (over time) replace the listener approach in the SoapUI code-base; instead of each observable object handling its own collection of listeners it can use the event-bus for distributing messages. 61 | 62 | The ReadyApiEventBus interface in ready-api-core defines the behaviour of the event bus: 63 | 64 | ```java 65 | public interface ReadyApiEventBus { 66 | 67 | void postAsync(ReadyApiMessage message); 68 | 69 | void post(ReadyApiMessage message); 70 | 71 | void register(Object listener); 72 | 73 | void unregister(Object listener); 74 | 75 | void clearEventBus(); 76 | } 77 | ``` 78 | 79 | There are two ways of accessing the available ReadyApiEventBus instance: 80 | 81 | 1. For classes created via Guice - inject it into your class with Guice @Inject (constructor, field or method) 82 | 2. For classes not created via Guice - use the static ReadyApiCoreModule.getEventBus() method - for these classes consider creating factory interfaces together with the Guice [AssistedInject](https://github.com/google/guice/wiki/AssistedInject) functionality. 83 | 84 | ### Posting and Receiving messages 85 | 86 | Posting messages can either be synchronously or asynchronously - use the later if you don't want to block the current thread of execution (but be sure that eventual objects you are sending with a message will still be valid when that message is delivered. 87 | 88 | Listening to messages is achieved by creating methods annotated with the @Handler annotation and registering the containing class with the EventBus which can either be done by calling ReadyApiEventBus.register or by annotating the class with @ReadyApiEventHandler - which will automatically perform this registration for you, provided that the class is created through Guice. 89 | 90 | ### Unregistering Handlers 91 | 92 | If you register handlers that are temporary - i.e. don't exist for the entire lifespan of the Ready! API session, you will need to unregister them using either the ReadyApiEventBus.unregister(...) method - or by adding a method annotated with @UnregisterReadyApiEventHandler to a @ReadyApiEventHandler class that gets called when the class is disposed (for example a release method). 93 | 94 | ### Implementation Notes 95 | 96 | Ready! API currently uses the [MBassador](https://github.com/bennidi/mbassador) project for implementing the ReadyApiEventBus interface. 97 | -------------------------------------------------------------------------------- /import-and-discovery.md: -------------------------------------------------------------------------------- 1 | ## Import and resource discovery in Ready! API 2 | 3 | To add a new way of converting external data into Ready! API projects, you must either define an _Import method_ or a 4 | _Discovery method_. The distinction between the two methods is largely a conceptual one; technically they are very similar. 5 | Both types will be inserted into the New project dialog, but in different select boxes. 6 | 7 | An import method takes something intended to be a definition of a service, such as a RAML or Swagger definition file, 8 | and converts it into a project. 9 | 10 | A discovery method, on the other hand, converts some source of raw data – a log file, a network trace, a binary – and 11 | organizes it internally before creating a project, or services to add to a project, from it. 12 | 13 | ### Steps for implementing an Import method 14 | To define an Import method in a plugin, do the following: 15 | 16 | 1. Create an action class targeting the class `WorkspaceImpl`, just like a standalone action, but without the annotation. 17 | 2. Create a class implementing the `ImportMethod` interface, and have the `getImportMethod()` method return the action created in the previous step. 18 | 3. Annotate the `ImportMethod` class with `@PluginImportMethod`, setting the attribute label to the label you want it to have in the New project dialog. 19 | 20 | When a user opts to import a project and selects the Import method you've added, the `perform()` method of your action class 21 | will be invoked. 22 | 23 | ### Steps for implementing an Discovery method 24 | To define an Import method in a plugin, do the following: 25 | 26 | 1. Create a class implementing the `ImportMethod` interface, which will be either synchronous or asynchronous (see below). 27 | 2. Annotate the `DiscoveryMethod` class with `@PluginDiscoveryMethod`, setting the attribute label to the label you want it to have in the New project dialog. 28 | 29 | When a user opts to discover resources in the New project dialog and then selects the Discovery method you've added, the `perform()` method of your action class 30 | will be invoked. 31 | 32 | If the `isSynchronous()` method of the Discovery method returns true, Ready! API expects the `discoverResourcesSynchronously()` method to 33 | return a List of DiscoveredRequest instances. It will then build a project from those resources. 34 | 35 | If, on the other hand, the `isSynchronous()` method of the Discovery method returns false, Ready! API simply invokes the `discoverResources()` 36 | and delegates the actual project creation completely to the plugin developer. 37 | 38 | It's good practice to let the method discover method that shouldn't be invoked throw `UnsupportedOperationException`. 39 | 40 | ### Methods are singletons 41 | Import and Discovery methods are singletons - which means that they will be invoked for different target objects, so be 42 | careful with persistent state. If possible, don't share any state whatsoever across invocations. 43 | 44 | ### Support for Guice injection 45 | 46 | Import and Discovery methods can inject any other Ready! API objects they may need access to to perform their work. They 47 | simply have to annotate the fields or setter methods with the Guice `@Inject` annotation. 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /listeners.md: -------------------------------------------------------------------------------- 1 | ## Listeners 2 | 3 | Listeners are object that react to different kinds of events in Ready! API. They are used heavily in Ready! API itself, but it's also very easy to add one in a plugin. Simply implement one of available listener interfaces (see below) and annotate your class with (https://github.com/SmartBear/soapui/blob/next/soapui/src/main/java/com/eviware.soapui.plugins.ListenerConfiguration. Your listener will be loaded and initialized. 4 | 5 | One of the listener interfaces – [RequestFilter](https://github.com/SmartBear/soapui/blob/next/soapui/src/main/java/com/eviware/soapui/impl/wsdl/submit/RequestFilter.java) 6 | – needs to be annotated in a special way, namely with the annotation `com.eviware.soapui.plugins.auto.RequestPluginFilter` 7 | 8 | Some useful facts about listeners in Ready! API: 9 | - Most listener interfaces in Ready! API come with adapter classes that can be subclassed, which is handy if you only want to implement some of the methods in the interface. 10 | - When Ready! API instantiates the listener, it will look for fields and setter methods annotated with the Guice annotation @Inject and will inject any other object known to the Guice context, including core services like the action registry and actions, for example. 11 | - If the listener class implements the interface (https://github.com/SmartBear/soapui/blob/next/soapui/src/main/java/com/eviware.soapui.plugins.PluginAware, the plugin configuration class will be passed into it using the setPlugin() method, which can be used to wire different parts of the plugin. 12 | 13 | # Listener interfaces 14 | 15 | The table below describes all the listener interfaces available in Ready! API and the adapter classed implementing them, when applicable. 16 | 17 | When possible, links are provided to the open source repository of SoapUI. 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 72 | 73 | 74 | 75 | 76 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 91 | 93 | 94 | 95 | 96 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |
InterfaceDescriptionAdapter class
com.eviware.soapui.lifecycle.ApplicationListenerInvoked when Ready! API is started and when it shuts down-
WorkspaceListenerInvoked when workspaces are switched, and when projects are added and removed.WorkspaceListenerAdapter
ProjectListenerKeeps tabs on a wide range of events related to projects. Methods are invoked after projects are loaded and before they are saved; 36 | when services ("interfaces"), test suites and virts are added to and removed from a project, and when test 37 | suites are moved to a new positionProjectListenerAdapter
InterfaceListenerHandles lifecycle events associated with APIs (typically REST or SOAP service) - when API operations are added, 43 | removed and updated, and when requests are added and removedInterfaceListenerAdapter
TestSuiteListenerHandles all lifecycle events associated with test suites and test cases: when test cases are added to and removed from test suites, 49 | and when test steps, security tests and load tests are added to and removed from test cases.TestSuiteListenerAdapter
EnvironmentListenerContains a single method that will be invoked whenever an environmental property is changed.-
TestSuiteListenerInvoked before and after a test case is run, and before and after each test step in a functional test, i.e. 60 | not in a security or load test.TestRunListenerAdapter
ProjectRunListenerInvoked before and after all the tests in a project are run, and before and after a test suite is run.-
SecurityTestRunListenerEquivalent to TestRunListener, but its methods are invoked before and after a security test and its 71 | test steps are executed. In addition, it provides methods that will be invoked before and after security scans.SecurityTestRunListenerAdapter
LoadTestRunListenerEquivalent to TestRunListener, but its methods are invoked before and after a load test and its 77 | test steps are executed. It also contains the method loadTestStopped(), which will be invoked if 78 | a load test is stopped before it completes.LoadTestRunListenerAdapter
SubmitListenerInvoked before and after a request is submitted to an API (usually REST or SOAP service) or other resource.-
RequestFilterThis interface allows you to intercept a request and modify it just before sending it, by writing an 89 | implementation for filterRequest(). You can also add a callback that will be invoked after the request 90 | has been sent and, if you subclass AbstractRequestFilter, you can examine the response.AbstractRequestFilter 92 | (technically not an adapter class, but very useful when you want to build a RequestFilter)
MockRunListenerCalled "MockRunListener" for historic reasons, this interface contains method that will be invoked when 97 | a virt starts and stops, when a virt receives a request and when it provides a result (response).MockRunListenerAdapter
MonitorListenerInvoked when the HTTP monitor intercepts requests.MonitorListenerAdapter
106 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.smartbear 8 | ready-api-plugins 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | ready-api-plugin-template 13 | ready-api-plugin-template-test 14 | ready-api-plugin-archetype 15 | 16 | 17 | 18 | 3.54.0 19 | 3.0.19 20 | 2.1.3 21 | 22 | 3.1.2 23 | 3.1.2 24 | 3.3.1 25 | 3.13.0 26 | 27 | 28 | 29 | 30 | eviware 31 | SmartBear Software Maven2 Repository 32 | http://smartbearsoftware.com/repository/maven2 33 | 34 | 35 | central 36 | Central Maven2 Repository 37 | http://repo1.maven.org/maven2 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/README.md: -------------------------------------------------------------------------------- 1 | ready-api-plugin-archetype 2 | ============================= 3 | 4 | A maven archetype for creating ReadyAPI Plugins - supports creation of the following types of plugins: 5 | - Action: creates an Action, by default at the Project level 6 | - Assertion: creates a custom assertion 7 | - Discovery: creates a custom REST Discovery method 8 | - Import: creates a custom Project Importer 9 | - Listener: creates a TestRunListener (you can change to any of the other supported listeners) 10 | - PanelBuilder: creates a PanelBuilder, use this if you create your own TestStep 11 | - Prefs: creates a custom tab in the global Preferences 12 | - RequestFilter: creates a custom Request filter, applied to all outgoing requests 13 | - RequestEditor: creates a custom Request Editor view 14 | - RequestInspector: creates a custom Request Inspector tab 15 | - ResponseEditor: creates a custom Response Editor view 16 | - ResponseInspector: creates a custom Response Inspector tab 17 | - SubReport: creates a custom SubReport data source 18 | - TestStep: creates a custom TestStep 19 | - ToolbarAction: creates a custom Toolbar item 20 | - ValueProvider: creates a custom property-expansion Value Provider 21 | 22 | The archetype can be used for both creating a new and adding to an existing project. 23 | 24 | Usage 25 | ----- 26 | 27 | Run the following maven command from the command-line: 28 | 29 | ``` 30 | mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeGroupId=com.smartbear -DarchetypeArtifactId=ready-api-plugin-archetype -DarchetypeCatalog=http://smartbearsoftware.com/repository/maven2/ 31 | ``` 32 | 33 | This will download the archetype from the SmartBear repository and start the project creation process. You will be prompted 34 | for the following: 35 | - groupId : the groupId to use in the generated pom.xml, for example "com.mycompany" 36 | - artifactId : the artifact set in the generated pom.xml, for example "my-readyapi-plugin" 37 | - version : the intial version of your plugin, defaults to "1.0-SNAPSHOT" 38 | - package : the package where your plugin code will be generated, defaults to the specified groupId 39 | - language : the language to generate for, specify either "java" or "groovy" 40 | - type : the type of plugin you want to generate, specify one of the values described above (for example "Action") 41 | 42 | You will be prompted to confirm your values, do that and a skeleton plugin will be generated. You can build the 43 | plugin by simply changing to the generated plugin directory and running 44 | 45 | ``` 46 | mvn install 47 | ``` 48 | 49 | This will generate a plugin jar file in the target folder of your project. If you want to install the plugin in ReadyAPI 50 | simply open the open the Plugin Manager from the main toolbar and choose to load a plugin from file (if you get a complaint about the version being invalid go into the generate PluginConfig class and change the version attribute of the PluginConfiguration sannotation to a valid value, for example "1.0.0" - and rebuild the plugin). 51 | 52 | Good Luck! 53 | 54 | Release History 55 | --------------- 56 | 57 | - 20141024 : initial release - groovy support is lacking. 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ready-api-plugins 7 | com.smartbear 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | ready-api-maven-archetype 13 | 14 | maven-archetype 15 | 16 | Ready! API Plugin Maven Archetype 17 | 18 | 19 | 20 | 21 | org.apache.maven.archetype 22 | archetype-packaging 23 | 2.2 24 | 25 | 26 | 27 | 28 | 29 | 30 | maven-archetype-plugin 31 | 2.2 32 | 33 | 34 | org.apache.maven.plugins 35 | maven-install-plugin 36 | ${maven-install-plugin.version} 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-deploy-plugin 41 | ${maven-deploy-plugin.version} 42 | 43 | 44 | org.apache.maven.plugins 45 | maven-resources-plugin 46 | ${maven-resources-plugin.version} 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | src/main/__language__ 14 | 15 | **/*.* 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/archetype-resources/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | Ready! API ${type} Plugin 6 | ${artifactId} 7 | ${groupId} 8 | 9 | 10 | 11 | eviware 12 | SmartBear Software Maven2 Repository 13 | http://smartbearsoftware.com/repository/maven2 14 | 15 | 16 | central 17 | Central Maven2 Repository 18 | http://repo1.maven.org/maven2 19 | 20 | 21 | 22 | ${version} 23 | 24 | 25 | 26 | org.codehaus.gmaven.runtime 27 | gmaven-runtime-1.8 28 | 1.5 29 | 30 | 31 | com.smartbear 32 | ready-api-soapui-pro 33 | 1.0.0 34 | 35 | 36 | 37 | 38 | src/main/${language} 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-compiler-plugin 44 | ${maven-compiler-plugin.version} 45 | 46 | 1.8 47 | 1.8 48 | groovy-eclipse-compiler 49 | 50 | 51 | 52 | org.codehaus.groovy 53 | groovy-eclipse-compiler 54 | 2.8.0-01 55 | 56 | 57 | org.codehaus.groovy 58 | groovy-eclipse-batch 59 | 2.1.8-01 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/archetype-resources/src/main/__language__/ActionGroups.__language__: -------------------------------------------------------------------------------- 1 | #set( $symbol_pound = '#' ) 2 | #set( $symbol_dollar = '$' ) 3 | #set( $symbol_escape = '\' ) 4 | package ${package}; 5 | #parse( "common/ActionGroups.txt" ) 6 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/archetype-resources/src/main/__language__/My__type__.__language__: -------------------------------------------------------------------------------- 1 | #set( $symbol_pound = '#' ) 2 | #set( $symbol_dollar = '$' ) 3 | #set( $symbol_escape = '\' ) 4 | #set($file = "${language}/${type}.inc" ) 5 | #parse( $file ) 6 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/archetype-resources/src/main/__language__/PluginConfig.__language__: -------------------------------------------------------------------------------- 1 | #set( $symbol_pound = '#' ) 2 | #set( $symbol_dollar = '$' ) 3 | #set( $symbol_escape = '\' ) 4 | package ${package}; 5 | 6 | import com.eviware.soapui.plugins.PluginAdapter; 7 | import com.eviware.soapui.plugins.PluginConfiguration; 8 | 9 | @PluginConfiguration(groupId = "${groupId}.plugins", name = "${artifactId} SoapUI ${type}", version = "0.1", 10 | autoDetect = true, description = "${artifactId} SoapUI ${type}", 11 | infoUrl = "" ) 12 | public class PluginConfig extends PluginAdapter { 13 | } 14 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/common/ActionGroups.txt: -------------------------------------------------------------------------------- 1 | public class ActionGroups { 2 | 3 | /* 4 | * Actions applied to the workspace. They will also be inserted into the File menu of SoapUI. 5 | * Have your action class extend AbstractSoapUIAction. 6 | */ 7 | public static final String WORKSPACE_ACTIONS = "WorkspaceImplActions"; 8 | 9 | /* 10 | * Actions applied to all projects, regardless of the state (enabled, disabled; closed or opened; encrypted or not. 11 | * Have your action class extend AbstractSoapUIAction. 12 | */ 13 | public static final String PROJECT_ACTIONS = "WsdlProjectActions"; 14 | 15 | /* 16 | * Actions applied to opened projects. If you're writing a project level action, this is usually the action group 17 | * you want it in. 18 | * 19 | * Have your action class extend AbstractSoapUIAction. 20 | */ 21 | public static final String OPEN_PROJECT_ACTIONS = "EnabledWsdlProjectActions"; 22 | 23 | /* 24 | * Actions applied to opened composite projects. If you're writing a project level action that applies to composite 25 | * projects, you usually want to include this action group, e.g. by using the @ActionConfigurations annotation. 26 | * 27 | * Have your action class extend AbstractSoapUIAction. 28 | */ 29 | public static final String OPEN_COMPOSITE_PROJECT_ACTIONS = "CompositeWsdlProjectActions"; 30 | 31 | /* 32 | * Actions applied to closed projects. 33 | * 34 | * Have your action class extend AbstractSoapUIAction. 35 | */ 36 | public static final String CLOSED_PROJECT_ACTIONS = "ClosedWsdlProjectActions"; 37 | 38 | /* 39 | * Actions applied to encrypted projects. 40 | * Have your action class extend AbstractSoapUIAction. 41 | */ 42 | public static final String ENCRYPTED_PROJECT_ACTIONS = "EncryptedWsdlProjectActions"; 43 | 44 | /* 45 | * Actions applied to both SOAP and REST services. 46 | * Have your action class extend AbstractSoapUIAction. 47 | */ 48 | public static final String INTERFACE_ACTIONS = "WsdlInterfaceActions"; 49 | 50 | /* 51 | * Actions applied only to REST services. 52 | * Have your action class extend AbstractSoapUIAction. 53 | */ 54 | public static final String REST_SERVICE_ACTIONS = "RestServiceActions"; 55 | 56 | /* 57 | * Actions applied to SOAP services. 58 | * Have your action class extend AbstractSoapUIAction. 59 | */ 60 | public static final String REST_RESOURCE_ACTIONS = "RestResourceActions"; 61 | 62 | /* 63 | * Actions applied only to REST method nodes, i.e. the level below the REST resource, most often named GET or POST. 64 | * Have your action class extend AbstractSoapUIAction. 65 | */ 66 | public static final String REST_METHOD_ACTIONS = "RestMethodActions"; 67 | 68 | /* 69 | * Actions applied to REST requests. 70 | * Have your action class extend AbstractSoapUIAction. 71 | */ 72 | public static final String REST_REQUEST_ACTIONS = "RestMethodActions"; 73 | 74 | /* 75 | * Actions applied to SOAP operations. 76 | * Have your action class extend AbstractSoapUIAction. 77 | */ 78 | public static final String SOAP_OPERATION_ACTIONS = "WsdlOperationActions"; 79 | 80 | /* 81 | * Actions applied to SOAP operations. 82 | * Have your action class extend AbstractSoapUIAction. 83 | */ 84 | public static final String SOAP_REQUEST_ACTIONS = "WsdlRequestActions"; 85 | 86 | /* 87 | * Actions applied to test suites. 88 | * Have your action class extend AbstractSoapUIAction. 89 | */ 90 | public static final String TEST_SUITE_ACTIONS = "WsdlTestSuiteActions"; 91 | 92 | /* 93 | * Actions applied to test cases. 94 | * Have your action class extend AbstractSoapUIAction. 95 | */ 96 | public static final String TEST_CASE_ACTIONS = "WsdlTestSuiteActions"; 97 | 98 | /* 99 | * Actions applied to all test steps. 100 | * Have your action class extend AbstractSoapUIAction. 101 | */ 102 | public static final String TEST_STEP_ACTIONS = "WsdlTestStepActions"; 103 | 104 | /* 105 | * Actions applied only to REST requests test steps. 106 | * Have your action class extend AbstractSoapUIAction. 107 | */ 108 | public static final String REST_TEST_REQUEST_ACTIONS = "RestTestRequestStepActions"; 109 | 110 | /* 111 | * Actions applied to SOAP operations. 112 | * Have your action class extend AbstractSoapUIAction. 113 | */ 114 | public static final String SOAP_TEST_REQUEST_ACTIONS = "WsdlTestRequestStepActions"; 115 | 116 | /* 117 | * Actions applied to assertions. 118 | * Have your action class extend AbstractSoapUIAction. 119 | */ 120 | public static final String ASSERTION_ACTIONS = "WsdlMessageAssertionActions"; 121 | 122 | 123 | 124 | } -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/Action.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.SoapUI; 4 | import com.eviware.soapui.impl.wsdl.WsdlProject; 5 | import com.eviware.soapui.plugins.ActionConfiguration; 6 | import com.eviware.soapui.support.UISupport; 7 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction; 8 | 9 | import javax.swing.*; 10 | 11 | @ActionConfiguration(actionGroup = ActionGroups.OPEN_PROJECT_ACTIONS) 12 | public class My${type} extends AbstractSoapUIAction { 13 | 14 | public My${type}() { 15 | super("My Action", "My plugin action at the project level"); 16 | } 17 | 18 | @Override 19 | public void perform(WsdlProject wsdlProject, Object o) { 20 | UISupport.showInfoMessage("Hello from [" + wsdlProject.getName() + "]!"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/Assertion.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.config.TestAssertionConfig; 4 | import com.eviware.soapui.impl.wsdl.panels.assertions.AssertionCategoryMapping; 5 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlMessageAssertion; 6 | import com.eviware.soapui.model.TestPropertyHolder; 7 | import com.eviware.soapui.model.iface.MessageExchange; 8 | import com.eviware.soapui.model.iface.SubmitContext; 9 | import com.eviware.soapui.model.testsuite.Assertable; 10 | import com.eviware.soapui.model.testsuite.AssertionError; 11 | import com.eviware.soapui.model.testsuite.AssertionException; 12 | import com.eviware.soapui.model.testsuite.ResponseAssertion; 13 | import com.eviware.soapui.plugins.auto.PluginTestAssertion; 14 | import com.eviware.soapui.support.StringUtils; 15 | import net.sf.json.JSONSerializer; 16 | 17 | @PluginTestAssertion(id = "MyTestAssertionId", label = "My JSON Content Assertion", 18 | category = AssertionCategoryMapping.VALIDATE_RESPONSE_CONTENT_CATEGORY, 19 | description = "Asserts that the response message is a valid JSON string") 20 | public class My${type} extends WsdlMessageAssertion implements ResponseAssertion { 21 | /** 22 | * Assertions need to have a constructor that takes a TestAssertionConfig and the ModelItem to be asserted 23 | */ 24 | 25 | public My${type}(TestAssertionConfig assertionConfig, Assertable modelItem) { 26 | super(assertionConfig, modelItem, true, false, false, true); 27 | } 28 | 29 | @Override 30 | protected String internalAssertResponse(MessageExchange messageExchange, SubmitContext submitContext) throws AssertionException { 31 | 32 | try { 33 | String content = messageExchange.getResponse().getContentAsString(); 34 | if (StringUtils.isNullOrEmpty(content)) { 35 | return "Response is empty - not a valid JSON response"; 36 | } 37 | 38 | JSONSerializer.toJSON(messageExchange.getResponse().getContentAsString()); 39 | } catch (Exception e) { 40 | throw new AssertionException(new AssertionError("JSON Parsing failed; [" + e.toString() + "]")); 41 | } 42 | 43 | return "Response is valid JSON"; 44 | } 45 | 46 | @Override 47 | protected String internalAssertRequest(MessageExchange messageExchange, SubmitContext context) throws AssertionException { 48 | return null; 49 | } 50 | 51 | @Override 52 | protected String internalAssertProperty(TestPropertyHolder source, String propertyName, MessageExchange messageExchange, SubmitContext context) throws AssertionException { 53 | return null; 54 | } 55 | 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/Discovery.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.actions.DiscoveryMethod; 4 | import com.eviware.soapui.impl.rest.discovery.DiscoveredRequest; 5 | import com.eviware.soapui.model.workspace.Workspace; 6 | import com.eviware.soapui.plugins.auto.PluginDiscoveryMethod; 7 | import com.eviware.soapui.support.UISupport; 8 | 9 | import java.util.List; 10 | 11 | @PluginDiscoveryMethod 12 | public class My${type} implements DiscoveryMethod { 13 | @Override 14 | public boolean isSynchronous() { 15 | return false; 16 | } 17 | 18 | @Override 19 | public void discoverResources(Workspace workspace) { 20 | UISupport.showInfoMessage("Nothing discovered!"); 21 | } 22 | 23 | @Override 24 | public List discoverResourcesSynchronously(Workspace workspace) { 25 | return null; 26 | } 27 | 28 | @Override 29 | public String getLabel() { 30 | return "Plugin Discovery!"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/Import.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.WorkspaceImpl; 4 | import com.eviware.soapui.plugins.auto.PluginImportMethod; 5 | import com.eviware.soapui.support.UISupport; 6 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction; 7 | 8 | @PluginImportMethod(label = "Sample Importer") 9 | public class My${type} extends AbstractSoapUIAction { 10 | public My${type}() { 11 | super("MyImportMethod", "My importer", "My importer description"); 12 | } 13 | 14 | @Override 15 | public void perform(WorkspaceImpl target, Object param) { 16 | UISupport.showInfoMessage("Importing..."); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/Listener.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.SoapUI; 4 | import com.eviware.soapui.model.support.TestRunListenerAdapter; 5 | import com.eviware.soapui.model.testsuite.TestCaseRunContext; 6 | import com.eviware.soapui.model.testsuite.TestCaseRunner; 7 | import com.eviware.soapui.plugins.ListenerConfiguration; 8 | 9 | @ListenerConfiguration 10 | public class My${type} extends TestRunListenerAdapter { 11 | 12 | @Override 13 | public void beforeRun(TestCaseRunner testRunner, TestCaseRunContext runContext) { 14 | SoapUI.log("Test " + testRunner.getTestCase().getName() + " starting..."); 15 | } 16 | 17 | @Override 18 | public void afterRun(TestCaseRunner testRunner, TestCaseRunContext runContext) { 19 | SoapUI.log("Test " + testRunner.getTestCase().getName() + " stopping..."); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/Panelbuilder.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.EmptyPanelBuilder; 4 | import com.eviware.soapui.plugins.auto.PluginPanelBuilder; 5 | 6 | /** 7 | * Created by ole on 18/06/14. 8 | */ 9 | @PluginPanelBuilder(targetModelItem = MyTestStep.class) 10 | public class My${type} extends EmptyPanelBuilder { 11 | } 12 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/Prefs.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.actions.Prefs; 4 | import com.eviware.soapui.model.settings.Settings; 5 | import com.eviware.soapui.plugins.auto.PluginPrefs; 6 | import com.eviware.soapui.support.components.SimpleForm; 7 | import com.eviware.soapui.support.types.StringToStringMap; 8 | 9 | @PluginPrefs 10 | public class My${type} implements Prefs { 11 | @Override 12 | public SimpleForm getForm() { 13 | return new SimpleForm(); 14 | } 15 | 16 | @Override 17 | public void setFormValues(Settings settings) { 18 | 19 | } 20 | 21 | @Override 22 | public void getFormValues(Settings settings) { 23 | 24 | } 25 | 26 | @Override 27 | public void storeValues(StringToStringMap values, Settings settings) { 28 | 29 | } 30 | 31 | @Override 32 | public StringToStringMap getValues(Settings settings) { 33 | return null; 34 | } 35 | 36 | @Override 37 | public String getTitle() { 38 | return "Plugin Prefs"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/RequestEditor.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginRequestEditorView; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.views.AbstractXmlEditorView; 7 | import com.eviware.soapui.support.editor.xml.XmlEditor; 8 | 9 | import javax.swing.JComponent; 10 | import javax.swing.JLabel; 11 | 12 | @PluginRequestEditorView(viewId = "MyEditorView") 13 | public class My${type} extends AbstractXmlEditorView { 14 | 15 | private ModelItem modelItem; 16 | 17 | public My${type}(Editor editor, ModelItem modelItem) { 18 | super("My Editor View", (XmlEditor) editor, "MyEditorView"); 19 | this.modelItem = modelItem; 20 | } 21 | 22 | @Override 23 | public JComponent getComponent() { 24 | return new JLabel(modelItem.getName()); 25 | } 26 | 27 | @Override 28 | public void setEditable(boolean enabled) { 29 | 30 | } 31 | 32 | @Override 33 | public boolean saveDocument(boolean validate) { 34 | return true; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/RequestFilter.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.support.AbstractHttpRequestInterface; 4 | import com.eviware.soapui.impl.wsdl.submit.filters.AbstractRequestFilter; 5 | import com.eviware.soapui.impl.wsdl.submit.transports.http.BaseHttpRequestTransport; 6 | import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse; 7 | import com.eviware.soapui.model.iface.SubmitContext; 8 | import com.eviware.soapui.plugins.auto.PluginRequestFilter; 9 | 10 | @PluginRequestFilter(protocol = "http") 11 | public class My${type} extends AbstractRequestFilter { 12 | @Override 13 | public void afterAbstractHttpResponse(SubmitContext context, AbstractHttpRequestInterface request) { 14 | HttpResponse response = (HttpResponse) context.getProperty(BaseHttpRequestTransport.RESPONSE); 15 | response.setProperty("Secret Message", "bu!"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/RequestInspector.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginRequestInspector; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.EditorView; 7 | import com.eviware.soapui.support.editor.inspectors.AbstractXmlInspector; 8 | import com.eviware.soapui.support.editor.xml.XmlDocument; 9 | 10 | import javax.swing.JComponent; 11 | import javax.swing.JLabel; 12 | 13 | @PluginRequestInspector(inspectorId = "MyRequestInspector") 14 | public class My${type} extends AbstractXmlInspector { 15 | private ModelItem modelItem; 16 | 17 | public My${type}(Editor editor, ModelItem modelItem) { 18 | super("My Request Inspector", "My request inspector", true, "MyRequestInspector"); 19 | this.modelItem = modelItem; 20 | } 21 | 22 | @Override 23 | public boolean isEnabledFor(EditorView view) { 24 | return true; 25 | } 26 | 27 | @Override 28 | public JComponent getComponent() { 29 | return new JLabel(modelItem.getName() + ": " + modelItem.getDescription()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/ResponseEditor.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginResponseEditorView; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.views.AbstractXmlEditorView; 7 | import com.eviware.soapui.support.editor.xml.XmlEditor; 8 | 9 | import javax.swing.JComponent; 10 | import javax.swing.JLabel; 11 | 12 | @PluginResponseEditorView(viewId = "MyResponseEditorView") 13 | public class My${type} extends AbstractXmlEditorView { 14 | 15 | private ModelItem modelItem; 16 | 17 | public My${type}(Editor editor, ModelItem modelItem) { 18 | super("Sample Response Editor View", (XmlEditor) editor, "MyResponseEditorView"); 19 | this.modelItem = modelItem; 20 | } 21 | 22 | @Override 23 | public JComponent getComponent() { 24 | return new JLabel(modelItem.getName()); 25 | } 26 | 27 | @Override 28 | public void setEditable(boolean enabled) { 29 | } 30 | 31 | @Override 32 | public boolean saveDocument(boolean validate) { 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/ResponseInspector.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginResponseInspector; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.EditorView; 7 | import com.eviware.soapui.support.editor.inspectors.AbstractXmlInspector; 8 | import com.eviware.soapui.support.editor.xml.XmlDocument; 9 | 10 | import javax.swing.JComponent; 11 | import javax.swing.JLabel; 12 | 13 | @PluginResponseInspector(inspectorId = "MyResponseInspector") 14 | public class My${type} extends AbstractXmlInspector { 15 | private ModelItem modelItem; 16 | 17 | public My${type}(Editor editor, ModelItem modelItem) { 18 | super("My Response Inspector", My response inspector", true, "MyResponseInspector"); 19 | this.modelItem = modelItem; 20 | } 21 | 22 | @Override 23 | public boolean isEnabledFor(EditorView view) { 24 | return true; 25 | } 26 | 27 | @Override 28 | public JComponent getComponent() { 29 | return new JLabel(modelItem.getName() + ": " + modelItem.getDescription()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/SubReport.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginSubReport; 5 | import com.eviware.soapui.reporting.reports.support.AbstractJasperSubReport; 6 | import net.sf.jasperreports.engine.JRDataSource; 7 | import net.sf.jasperreports.engine.JRException; 8 | import net.sf.jasperreports.engine.JRField; 9 | 10 | @PluginSubReport(name = "MySubReport", description = "My SubReport", id = "MySubReport", level = "COMMON") 11 | public class My${type} extends AbstractJasperSubReport { 12 | 13 | protected My${type}(ModelItem modelItem, String nameInReport, boolean cacheDataSource) { 14 | super(modelItem, nameInReport, cacheDataSource); 15 | } 16 | 17 | @Override 18 | public JRDataSource buildDataSource(ModelItem modelItem) { 19 | 20 | return new JRDataSource() { 21 | 22 | int cnt = 0; 23 | 24 | @Override 25 | public boolean next() throws JRException { 26 | 27 | return ++cnt < 5; 28 | } 29 | 30 | @Override 31 | public Object getFieldValue(JRField jrField) throws JRException { 32 | return jrField.getName() + " value " + cnt; 33 | } 34 | }; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/TestStep.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.SoapUI; 4 | import com.eviware.soapui.config.TestStepConfig; 5 | import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase; 6 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepResult; 7 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepWithProperties; 8 | import com.eviware.soapui.model.testsuite.TestCaseRunContext; 9 | import com.eviware.soapui.model.testsuite.TestCaseRunner; 10 | import com.eviware.soapui.model.testsuite.TestStepResult; 11 | import com.eviware.soapui.plugins.auto.PluginTestStep; 12 | 13 | @PluginTestStep(typeName = "MyTestStep", name = "My TestStep", description = "My TestStep") 14 | public class My${type} extends WsdlTestStepWithProperties { 15 | 16 | public My${type}(WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest) { 17 | super(testCase, config, false, forLoadTest); 18 | } 19 | 20 | @Override 21 | public TestStepResult run(TestCaseRunner testRunner, TestCaseRunContext testRunContext) { 22 | SoapUI.log("bu!"); 23 | WsdlTestStepResult result = new WsdlTestStepResult(this); 24 | result.addMessage("bu!"); 25 | return result; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/ToolbarAction.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.workspace.Workspace; 4 | import com.eviware.soapui.plugins.ActionConfiguration; 5 | import com.eviware.soapui.plugins.ToolbarPosition; 6 | import com.eviware.soapui.support.UISupport; 7 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction; 8 | 9 | @ActionConfiguration(actionGroup = "EnabledWsdlProjectActions", toolbarPosition = ToolbarPosition.FUNCTIONAL_TESTING, 10 | toolbarIcon = "/favicon.png", description = "Says Hello") 11 | public class My${type} extends AbstractSoapUIAction { 12 | 13 | public My${type}() { 14 | super("My Toolbar Action", "My toolbar action"); 15 | } 16 | 17 | @Override 18 | public void perform(Workspace workspace, Object o) { 19 | UISupport.showInfoMessage("Hello from toolbar action in workspace " + workspace.getName() + "!"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/Transport.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.wsdl.WsdlRequest; 4 | import com.eviware.soapui.impl.wsdl.submit.RequestFilter; 5 | import com.eviware.soapui.impl.wsdl.submit.RequestTransport; 6 | import com.eviware.soapui.impl.wsdl.submit.transports.http.SSLInfo; 7 | import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse; 8 | import com.eviware.soapui.model.iface.Request; 9 | import com.eviware.soapui.model.iface.Response; 10 | import com.eviware.soapui.model.iface.SubmitContext; 11 | import com.eviware.soapui.model.util.BaseResponse; 12 | import com.eviware.soapui.plugins.auto.PluginRequestTransport; 13 | import com.eviware.soapui.support.UISupport; 14 | 15 | import java.net.URL; 16 | 17 | @PluginRequestTransport(protocol = "echo") 18 | public class My${type} implements RequestTransport { 19 | @Override 20 | public void addRequestFilter(RequestFilter filter) { 21 | 22 | } 23 | 24 | @Override 25 | public void removeRequestFilter(RequestFilter filter) { 26 | 27 | } 28 | 29 | @Override 30 | public void abortRequest(SubmitContext submitContext) { 31 | 32 | } 33 | 34 | @Override 35 | public Response sendRequest(SubmitContext submitContext, final Request request) throws Exception { 36 | UISupport.getDialogs().showInfoMessage(request.getRequestContent()); 37 | return new MyResponse(request, request.getRequestContent(), "text/text"); 38 | } 39 | 40 | @Override 41 | public void insertRequestFilter(RequestFilter filter, RequestFilter refFilter) { 42 | 43 | } 44 | 45 | private static class MyResponse extends BaseResponse implements HttpResponse { 46 | private String responseContent; 47 | 48 | public MyResponse(Request request, String responseContent, String responseContentType) { 49 | super(request, responseContent, responseContentType); 50 | } 51 | 52 | @Override 53 | public void setResponseContent(String responseContent) { 54 | this.responseContent = responseContent; 55 | } 56 | 57 | @Override 58 | public String getContentAsString() { 59 | return responseContent == null ? super.getContentAsString() : responseContent; 60 | } 61 | 62 | @Override 63 | public Vector getWssResult() { 64 | return null; 65 | } 66 | 67 | @Override 68 | public WsdlRequest getRequest() { 69 | return (WsdlRequest) super.getRequest(); 70 | } 71 | 72 | @Override 73 | public SSLInfo getSSLInfo() { 74 | return null; 75 | } 76 | 77 | @Override 78 | public URL getURL() { 79 | return null; 80 | } 81 | 82 | @Override 83 | public String getMethod() { 84 | return "GET"; 85 | } 86 | 87 | @Override 88 | public String getHttpVersion() { 89 | return "1.0"; 90 | } 91 | 92 | @Override 93 | public int getStatusCode() { 94 | return 200; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/groovy/ValueProvider.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext; 4 | import com.eviware.soapui.model.propertyexpansion.resolvers.DynamicPropertyResolver; 5 | import com.eviware.soapui.plugins.auto.PluginValueProvider; 6 | 7 | @PluginValueProvider(valueName = "randomNumber") 8 | public class My${type} implements DynamicPropertyResolver.ValueProvider { 9 | @Override 10 | public String getValue(PropertyExpansionContext propertyExpansionContext) { 11 | return String.valueOf(1000 * Math.random()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/Action.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.SoapUI; 4 | import com.eviware.soapui.impl.wsdl.WsdlProject; 5 | import com.eviware.soapui.plugins.ActionConfiguration; 6 | import com.eviware.soapui.support.UISupport; 7 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction; 8 | 9 | import javax.swing.*; 10 | 11 | @ActionConfiguration(actionGroup = ActionGroups.OPEN_PROJECT_ACTIONS) 12 | public class My${type} extends AbstractSoapUIAction { 13 | 14 | public My${type}() { 15 | super("My Action", "A plugin action at the project level"); 16 | } 17 | 18 | @Override 19 | public void perform(WsdlProject wsdlProject, Object o) { 20 | UISupport.showInfoMessage("Hello from [" + wsdlProject.getName() + "]!"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/Assertion.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.config.TestAssertionConfig; 4 | import com.eviware.soapui.impl.wsdl.panels.assertions.AssertionCategoryMapping; 5 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlMessageAssertion; 6 | import com.eviware.soapui.model.TestPropertyHolder; 7 | import com.eviware.soapui.model.iface.MessageExchange; 8 | import com.eviware.soapui.model.iface.SubmitContext; 9 | import com.eviware.soapui.model.testsuite.Assertable; 10 | import com.eviware.soapui.model.testsuite.AssertionError; 11 | import com.eviware.soapui.model.testsuite.AssertionException; 12 | import com.eviware.soapui.model.testsuite.ResponseAssertion; 13 | import com.eviware.soapui.plugins.auto.PluginTestAssertion; 14 | import com.eviware.soapui.support.StringUtils; 15 | import net.sf.json.JSONSerializer; 16 | 17 | @PluginTestAssertion(id = "MyTestAssertionId", label = "My JSON Content Assertion", 18 | category = AssertionCategoryMapping.VALIDATE_RESPONSE_CONTENT_CATEGORY, 19 | description = "Asserts that the response message is a valid JSON string") 20 | public class My${type} extends WsdlMessageAssertion implements ResponseAssertion { 21 | /** 22 | * Assertions need to have a constructor that takes a TestAssertionConfig and the ModelItem to be asserted 23 | */ 24 | 25 | public My${type}(TestAssertionConfig assertionConfig, Assertable modelItem) { 26 | super(assertionConfig, modelItem, true, false, false, true); 27 | } 28 | 29 | @Override 30 | protected String internalAssertResponse(MessageExchange messageExchange, SubmitContext submitContext) throws AssertionException { 31 | 32 | try { 33 | String content = messageExchange.getResponse().getContentAsString(); 34 | if (StringUtils.isNullOrEmpty(content)) { 35 | return "Response is empty - not a valid JSON response"; 36 | } 37 | 38 | JSONSerializer.toJSON(messageExchange.getResponse().getContentAsString()); 39 | } catch (Exception e) { 40 | throw new AssertionException(new AssertionError("JSON Parsing failed; [" + e.toString() + "]")); 41 | } 42 | 43 | return "Response is valid JSON"; 44 | } 45 | 46 | @Override 47 | protected String internalAssertRequest(MessageExchange messageExchange, SubmitContext context) throws AssertionException { 48 | return null; 49 | } 50 | 51 | @Override 52 | protected String internalAssertProperty(TestPropertyHolder source, String propertyName, MessageExchange messageExchange, SubmitContext context) throws AssertionException { 53 | return null; 54 | } 55 | 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/Discovery.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.actions.DiscoveryMethod; 4 | import com.eviware.soapui.impl.rest.discovery.DiscoveredRequest; 5 | import com.eviware.soapui.model.workspace.Workspace; 6 | import com.eviware.soapui.plugins.auto.PluginDiscoveryMethod; 7 | import com.eviware.soapui.support.UISupport; 8 | 9 | import java.util.List; 10 | 11 | @PluginDiscoveryMethod 12 | public class My${type} implements DiscoveryMethod { 13 | @Override 14 | public boolean isSynchronous() { 15 | return false; 16 | } 17 | 18 | @Override 19 | public void discoverResources(Workspace workspace) { 20 | UISupport.showInfoMessage("Nothing discovered!"); 21 | } 22 | 23 | @Override 24 | public List discoverResourcesSynchronously(Workspace workspace) { 25 | return null; 26 | } 27 | 28 | @Override 29 | public String getLabel() { 30 | return "Plugin Discovery!"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/Import.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.WorkspaceImpl; 4 | import com.eviware.soapui.plugins.auto.PluginImportMethod; 5 | import com.eviware.soapui.support.UISupport; 6 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction; 7 | 8 | @PluginImportMethod(label = "Sample Importer") 9 | public class My${type} extends AbstractSoapUIAction { 10 | public My${type}() { 11 | super("MyImportMethod", "My importer", "My importer description"); 12 | } 13 | 14 | @Override 15 | public void perform(WorkspaceImpl target, Object param) { 16 | UISupport.showInfoMessage("Importing..."); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/Listener.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.SoapUI; 4 | import com.eviware.soapui.model.support.TestRunListenerAdapter; 5 | import com.eviware.soapui.model.testsuite.TestCaseRunContext; 6 | import com.eviware.soapui.model.testsuite.TestCaseRunner; 7 | import com.eviware.soapui.plugins.ListenerConfiguration; 8 | 9 | @ListenerConfiguration 10 | public class My${type} extends TestRunListenerAdapter { 11 | 12 | @Override 13 | public void beforeRun(TestCaseRunner testRunner, TestCaseRunContext runContext) { 14 | SoapUI.log("My Test " + testRunner.getTestCase().getName() + " starting..."); 15 | } 16 | 17 | @Override 18 | public void afterRun(TestCaseRunner testRunner, TestCaseRunContext runContext) { 19 | SoapUI.log("My Test " + testRunner.getTestCase().getName() + " stopping..."); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/PanelBuilder.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.EmptyPanelBuilder; 4 | import com.eviware.soapui.plugins.auto.PluginPanelBuilder; 5 | 6 | @PluginPanelBuilder(targetModelItem = MyTestStep.class) 7 | public class My${type} extends EmptyPanelBuilder { 8 | } 9 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/Prefs.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.actions.Prefs; 4 | import com.eviware.soapui.model.settings.Settings; 5 | import com.eviware.soapui.plugins.auto.PluginPrefs; 6 | import com.eviware.soapui.support.components.SimpleForm; 7 | import com.eviware.soapui.support.types.StringToStringMap; 8 | 9 | @PluginPrefs 10 | public class My${type} implements Prefs { 11 | @Override 12 | public SimpleForm getForm() { 13 | return new SimpleForm(); 14 | } 15 | 16 | @Override 17 | public void setFormValues(Settings settings) { 18 | 19 | } 20 | 21 | @Override 22 | public void getFormValues(Settings settings) { 23 | 24 | } 25 | 26 | @Override 27 | public void storeValues(StringToStringMap values, Settings settings) { 28 | 29 | } 30 | 31 | @Override 32 | public StringToStringMap getValues(Settings settings) { 33 | return null; 34 | } 35 | 36 | @Override 37 | public String getTitle() { 38 | return "My Plugin Prefs"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/RequestEditor.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginRequestEditorView; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.views.AbstractXmlEditorView; 7 | import com.eviware.soapui.support.editor.xml.XmlEditor; 8 | 9 | import javax.swing.JComponent; 10 | import javax.swing.JLabel; 11 | 12 | @PluginRequestEditorView(viewId = "PluginEditorView") 13 | public class My${type} extends AbstractXmlEditorView { 14 | 15 | private ModelItem modelItem; 16 | 17 | public My${type}(Editor editor, ModelItem modelItem) { 18 | super("My Editor View", (XmlEditor) editor, "MyEditorView"); 19 | this.modelItem = modelItem; 20 | } 21 | 22 | @Override 23 | public JComponent getComponent() { 24 | return new JLabel(modelItem.getName()); 25 | } 26 | 27 | @Override 28 | public void setEditable(boolean enabled) { 29 | 30 | } 31 | 32 | @Override 33 | public boolean saveDocument(boolean validate) { 34 | return true; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/RequestFilter.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.support.AbstractHttpRequestInterface; 4 | import com.eviware.soapui.impl.wsdl.submit.filters.AbstractRequestFilter; 5 | import com.eviware.soapui.impl.wsdl.submit.transports.http.BaseHttpRequestTransport; 6 | import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse; 7 | import com.eviware.soapui.model.iface.SubmitContext; 8 | import com.eviware.soapui.plugins.auto.PluginRequestFilter; 9 | 10 | @PluginRequestFilter(protocol = "http") 11 | public class My${type} extends AbstractRequestFilter { 12 | @Override 13 | public void afterAbstractHttpResponse(SubmitContext context, AbstractHttpRequestInterface request) { 14 | HttpResponse response = (HttpResponse) context.getProperty(BaseHttpRequestTransport.RESPONSE); 15 | response.setProperty("Secret Message", "bu!"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/RequestInspector.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginRequestInspector; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.EditorView; 7 | import com.eviware.soapui.support.editor.inspectors.AbstractXmlInspector; 8 | import com.eviware.soapui.support.editor.xml.XmlDocument; 9 | 10 | import javax.swing.JComponent; 11 | import javax.swing.JLabel; 12 | 13 | @PluginRequestInspector(inspectorId = "MyRequestInspector") 14 | public class My${type} extends AbstractXmlInspector { 15 | private ModelItem modelItem; 16 | 17 | public My${type}(Editor editor, ModelItem modelItem) { 18 | super("My Request Inspector", "My request inspector", true, "MyRequestInspector"); 19 | this.modelItem = modelItem; 20 | } 21 | 22 | @Override 23 | public boolean isEnabledFor(EditorView view) { 24 | return true; 25 | } 26 | 27 | @Override 28 | public JComponent getComponent() { 29 | return new JLabel(modelItem.getName() + ": " + modelItem.getDescription()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/ResponseEditor.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginResponseEditorView; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.views.AbstractXmlEditorView; 7 | import com.eviware.soapui.support.editor.xml.XmlEditor; 8 | 9 | import javax.swing.JComponent; 10 | import javax.swing.JLabel; 11 | 12 | @PluginResponseEditorView(viewId = "MyResponseEditorView") 13 | public class My${type} extends AbstractXmlEditorView { 14 | 15 | private ModelItem modelItem; 16 | 17 | public My${type}(Editor editor, ModelItem modelItem) { 18 | super("My Response Editor View", (XmlEditor) editor, "MyResponseEditorView"); 19 | this.modelItem = modelItem; 20 | } 21 | 22 | @Override 23 | public JComponent getComponent() { 24 | return new JLabel(modelItem.getName()); 25 | } 26 | 27 | @Override 28 | public void setEditable(boolean enabled) { 29 | } 30 | 31 | @Override 32 | public boolean saveDocument(boolean validate) { 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/ResponseInspector.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginResponseInspector; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.EditorView; 7 | import com.eviware.soapui.support.editor.inspectors.AbstractXmlInspector; 8 | import com.eviware.soapui.support.editor.xml.XmlDocument; 9 | 10 | import javax.swing.JComponent; 11 | import javax.swing.JLabel; 12 | 13 | @PluginResponseInspector(inspectorId = "MyResponseInspector") 14 | public class My${type} extends AbstractXmlInspector { 15 | private ModelItem modelItem; 16 | 17 | public My${type}(Editor editor, ModelItem modelItem) { 18 | super("My Response Inspector", "My Response Inspector", true, "MyResponseInspector"); 19 | this.modelItem = modelItem; 20 | } 21 | 22 | @Override 23 | public boolean isEnabledFor(EditorView view) { 24 | return true; 25 | } 26 | 27 | @Override 28 | public JComponent getComponent() { 29 | return new JLabel(modelItem.getName() + ": " + modelItem.getDescription()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/SubReport.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginSubReport; 5 | import com.eviware.soapui.reporting.reports.support.AbstractJasperSubReport; 6 | import net.sf.jasperreports.engine.JRDataSource; 7 | import net.sf.jasperreports.engine.JRException; 8 | import net.sf.jasperreports.engine.JRField; 9 | 10 | @PluginSubReport(name = "MySubReport", description = "My SubReport", id = "MySubReport", level = "COMMON") 11 | public class My${type} extends AbstractJasperSubReport { 12 | 13 | protected My${type}(ModelItem modelItem, String nameInReport, boolean cacheDataSource) { 14 | super(modelItem, nameInReport, cacheDataSource); 15 | } 16 | 17 | @Override 18 | public JRDataSource buildDataSource(ModelItem modelItem) { 19 | 20 | return new JRDataSource() { 21 | 22 | int cnt = 0; 23 | 24 | @Override 25 | public boolean next() throws JRException { 26 | 27 | return ++cnt < 5; 28 | } 29 | 30 | @Override 31 | public Object getFieldValue(JRField jrField) throws JRException { 32 | return jrField.getName() + " value " + cnt; 33 | } 34 | }; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/TestStep.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.SoapUI; 4 | import com.eviware.soapui.config.TestStepConfig; 5 | import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase; 6 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepResult; 7 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepWithProperties; 8 | import com.eviware.soapui.model.testsuite.TestCaseRunContext; 9 | import com.eviware.soapui.model.testsuite.TestCaseRunner; 10 | import com.eviware.soapui.model.testsuite.TestStepResult; 11 | import com.eviware.soapui.plugins.auto.PluginTestStep; 12 | 13 | @PluginTestStep(typeName = "MyTestStep", name = "My TestStep", description = "My immensely cool and useful TestStep") 14 | public class My${type} extends WsdlTestStepWithProperties { 15 | 16 | public My${type}(WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest) { 17 | super(testCase, config, false, forLoadTest); 18 | } 19 | 20 | @Override 21 | public TestStepResult run(TestCaseRunner testRunner, TestCaseRunContext testRunContext) { 22 | SoapUI.log("bu!"); 23 | WsdlTestStepResult result = new WsdlTestStepResult(this); 24 | result.addMessage("bu!"); 25 | return result; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/ToolbarAction.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.workspace.Workspace; 4 | import com.eviware.soapui.plugins.ActionConfiguration; 5 | import com.eviware.soapui.plugins.ToolbarPosition; 6 | import com.eviware.soapui.support.UISupport; 7 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction; 8 | 9 | @ActionConfiguration(actionGroup = "EnabledWsdlProjectActions", toolbarPosition = ToolbarPosition.FUNCTIONAL_TESTING, 10 | toolbarIcon = "/favicon.png", description = "Says Hello") 11 | public class My${type} extends AbstractSoapUIAction { 12 | 13 | public My${type}() { 14 | super("My Plugin Toolbar Action", "A sample Toolbar action"); 15 | super("My Plugin Toolbar Action", "A sample Toolbar action"); 16 | } 17 | 18 | @Override 19 | public void perform(Workspace workspace, Object o) { 20 | UISupport.showInfoMessage("Hello from toolbar action in workspace " + workspace.getName() + "!"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/Transport.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.impl.wsdl.WsdlRequest; 4 | import com.eviware.soapui.impl.wsdl.submit.RequestFilter; 5 | import com.eviware.soapui.impl.wsdl.submit.RequestTransport; 6 | import com.eviware.soapui.impl.wsdl.submit.transports.http.SSLInfo; 7 | import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse; 8 | import com.eviware.soapui.model.iface.Request; 9 | import com.eviware.soapui.model.iface.Response; 10 | import com.eviware.soapui.model.iface.SubmitContext; 11 | import com.eviware.soapui.model.util.BaseResponse; 12 | import com.eviware.soapui.plugins.auto.PluginRequestTransport; 13 | import com.eviware.soapui.support.UISupport; 14 | 15 | import java.net.URL; 16 | 17 | @PluginRequestTransport(protocol = "echo") 18 | public class My${type} implements RequestTransport { 19 | @Override 20 | public void addRequestFilter(RequestFilter filter) { 21 | 22 | } 23 | 24 | @Override 25 | public void removeRequestFilter(RequestFilter filter) { 26 | 27 | } 28 | 29 | @Override 30 | public void abortRequest(SubmitContext submitContext) { 31 | 32 | } 33 | 34 | @Override 35 | public Response sendRequest(SubmitContext submitContext, final Request request) throws Exception { 36 | UISupport.getDialogs().showInfoMessage(request.getRequestContent()); 37 | return new MyResponse(request, request.getRequestContent(), "text/text"); 38 | } 39 | 40 | @Override 41 | public void insertRequestFilter(RequestFilter filter, RequestFilter refFilter) { 42 | 43 | } 44 | 45 | private static class MyResponse extends BaseResponse implements WsdlResponse { 46 | private String responseContent; 47 | 48 | public MyResponse(Request request, String responseContent, String responseContentType) { 49 | super(request, responseContent, responseContentType); 50 | } 51 | 52 | @Override 53 | public void setResponseContent(String responseContent) { 54 | this.responseContent = responseContent; 55 | } 56 | 57 | @Override 58 | public String getContentAsString() { 59 | return responseContent == null ? super.getContentAsString() : responseContent; 60 | } 61 | 62 | @Override 63 | public Vector getWssResult() { 64 | return null; 65 | } 66 | 67 | @Override 68 | public WsdlRequest getRequest() { 69 | return (WsdlRequest) super.getRequest(); 70 | } 71 | 72 | @Override 73 | public SSLInfo getSSLInfo() { 74 | return null; 75 | } 76 | 77 | @Override 78 | public URL getURL() { 79 | return null; 80 | } 81 | 82 | @Override 83 | public String getMethod() { 84 | return "GET"; 85 | } 86 | 87 | @Override 88 | public String getHttpVersion() { 89 | return "1.0"; 90 | } 91 | 92 | @Override 93 | public int getStatusCode() { 94 | return 200; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ready-api-plugin-archetype/src/main/resources/java/ValueProvider.inc: -------------------------------------------------------------------------------- 1 | package ${package}; 2 | 3 | import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext; 4 | import com.eviware.soapui.model.propertyexpansion.resolvers.DynamicPropertyResolver; 5 | import com.eviware.soapui.plugins.auto.PluginValueProvider; 6 | 7 | @PluginValueProvider(valueName = "randomNumber") 8 | public class My${type} implements DynamicPropertyResolver.ValueProvider { 9 | @Override 10 | public String getValue(PropertyExpansionContext propertyExpansionContext) { 11 | return String.valueOf(1000 * Math.random()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ready-api-plugin-template-test/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | ready-api-plugins 9 | com.smartbear 10 | 1.0-SNAPSHOT 11 | 12 | 13 | Ready! API Plugin Template Test 14 | ready-api-plugin-template-test 15 | pom 16 | 17 | 18 | src/test/java 19 | 20 | 21 | -------------------------------------------------------------------------------- /ready-api-plugin-template-test/src/test/java/com/smartbear/ready/template/TestPluginTemplate.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.soapui.plugins; 2 | 3 | import com.eviware.soapui.SoapUIProCore; 4 | import com.eviware.soapui.actions.SoapUIPreferencesAction; 5 | import com.eviware.soapui.impl.wsdl.WsdlProject; 6 | import com.eviware.soapui.impl.wsdl.WsdlProjectPro; 7 | import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase; 8 | import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner; 9 | import com.eviware.soapui.impl.wsdl.teststeps.HttpTestRequestStep; 10 | import com.eviware.soapui.impl.wsdl.teststeps.RestRequestStepResult; 11 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep; 12 | import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionFactory; 13 | import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry; 14 | import com.eviware.soapui.impl.wsdl.teststeps.registry.HttpRequestStepFactory; 15 | import com.eviware.soapui.impl.wsdl.teststeps.registry.WsdlTestStepRegistry; 16 | import com.eviware.soapui.model.PanelBuilder; 17 | import com.eviware.soapui.model.propertyexpansion.PropertyExpander; 18 | import com.eviware.soapui.model.testsuite.TestRunner; 19 | import com.eviware.soapui.model.util.PanelBuilderRegistry; 20 | import com.eviware.soapui.plugins.Plugin; 21 | import com.eviware.soapui.reporting.SubReportFactoryRegistry; 22 | import com.eviware.soapui.support.SoapUIException; 23 | import com.eviware.soapui.support.action.SoapUIActionRegistry; 24 | import com.eviware.soapui.support.editor.registry.EditorViewFactory; 25 | import com.eviware.soapui.support.editor.registry.EditorViewFactoryRegistry; 26 | import com.eviware.soapui.support.editor.registry.InspectorFactory; 27 | import com.eviware.soapui.support.editor.registry.InspectorRegistry; 28 | import com.eviware.soapui.support.editor.registry.RequestEditorViewFactory; 29 | import com.eviware.soapui.support.editor.registry.RequestInspectorFactory; 30 | import com.eviware.soapui.support.editor.registry.ResponseEditorViewFactory; 31 | import com.eviware.soapui.support.editor.registry.ResponseInspectorFactory; 32 | import com.google.inject.Guice; 33 | import com.smartbear.ready.core.ApplicationEnvironment; 34 | import com.smartbear.ready.core.ReadyApiCoreModule; 35 | import com.smartbear.ready.db.DbModule; 36 | import com.smartbear.ready.license.LicenseInitializerModule; 37 | import org.apache.xmlbeans.XmlException; 38 | import org.hamcrest.Description; 39 | import org.hamcrest.Matcher; 40 | import org.hamcrest.TypeSafeMatcher; 41 | import org.junit.jupiter.api.AfterAll; 42 | import org.junit.jupiter.api.BeforeAll; 43 | import org.junit.jupiter.api.Test; 44 | 45 | import java.io.File; 46 | import java.io.IOException; 47 | import java.net.URISyntaxException; 48 | import java.util.Map; 49 | 50 | import static com.eviware.soapui.support.SoapUITools.createTemporaryDirectory; 51 | import static com.smartbear.ready.core.ReadyApiPaths.absolutePath; 52 | import static com.smartbear.ready.core.ReadyApiPaths.readyApiHomeDir; 53 | import static org.hamcrest.CoreMatchers.is; 54 | import static org.hamcrest.CoreMatchers.not; 55 | import static org.hamcrest.CoreMatchers.notNullValue; 56 | import static org.hamcrest.CoreMatchers.nullValue; 57 | import static org.hamcrest.MatcherAssert.assertThat; 58 | import static org.hamcrest.collection.IsArrayContaining.hasItemInArray; 59 | import static org.junit.jupiter.api.Assertions.assertEquals; 60 | import static org.junit.jupiter.api.Assertions.assertNotNull; 61 | import static org.junit.jupiter.api.Assertions.assertNull; 62 | 63 | // RIA-22336 This class needs to be fixed and probably moved elsewhere. 64 | class TestPluginTemplate { 65 | 66 | private static WsdlTestCase testCase; 67 | private static String originalSoapUIHome; 68 | private static Plugin plugin; 69 | private static SoapUIProCore soapUIProCore; 70 | 71 | @BeforeAll 72 | public static void initializeSoapUICoreAndInstallPlugin() throws IOException, URISyntaxException { 73 | setupPluginDirectory(); 74 | initializeCore(); 75 | 76 | File baseSoapUIProDirectory = new File(TestPluginTemplate.class.getResource("/").toURI()).getParentFile(). 77 | getParentFile().getParentFile(); 78 | File pluginTemplateJarFile = new File(baseSoapUIProDirectory, 79 | "ready-api-plugin-template/target/ready-api-plugin-template-1.0.jar"); 80 | if (!pluginTemplateJarFile.exists()) { 81 | throw new Error("Plugin JAR " + pluginTemplateJarFile.getAbsolutePath() + " not found"); 82 | } 83 | 84 | plugin = soapUIProCore.getPluginManager().installPlugin(pluginTemplateJarFile); 85 | } 86 | 87 | @AfterAll 88 | public static void restoreSoapUIHome() { 89 | if (originalSoapUIHome != null) { 90 | System.setProperty("soapui.home", originalSoapUIHome); 91 | } 92 | } 93 | 94 | @Test 95 | void installsPluginFunctionality() throws Exception { 96 | verifyFunctionalityInstalled(plugin); 97 | } 98 | 99 | @Test 100 | void uninstallsPluginFunctionality() throws Exception { 101 | soapUIProCore.getPluginManager().uninstallPlugin(plugin); 102 | verifyFunctionalityUninstalled(); 103 | } 104 | 105 | /* 106 | Helper methods. 107 | */ 108 | 109 | private static void setupPluginDirectory() throws IOException { 110 | File fakeSoapUIHome = createTemporaryDirectory(); 111 | originalSoapUIHome = absolutePath(readyApiHomeDir()); 112 | System.setProperty("soapui.home", fakeSoapUIHome.getAbsolutePath()); 113 | File pluginDirectory = new File(fakeSoapUIHome, "plugins"); 114 | if (!pluginDirectory.mkdir()) { 115 | throw new Error("Couldn't create plugins directory!"); 116 | } 117 | } 118 | 119 | private static void initializeCore() { 120 | ApplicationEnvironment.setSoapUICore(new SoapUIProCore(Guice.createInjector(new LicenseInitializerModule(), new DbModule()), true, null, null)); 121 | soapUIProCore = SoapUIProCore.getInstance(); 122 | SoapUIPreferencesAction.getInstance(); 123 | } 124 | 125 | private void verifyFunctionalityInstalled(Plugin plugin) throws XmlException, IOException, SoapUIException { 126 | assertThat(plugin.getInfo().getId().getName(), is(ReadyApiCoreModule.READY_API_NAME + " Plugin Template")); 127 | 128 | WsdlProject project = new WsdlProjectPro(); 129 | testCase = project.addNewTestSuite("TestSuite").addNewTestCase("TestCase"); 130 | 131 | WsdlTestStep sampleTestStep = testCase.addTestStep("SampleTestStep", "My TestStep"); 132 | assertThat(sampleTestStep.getClass().getSimpleName(), is("SampleTestStep")); 133 | 134 | WsdlTestStep sampleGroovyTestStep = testCase.addTestStep("SampleGroovyTestStep", "My TestStep"); 135 | assertThat(sampleGroovyTestStep.getClass().getSimpleName(), is("SampleGroovyTestStep")); 136 | 137 | HttpTestRequestStep requestStep = (HttpTestRequestStep) testCase.addTestStep( 138 | HttpRequestStepFactory.HTTPREQUEST_TYPE, "Request 1", "", "GET"); 139 | requestStep.getTestRequest().setEndpoint("echo://something"); 140 | requestStep.getTestRequest().setRequestContent("echo:something"); 141 | 142 | testCase.addTestStep(HttpRequestStepFactory.HTTPREQUEST_TYPE, "Request 2", "http://www.google.com", "GET"); 143 | WsdlTestCaseRunner runner = testCase.run(null, false); 144 | 145 | RestRequestStepResult result = (RestRequestStepResult) runner.getResults().get(2); 146 | assertThat(result.getResponseContent(), is("echo:something")); 147 | assertThat(runner.getResults().get(0).getMessages()[0], is("bu!")); 148 | assertThat(runner.getResults().get(1).getMessages()[0], is("groovy bu!")); 149 | 150 | result = (RestRequestStepResult) runner.getResults().get(3); 151 | assertThat(result.getResponse().getProperty("Secret Message"), is("bu!")); 152 | 153 | PanelBuilder panelBuilder = PanelBuilderRegistry.getPanelBuilder(testCase.getTestStepAt(0)); 154 | assertThat(panelBuilder, is(notNullValue())); 155 | 156 | assertThat(SubReportFactoryRegistry.getFactory("SampleSubReport"), is(notNullValue())); 157 | 158 | EditorViewFactory[] editorViewFactories = EditorViewFactoryRegistry.getInstance().getFactoriesOfType(RequestEditorViewFactory.class); 159 | final String sampleRequestEditorView = "SampleRequestEditorView"; 160 | assertThat(editorViewFactories, hasAnEditorViewWithId(sampleRequestEditorView)); 161 | 162 | editorViewFactories = EditorViewFactoryRegistry.getInstance().getFactoriesOfType(ResponseEditorViewFactory.class); 163 | assertThat(editorViewFactories, hasAnEditorViewWithId("SampleResponseEditorView")); 164 | 165 | assertThat(InspectorRegistry.getInstance().getFactoriesOfType(RequestInspectorFactory.class), hasAnInspectorWithId("SampleRequestInspector")); 166 | 167 | assertThat(InspectorRegistry.getInstance().getFactoriesOfType(ResponseInspectorFactory.class), hasAnInspectorWithId("SampleResponseInspector")); 168 | 169 | Map availableAssertions = TestAssertionRegistry.getInstance().getAvailableAssertions(); 170 | assertNotNull(availableAssertions.get("SampleTestAssertionId")); 171 | assertNotNull(WsdlTestStepRegistry.getInstance().getFactory("SampleTestStep")); 172 | 173 | String dynamicPropertyExpansion = 174 | "${=new com.smartbear.soapui.plugin.template.TemplateScript(\"Hello %s\").format( \"Doug\" )}"; 175 | assertThat(PropertyExpander.getDefaultExpander().expand(project, dynamicPropertyExpansion), is("Hello Doug")); 176 | 177 | assertThat(soapUIProCore.getActionRegistry(), containsActionWithId("SampleJavaAction")); 178 | assertThat(soapUIProCore.getActionRegistry(), containsActionWithId("SampleGroovyAction")); 179 | } 180 | 181 | private Matcher containsActionWithId(final String actionId) { 182 | 183 | return new TypeSafeMatcher() { 184 | @Override 185 | protected boolean matchesSafely(SoapUIActionRegistry soapUIActionRegistry) { 186 | return soapUIActionRegistry.getAction(actionId) != null; 187 | } 188 | 189 | @Override 190 | public void describeTo(Description description) { 191 | description.appendText("An actions with id [" + actionId + "]"); 192 | } 193 | }; 194 | 195 | } 196 | 197 | private void verifyFunctionalityUninstalled() { 198 | WsdlTestCaseRunner runner; 199 | RestRequestStepResult result; 200 | EditorViewFactory[] editorViewFactories; 201 | InspectorFactory[] inspectorFactories; 202 | assertThat(PanelBuilderRegistry.getPanelBuilder(testCase.getTestStepAt(0)), is(nullValue())); 203 | assertThat(testCase.addTestStep("SampleTestStep", "My TestStep"), is(nullValue())); 204 | assertThat(testCase.addTestStep("SampleGroovyTestStep", "My TestStep"), is(nullValue())); 205 | testCase.removeTestStep(testCase.getTestStepAt(0)); 206 | testCase.removeTestStep(testCase.getTestStepAt(0)); 207 | 208 | runner = testCase.run(null, false); 209 | 210 | assertEquals(TestRunner.Status.FAILED, runner.getStatus()); 211 | assertEquals(1, runner.getResults().size()); 212 | 213 | testCase.setFailOnError(false); 214 | runner = testCase.run(null, false); 215 | 216 | result = (RestRequestStepResult) runner.getResults().get(0); 217 | assertEquals("", result.getResponseContent()); 218 | 219 | result = (RestRequestStepResult) runner.getResults().get(1); 220 | assertNull(result.getResponse().getProperty("Secret Message")); 221 | 222 | assertNull(SubReportFactoryRegistry.getFactory("SampleSubReport")); 223 | 224 | editorViewFactories = EditorViewFactoryRegistry.getInstance().getFactoriesOfType(RequestEditorViewFactory.class); 225 | assertThat(editorViewFactories, not(hasAnEditorViewWithId("SampleRequestEditorView"))); 226 | 227 | editorViewFactories = EditorViewFactoryRegistry.getInstance().getFactoriesOfType(ResponseEditorViewFactory.class); 228 | assertThat(editorViewFactories, not(hasAnEditorViewWithId("SampleResponseEditorView"))); 229 | 230 | 231 | inspectorFactories = InspectorRegistry.getInstance().getFactoriesOfType(RequestInspectorFactory.class); 232 | assertThat(inspectorFactories, not(hasAnInspectorWithId("SampleRequestInspector"))); 233 | 234 | assertThat(InspectorRegistry.getInstance().getFactoriesOfType(ResponseInspectorFactory.class), not(hasAnInspectorWithId("SampleResponseInspector"))); 235 | Map availableAssertions2 = TestAssertionRegistry.getInstance().getAvailableAssertions(); 236 | assertNull(availableAssertions2.get("SampleTestAssertionId")); 237 | assertNull(WsdlTestStepRegistry.getInstance().getFactory("SampleTestStep")); 238 | } 239 | 240 | private Matcher hasAnEditorViewWithId(final String viewId) { 241 | return hasItemInArray( 242 | new TypeSafeMatcher() { 243 | @Override 244 | public boolean matchesSafely(EditorViewFactory o) { 245 | return o.getViewId().equals(viewId); 246 | } 247 | 248 | @Override 249 | public void describeTo(Description description) { 250 | description.appendText("a RequestEditorFactory with the ID " + viewId); 251 | } 252 | }); 253 | } 254 | 255 | private Matcher hasAnInspectorWithId(final String inspectorId) { 256 | return hasItemInArray( 257 | new TypeSafeMatcher() { 258 | @Override 259 | public boolean matchesSafely(InspectorFactory o) { 260 | return o.getInspectorId().equals(inspectorId); 261 | } 262 | 263 | @Override 264 | public void describeTo(Description description) { 265 | description.appendText("an inspector factory with the ID " + inspectorId); 266 | } 267 | }); 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /ready-api-plugin-template/README.md: -------------------------------------------------------------------------------- 1 | ready-api-plugin-template 2 | ========================== 3 | 4 | A sample plugin showing off most of the current extension mechanisms in ReadyAPI. 5 | 6 | Clone the containing repository locally and run in the ready-api-plugin-template folder 7 | 8 | ``` 9 | mvn install 10 | ``` 11 | 12 | which will create a ready-api-plugin-template-1.0-SNAPSHOT.jar in your target folder. Open ReadyAPIs 13 | Plugin Repository from the main toolbar and choose to load a plugin from file - select this file - which 14 | will install all the extensions in Ready! API for your musing. 15 | 16 | Also see the [maven-soapui-plugin-archetype](https://github.com/olensmar/maven-soapui-plugin-archetype) project 17 | if you want to create new plugins from scratch. 18 | 19 | Please open issues / improvement requests here at GitHub. 20 | 21 | Enjoy! 22 | -------------------------------------------------------------------------------- /ready-api-plugin-template/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | ready-api-plugins 7 | com.smartbear 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | ready-api-plugin-template 13 | 14 | Ready! API Plugin Template 15 | 16 | 17 | SoapUI_M2 18 | SoapUI/ReadyAPI maven 19 | https://rapi.tools.ops.smartbear.io/nexus/content/groups/public/ 20 | 21 | 22 | 23 | 24 | 25 | org.codehaus.gmaven.runtime 26 | gmaven-runtime-1.8 27 | 1.5 28 | provided 29 | 30 | 31 | junit 32 | junit 33 | 4.13.1 34 | test 35 | 36 | 37 | com.smartbear 38 | ready-api-core 39 | ${ready-api-version} 40 | provided 41 | 42 | 43 | com.smartbear 44 | ready-api-soapui-pro 45 | ${ready-api-version} 46 | provided 47 | 48 | 49 | com.google.guava 50 | guava 51 | 52 | 53 | com.lowagie 54 | itext 55 | 56 | 57 | 58 | 59 | com.smartbear 60 | ready-api-projects 61 | ${ready-api-version} 62 | provided 63 | 64 | 65 | com.lowagie 66 | itext 67 | 68 | 69 | 70 | 71 | json 72 | json-lib 73 | 2.2.2-jdk15-fixed 74 | 75 | 76 | 77 | 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-compiler-plugin 82 | ${maven-compiler-plugin.version} 83 | 84 | 1.8 85 | 1.8 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/PluginConfig.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template; 2 | 3 | import com.eviware.soapui.plugins.PluginAdapter; 4 | import com.eviware.soapui.plugins.PluginConfiguration; 5 | 6 | @PluginConfiguration(groupId = "com.smartbear.ready.plugins", 7 | name = "Ready! API Plugin Template", version = "1.0", 8 | autoDetect = true, description = "A Sample Ready! API Plugin", 9 | infoUrl = "https://github.com/smartbear/ready-api-plugin-template") 10 | public class PluginConfig extends PluginAdapter { 11 | } 12 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/actions/SampleJavaAction.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.actions; 2 | 3 | import com.eviware.soapui.impl.wsdl.WsdlProject; 4 | import com.eviware.soapui.plugins.ActionConfiguration; 5 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction; 6 | import com.smartbear.ready.core.ApplicationEnvironment; 7 | 8 | import javax.swing.JLabel; 9 | 10 | @ActionConfiguration(actionGroup = "EnabledWsdlProjectActions") 11 | public class SampleJavaAction extends AbstractSoapUIAction { 12 | 13 | public SampleJavaAction() { 14 | super("Sample Java Action", "A sample action at the project level"); 15 | } 16 | 17 | @Override 18 | public void perform(WsdlProject wsdlProject, Object o) { 19 | ApplicationEnvironment.getDesktop().setInspectorContent("Inspector", new JLabel("Hello from [" + wsdlProject.getName() + "]!")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/actions/SampleToolbarAction.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.actions; 2 | 3 | import com.eviware.soapui.model.workspace.Workspace; 4 | import com.eviware.soapui.plugins.ActionConfiguration; 5 | import com.eviware.soapui.plugins.ToolbarPosition; 6 | import com.eviware.soapui.support.UISupport; 7 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction; 8 | 9 | /** 10 | * Example of a plugin action that will be inserted into the SoapUI main toolbar. 11 | */ 12 | 13 | @ActionConfiguration(actionGroup = "EnabledWsdlProjectActions", toolbarPosition = ToolbarPosition.FUNCTIONAL_TESTING, 14 | toolbarIcon = "/favicon.png", description = "Says Hello") 15 | public class SampleToolbarAction extends AbstractSoapUIAction { 16 | 17 | public SampleToolbarAction() { 18 | super("Sample Toolbar Action", "A sample Toolbar action"); 19 | } 20 | 21 | @Override 22 | public void perform(Workspace workspace, Object o) { 23 | UISupport.showInfoMessage("Hello from toolbar action in workspace " + workspace.getName() + "!"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleDiscoveryMethod.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.impl.actions.DiscoveryMethod; 4 | import com.eviware.soapui.impl.rest.discovery.DiscoveredRequest; 5 | import com.eviware.soapui.impl.rest.discovery.RestDiscoveryMethod; 6 | import com.eviware.soapui.model.workspace.Workspace; 7 | import com.eviware.soapui.plugins.auto.PluginDiscoveryMethod; 8 | import com.eviware.soapui.support.UISupport; 9 | 10 | import java.util.List; 11 | 12 | @PluginDiscoveryMethod 13 | public class SampleDiscoveryMethod implements DiscoveryMethod { 14 | @Override 15 | public boolean isSynchronous() { 16 | return false; 17 | } 18 | 19 | @Override 20 | public void discoverResources(Workspace workspace) { 21 | UISupport.showInfoMessage("bu!"); 22 | } 23 | 24 | @Override 25 | public List discoverResourcesSynchronously(Workspace workspace) { 26 | return null; 27 | } 28 | 29 | @Override 30 | public String getDescription() { 31 | return "Dummy Discovery method - doesn't actually do anything."; 32 | } 33 | 34 | @Override 35 | public RestDiscoveryMethod getRestDiscoveryMethod() { 36 | return null; 37 | } 38 | 39 | @Override 40 | public String getLabel() { 41 | return "Ghost Discovery!"; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleImportMethod.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.impl.WorkspaceImpl; 4 | import com.eviware.soapui.plugins.auto.PluginImportMethod; 5 | import com.eviware.soapui.support.UISupport; 6 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction; 7 | 8 | /** 9 | * Created by ole on 20/06/14. 10 | */ 11 | 12 | @PluginImportMethod(label = "Sample Importer") 13 | public class SampleImportMethod extends AbstractSoapUIAction { 14 | public SampleImportMethod() { 15 | super("SampleImportMethod", "A sample importer", "A sample importer description"); 16 | } 17 | 18 | @Override 19 | public void perform(WorkspaceImpl target, Object param) { 20 | UISupport.showInfoMessage("bu!"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SamplePanelBuilder.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.impl.EmptyPanelBuilder; 4 | import com.eviware.soapui.plugins.auto.PluginPanelBuilder; 5 | 6 | /** 7 | * Created by ole on 18/06/14. 8 | */ 9 | @PluginPanelBuilder(targetModelItem = SampleTestStep.class) 10 | public class SamplePanelBuilder extends EmptyPanelBuilder { 11 | } 12 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SamplePrefs.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.actions.GroupedPreferences; 4 | import com.eviware.soapui.model.settings.Settings; 5 | import com.eviware.soapui.plugins.auto.PluginPrefs; 6 | import com.eviware.soapui.support.components.ListStyleForm; 7 | import com.eviware.soapui.support.components.SimpleForm; 8 | import com.eviware.soapui.support.types.StringToStringMap; 9 | 10 | /** 11 | * Created by ole on 18/06/14. 12 | */ 13 | @PluginPrefs 14 | public class SamplePrefs implements GroupedPreferences { 15 | @Override 16 | public SimpleForm getForm() { 17 | return new ListStyleForm(); 18 | } 19 | 20 | @Override 21 | public void setFormValues(Settings settings) { 22 | 23 | } 24 | 25 | @Override 26 | public void getFormValues(Settings settings) { 27 | 28 | } 29 | 30 | @Override 31 | public void storeValues(StringToStringMap values, Settings settings) { 32 | 33 | } 34 | 35 | @Override 36 | public StringToStringMap getValues(Settings settings) { 37 | return null; 38 | } 39 | 40 | @Override 41 | public String getTitle() { 42 | return "Sample Prefs"; 43 | } 44 | 45 | @Override 46 | public String getGroup() { 47 | return "Other"; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleRequestEditorView.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginRequestEditorView; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.views.AbstractXmlEditorView; 7 | import com.eviware.soapui.support.editor.xml.XmlEditor; 8 | 9 | import javax.swing.JComponent; 10 | import javax.swing.JLabel; 11 | 12 | /** 13 | * Created by ole on 18/06/14. 14 | */ 15 | 16 | @PluginRequestEditorView(viewId = "SampleRequestEditorView") 17 | public class SampleRequestEditorView extends AbstractXmlEditorView { 18 | 19 | private ModelItem modelItem; 20 | 21 | public SampleRequestEditorView(Editor editor, ModelItem modelItem) { 22 | super("Sample Request Editor View", (XmlEditor) editor, "SampleRequestEditorView"); 23 | this.modelItem = modelItem; 24 | } 25 | 26 | @Override 27 | public JComponent getComponent() { 28 | return new JLabel(modelItem.getName()); 29 | } 30 | 31 | @Override 32 | public void setEditable(boolean enabled) { 33 | 34 | } 35 | 36 | @Override 37 | public boolean saveDocument(boolean validate) { 38 | return true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleRequestFilter.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.impl.support.AbstractHttpRequestInterface; 4 | import com.eviware.soapui.impl.wsdl.submit.filters.AbstractRequestFilter; 5 | import com.eviware.soapui.impl.wsdl.submit.transports.http.BaseHttpRequestTransport; 6 | import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse; 7 | import com.eviware.soapui.model.iface.SubmitContext; 8 | import com.eviware.soapui.plugins.auto.PluginRequestFilter; 9 | 10 | /** 11 | * Created by ole on 18/06/14. 12 | */ 13 | 14 | @PluginRequestFilter(protocol = "http") 15 | public class SampleRequestFilter extends AbstractRequestFilter { 16 | @Override 17 | public void afterAbstractHttpResponse(SubmitContext context, AbstractHttpRequestInterface request) { 18 | HttpResponse response = (HttpResponse) context.getProperty(BaseHttpRequestTransport.RESPONSE); 19 | response.setProperty("Secret Message", "bu!"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleRequestInspector.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginRequestInspector; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.EditorView; 7 | import com.eviware.soapui.support.editor.inspectors.AbstractXmlInspector; 8 | import com.eviware.soapui.support.editor.xml.XmlDocument; 9 | 10 | import javax.swing.JComponent; 11 | import javax.swing.JLabel; 12 | 13 | /** 14 | * Created by ole on 18/06/14. 15 | */ 16 | 17 | @PluginRequestInspector(inspectorId = "SampleRequestInspector") 18 | public class SampleRequestInspector extends AbstractXmlInspector { 19 | private ModelItem modelItem; 20 | 21 | public SampleRequestInspector(Editor editor, ModelItem modelItem) { 22 | super("Sample Request Inspector", "A sample request inspector", true, "SampleRequestInspector"); 23 | this.modelItem = modelItem; 24 | } 25 | 26 | @Override 27 | public boolean isEnabledFor(EditorView view) { 28 | return true; 29 | } 30 | 31 | @Override 32 | public JComponent getComponent() { 33 | return new JLabel(modelItem.getName() + ": " + modelItem.getDescription()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleRequestTransport.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.impl.support.AbstractHttpRequestInterface; 4 | import com.eviware.soapui.impl.wsdl.submit.RequestFilter; 5 | import com.eviware.soapui.impl.wsdl.submit.RequestTransport; 6 | import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse; 7 | import com.eviware.soapui.impl.wsdl.submit.transports.http.SSLInfo; 8 | import com.eviware.soapui.model.iface.Request; 9 | import com.eviware.soapui.model.iface.Response; 10 | import com.eviware.soapui.model.iface.SubmitContext; 11 | import com.eviware.soapui.model.util.BaseResponse; 12 | import com.eviware.soapui.plugins.auto.PluginRequestTransport; 13 | import com.eviware.soapui.support.UISupport; 14 | 15 | import java.io.UnsupportedEncodingException; 16 | import java.net.URL; 17 | 18 | /** 19 | * Created by ole on 18/06/14. 20 | */ 21 | 22 | @PluginRequestTransport(protocol = "echo") 23 | public class SampleRequestTransport implements RequestTransport { 24 | @Override 25 | public void addRequestFilter(RequestFilter filter) { 26 | 27 | } 28 | 29 | @Override 30 | public void removeRequestFilter(RequestFilter filter) { 31 | 32 | } 33 | 34 | @Override 35 | public void abortRequest(SubmitContext submitContext) { 36 | 37 | } 38 | 39 | @Override 40 | public Response sendRequest(SubmitContext submitContext, final Request request) throws Exception { 41 | UISupport.getDialogs().showInfoMessage(request.getRequestContent()); 42 | return new MyResponse(request, request.getRequestContent(), "text/text"); 43 | } 44 | 45 | @Override 46 | public void insertRequestFilter(RequestFilter filter, RequestFilter refFilter) { 47 | 48 | } 49 | 50 | private static class MyResponse extends BaseResponse implements HttpResponse { 51 | private String responseContent; 52 | 53 | public MyResponse(Request request, String responseContent, String responseContentType) { 54 | super(request, responseContent, responseContentType); 55 | } 56 | 57 | @Override 58 | public void setResponseContent(String responseContent) { 59 | this.responseContent = responseContent; 60 | } 61 | 62 | @Override 63 | public String getContentAsString() { 64 | return responseContent == null ? super.getContentAsString() : responseContent; 65 | } 66 | 67 | @Override 68 | public AbstractHttpRequestInterface getRequest() { 69 | return (AbstractHttpRequestInterface) super.getRequest(); 70 | } 71 | 72 | @Override 73 | public SSLInfo getSSLInfo() { 74 | return null; 75 | } 76 | 77 | @Override 78 | public URL getURL() { 79 | return null; 80 | } 81 | 82 | @Override 83 | public byte[] getRawResponseBody() { 84 | try { 85 | return responseContent == null ? new byte[0] : responseContent.getBytes("UTF-8"); 86 | } catch (UnsupportedEncodingException wontHappen) { 87 | return new byte[0]; 88 | } 89 | } 90 | 91 | @Override 92 | public String getMethod() { 93 | return "GET"; 94 | } 95 | 96 | @Override 97 | public String getHttpVersion() { 98 | return "1.0"; 99 | } 100 | 101 | @Override 102 | public int getStatusCode() { 103 | return 200; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleResponseEditorView.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginResponseEditorView; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.views.AbstractXmlEditorView; 7 | import com.eviware.soapui.support.editor.xml.XmlEditor; 8 | 9 | import javax.swing.JComponent; 10 | import javax.swing.JLabel; 11 | 12 | /** 13 | * Created by ole on 18/06/14. 14 | */ 15 | 16 | @PluginResponseEditorView(viewId = "SampleResponseEditorView") 17 | public class SampleResponseEditorView extends AbstractXmlEditorView { 18 | 19 | private ModelItem modelItem; 20 | 21 | public SampleResponseEditorView(Editor editor, ModelItem modelItem) { 22 | super("Sample Response Editor View", (XmlEditor) editor, "SampleResponseEditorView"); 23 | this.modelItem = modelItem; 24 | } 25 | 26 | @Override 27 | public JComponent getComponent() { 28 | return new JLabel(modelItem.getName()); 29 | } 30 | 31 | @Override 32 | public void setEditable(boolean enabled) { 33 | } 34 | 35 | @Override 36 | public boolean saveDocument(boolean validate) { 37 | return true; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleResponseInspector.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginResponseInspector; 5 | import com.eviware.soapui.support.editor.Editor; 6 | import com.eviware.soapui.support.editor.EditorView; 7 | import com.eviware.soapui.support.editor.inspectors.AbstractXmlInspector; 8 | import com.eviware.soapui.support.editor.xml.XmlDocument; 9 | 10 | import javax.swing.JComponent; 11 | import javax.swing.JLabel; 12 | 13 | /** 14 | * Created by ole on 18/06/14. 15 | */ 16 | 17 | @PluginResponseInspector(inspectorId = "SampleResponseInspector") 18 | public class SampleResponseInspector extends AbstractXmlInspector { 19 | private ModelItem modelItem; 20 | 21 | public SampleResponseInspector(Editor editor, ModelItem modelItem) { 22 | super("Sample Response Inspector", "A sample response inspector", true, "SampleResponseInspector"); 23 | this.modelItem = modelItem; 24 | } 25 | 26 | @Override 27 | public boolean isEnabledFor(EditorView view) { 28 | return true; 29 | } 30 | 31 | @Override 32 | public JComponent getComponent() { 33 | return new JLabel(modelItem.getName() + ": " + modelItem.getDescription()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleSubReport.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.model.ModelItem; 4 | import com.eviware.soapui.plugins.auto.PluginSubReport; 5 | import com.eviware.soapui.reporting.reports.support.AbstractJasperSubReport; 6 | import net.sf.jasperreports.engine.JRDataSource; 7 | import net.sf.jasperreports.engine.JRException; 8 | import net.sf.jasperreports.engine.JRField; 9 | 10 | /** 11 | * Created by ole on 18/06/14. 12 | */ 13 | 14 | @PluginSubReport(name = "SampleSubReport", description = "A sample SubReport", id = "SampleSubReport", level = "COMMON") 15 | public class SampleSubReport extends AbstractJasperSubReport { 16 | 17 | protected SampleSubReport(ModelItem modelItem, String nameInReport, boolean cacheDataSource) { 18 | super(modelItem, nameInReport, cacheDataSource); 19 | } 20 | 21 | @Override 22 | public JRDataSource buildDataSource(ModelItem modelItem) { 23 | 24 | return new JRDataSource() { 25 | 26 | int cnt = 0; 27 | 28 | @Override 29 | public boolean next() throws JRException { 30 | 31 | return ++cnt < 5; 32 | } 33 | 34 | @Override 35 | public Object getFieldValue(JRField jrField) throws JRException { 36 | return jrField.getName() + " value " + cnt; 37 | } 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleTestAssertion.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.config.TestAssertionConfig; 4 | import com.eviware.soapui.impl.wsdl.panels.assertions.AssertionCategoryMapping; 5 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlMessageAssertion; 6 | import com.eviware.soapui.model.iface.MessageExchange; 7 | import com.eviware.soapui.model.iface.SubmitContext; 8 | import com.eviware.soapui.model.testsuite.Assertable; 9 | import com.eviware.soapui.model.testsuite.AssertionError; 10 | import com.eviware.soapui.model.testsuite.AssertionException; 11 | import com.eviware.soapui.model.testsuite.ResponseAssertion; 12 | import com.eviware.soapui.plugins.auto.PluginTestAssertion; 13 | import com.eviware.soapui.support.JsonUtil; 14 | import com.eviware.soapui.support.StringUtils; 15 | 16 | @PluginTestAssertion(id = "SampleTestAssertionId", label = "Sample JSON Content Assertion", 17 | category = AssertionCategoryMapping.VALIDATE_RESPONSE_CONTENT_CATEGORY, 18 | description = "Asserts that the response message is a valid JSON string") 19 | public class SampleTestAssertion extends WsdlMessageAssertion implements ResponseAssertion { 20 | /** 21 | * Assertions need to have a constructor that takes a TestAssertionConfig and the ModelItem to be asserted 22 | */ 23 | 24 | public SampleTestAssertion(TestAssertionConfig assertionConfig, Assertable modelItem) { 25 | super(assertionConfig, modelItem, true, false, false, true); 26 | } 27 | 28 | @Override 29 | protected String internalAssertResponse(MessageExchange messageExchange, SubmitContext submitContext) throws AssertionException { 30 | 31 | try { 32 | String content = messageExchange.getResponse().getContentAsString(); 33 | if (StringUtils.isNullOrEmpty(content)) { 34 | return "Response is empty - not a valid JSON response"; 35 | } 36 | 37 | JsonUtil.getJson(messageExchange.getResponse().getContentAsString()); 38 | } catch (Exception e) { 39 | throw new AssertionException(new AssertionError("JSON Parsing failed; [" + e.toString() + "]")); 40 | } 41 | 42 | return "Response is valid JSON"; 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleTestStep.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.config.TestStepConfig; 4 | import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase; 5 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepResult; 6 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepWithProperties; 7 | import com.eviware.soapui.model.testsuite.TestCaseRunContext; 8 | import com.eviware.soapui.model.testsuite.TestCaseRunner; 9 | import com.eviware.soapui.model.testsuite.TestStepResult; 10 | import com.eviware.soapui.plugins.auto.PluginTestStep; 11 | 12 | /** 13 | * Created by ole on 17/06/14. 14 | */ 15 | 16 | @PluginTestStep(typeName = "SampleTestStep", name = "Sample TestStep", description = "A sample TestStep") 17 | public class SampleTestStep extends WsdlTestStepWithProperties { 18 | 19 | public SampleTestStep(WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest) { 20 | super(testCase, config, false, forLoadTest); 21 | } 22 | 23 | @Override 24 | public TestStepResult run(TestCaseRunner testRunner, TestCaseRunContext testRunContext) { 25 | WsdlTestStepResult result = new WsdlTestStepResult(this); 26 | result.addMessage("bu!"); 27 | return result; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/factories/SampleValueProvider.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext; 4 | import com.eviware.soapui.model.propertyexpansion.resolvers.DynamicPropertyResolver; 5 | import com.eviware.soapui.plugins.auto.PluginValueProvider; 6 | 7 | /** 8 | * Created by ole on 14/06/14. 9 | */ 10 | 11 | @PluginValueProvider(valueName = "randomNumber") 12 | public class SampleValueProvider implements DynamicPropertyResolver.ValueProvider { 13 | @Override 14 | public String getValue(PropertyExpansionContext propertyExpansionContext) { 15 | return String.valueOf(1000 * Math.random()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/java/com/smartbear/ready/plugin/template/listeners/SampleJavaListener.java: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.listeners; 2 | 3 | import com.smartbear.ready.core.Logging; 4 | import com.eviware.soapui.model.support.TestRunListenerAdapter; 5 | import com.eviware.soapui.model.testsuite.TestCaseRunContext; 6 | import com.eviware.soapui.model.testsuite.TestCaseRunner; 7 | import com.eviware.soapui.plugins.ListenerConfiguration; 8 | 9 | @ListenerConfiguration 10 | public class SampleJavaListener extends TestRunListenerAdapter { 11 | 12 | @Override 13 | public void beforeRun(TestCaseRunner testRunner, TestCaseRunContext runContext) { 14 | Logging.log("Test " + testRunner.getTestCase().getName() + " starting..."); 15 | } 16 | 17 | @Override 18 | public void afterRun(TestCaseRunner testRunner, TestCaseRunContext runContext) { 19 | Logging.log("Test " + testRunner.getTestCase().getName() + " stopping..."); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/resources/com/smartbear/ready/plugin/template/GroovyAction.groovy: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template 2 | 3 | import com.eviware.soapui.impl.WorkspaceImpl 4 | import com.eviware.soapui.plugins.ActionConfiguration 5 | import com.eviware.soapui.support.UISupport 6 | import com.eviware.soapui.support.action.ActionGroups 7 | import com.eviware.soapui.support.action.support.AbstractSoapUIAction 8 | 9 | @ActionConfiguration( actionGroup = ActionGroups.WORKSPACE_ACTIONS) 10 | public class GroovyAction extends AbstractSoapUIAction { 11 | public GroovyAction() 12 | { 13 | super( "SampleGroovyAction", "Groovy Action", "Says something groovy") 14 | } 15 | 16 | @Override 17 | void perform(WorkspaceImpl target, Object param) { 18 | UISupport.showInfoMessage( "something groovy") 19 | } 20 | } -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/resources/com/smartbear/ready/plugin/template/TemplateScript.groovy: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template 2 | 3 | public class TemplateScript 4 | { 5 | String str 6 | 7 | public TemplateScript( def str ) 8 | { 9 | this.str = str; 10 | } 11 | 12 | public def format( def value ) 13 | { 14 | return String.format( str, value ) 15 | } 16 | } -------------------------------------------------------------------------------- /ready-api-plugin-template/src/main/resources/com/smartbear/ready/plugin/template/factories/SampleGroovyTestStep.groovy: -------------------------------------------------------------------------------- 1 | package com.smartbear.ready.plugin.template.factories; 2 | 3 | import com.eviware.soapui.config.TestStepConfig; 4 | import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase; 5 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepResult; 6 | import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepWithProperties; 7 | import com.eviware.soapui.model.testsuite.TestCaseRunContext; 8 | import com.eviware.soapui.model.testsuite.TestCaseRunner; 9 | import com.eviware.soapui.model.testsuite.TestStepResult; 10 | import com.eviware.soapui.plugins.auto.PluginTestStep; 11 | 12 | /** 13 | * Created by ole on 17/06/14. 14 | */ 15 | 16 | @PluginTestStep(typeName = "SampleGroovyTestStep", name = "Sample Groovy TestStep", description = "A sample TestStep written in Groovy") 17 | public class SampleGroovyTestStep extends WsdlTestStepWithProperties { 18 | 19 | public SampleGroovyTestStep(WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest) { 20 | super(testCase, config, false, forLoadTest); 21 | } 22 | 23 | @Override 24 | public TestStepResult run(TestCaseRunner testRunner, TestCaseRunContext testRunContext) { 25 | WsdlTestStepResult result = new WsdlTestStepResult(this); 26 | result.addMessage("groovy bu!"); 27 | return result; 28 | } 29 | } 30 | --------------------------------------------------------------------------------