modules/helpers/pluginGen/pom.xml | 15 modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Generator.java | 295 ++++++++++ modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java | 4 modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Prop.java | 114 +++ modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java | 2 5 files changed, 427 insertions(+), 3 deletions(-)
New commits: commit eb3c52f1ba91a70fa7bdb45405849a1af4aa524a Author: Heiko W. Rupp hwr@redhat.com Date: Mon Jul 15 10:18:15 2013 +0200
Add a JavaFX frontend to the PluginGenerator.
diff --git a/modules/helpers/pluginGen/pom.xml b/modules/helpers/pluginGen/pom.xml index e9a5e29..5aa512c 100644 --- a/modules/helpers/pluginGen/pom.xml +++ b/modules/helpers/pluginGen/pom.xml @@ -22,6 +22,14 @@ <build> <plugins>
+ <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> <artifactId>maven-jar-plugin</artifactId> <configuration> @@ -98,6 +106,13 @@ <artifactId>rhq-pluginAnnotations</artifactId> <version>4.8.0-SNAPSHOT</version> </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>javafx</artifactId> + <version>2.0</version> + <systemPath>${java.home}/lib/jfxrt.jar</systemPath> + <scope>system</scope> + </dependency> </dependencies>
</project> diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Generator.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Generator.java new file mode 100644 index 0000000..06f3fec --- /dev/null +++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Generator.java @@ -0,0 +1,295 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2013 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +package org.rhq.helpers.pluginGen; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javafx.application.Application; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import javafx.scene.text.FontPosture; +import javafx.scene.text.FontWeight; +import javafx.scene.text.Text; +import javafx.scene.text.TextAlignment; +import javafx.stage.DirectoryChooser; +import javafx.stage.Stage; + +/** + * JavaFX version of the plugin generator + * @author Heiko W. Rupp + */ +public class Generator extends Application{ + + Props props = new Props(); + private Text errorMessage; + private Stage primaryStage; + + public static void main(String[] args) { + launch(args); + } + + + @Override + public void start(Stage stage) throws Exception { + primaryStage = stage; + + Button createButton = new Button(); + createButton.setText("Create!"); + createButton.setAlignment(Pos.BOTTOM_RIGHT); + createButton.setOnAction(new EventHandler<ActionEvent>() { + @Override + public void handle(ActionEvent actionEvent) { + + PluginGen pluginGen = new PluginGen(); + pluginGen.postprocess(props); + try { + pluginGen.generate(props); + setInfoMessage("Generated!"); + + } + catch (Exception e) { + setErrorMessage("Error during generation: " + e.getMessage()); + } + } + }); + + GridPane pluginLevelPane = new GridPane(); + pluginLevelPane.setPadding(new Insets(10)); + Text pluginLevelDescription = new Text("Plugin level properties"); + pluginLevelDescription.setTextAlignment(TextAlignment.CENTER); + pluginLevelDescription.setFont(Font.font("Arial", FontWeight.BOLD, 14)); + + Text resourceLevelDescription = new Text("ResourceType level properties"); + resourceLevelDescription.setTextAlignment(TextAlignment.CENTER); + resourceLevelDescription.setFont(Font.font("Arial", FontWeight.BOLD, 14)); + + Text descriptionDescription = new Text("Field description"); + descriptionDescription.setTextAlignment(TextAlignment.CENTER); + descriptionDescription.setFont(Font.font("Arial", FontWeight.BOLD, 14)); + + HBox msgBox = getMessagesBox(); + + GridPane resourceLevelPane = new GridPane(); + resourceLevelPane.setPadding(new Insets(10)); + Text descriptionText = new Text(); + descriptionText.setFont(Font.font("Arial", FontPosture.ITALIC,12)); + + VBox innerBox = new VBox(); + innerBox.setAlignment(Pos.CENTER_LEFT); + innerBox.setPadding(new Insets(25, 25, 25, 25)); + innerBox.setSpacing(8); + + addFields(pluginLevelPane, true, descriptionText); + addFields(resourceLevelPane, false, descriptionText); + + ObservableList<Node> children = innerBox.getChildren(); + children.add(pluginLevelDescription); + children.add(pluginLevelPane); + children.add(resourceLevelDescription); + children.add(resourceLevelPane); + + + ScrollPane scrollPane = new ScrollPane(); + scrollPane.setContent(innerBox); + + BorderPane outerBox = new BorderPane(); + outerBox.setTop(msgBox); + outerBox.setPadding(new Insets(5)); + outerBox.setCenter(scrollPane); + + VBox descriptionBox = new VBox(); + descriptionBox.getChildren().add(descriptionDescription); + descriptionBox.getChildren().add(descriptionText); + outerBox.setBottom(descriptionBox); + + outerBox.setRight(createButton); + + + stage.setScene(new Scene(outerBox, 600, 550)); + stage.show(); + } + + private HBox getMessagesBox() { + HBox msgBox = new HBox(); + Label label = new Label("Messages:"); + msgBox.getChildren().add(label); + errorMessage = new Text(); + errorMessage.setFont(Font.font("Arial", FontWeight.SEMI_BOLD, 12)); + errorMessage.setId("errorMessage"); + msgBox.getChildren().add(errorMessage); + return msgBox; + } + + private int addFields(final GridPane root, boolean pluginLevel, final Text descriptionField) { + + int row = 0; + for (final Prop prop : Prop.values()) { + + if (!prop.isPluginLevel()==pluginLevel) { + continue; + } + + // Add the label + String name = prop.readableName(); + Label fieldName = new Label(name); + root.add(fieldName,0,row); + + // Now add the field itself + final Class propType = prop.getType(); + if (propType.equals(String.class)) { + final Pattern pattern = Pattern.compile(prop.getValidationRegex()); + + final TextField input = new TextField(); + // Add field leave event to fill in the props with the result + input.focusedProperty().addListener(new ChangeListener<Boolean>() { + @Override + public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldState, + Boolean newState) { + if (newState) { // User entered input field + descriptionField.setText(prop.getDescription()); + } + else { // User left input field + descriptionField.setText(""); + setPropsValue(prop.getVariableName(),input.getText(), propType); // TODO right place? + } + } + }); + // Add validation of the input + input.textProperty().addListener(new ChangeListener<String>() { + @Override + public void changed(ObservableValue<? extends String> observableValue, String s, String newText) { + Matcher m = pattern.matcher(newText); + if (!m.matches()) { + setErrorMessage("Input does not match " + prop.getValidationRegex()); + } else { + clearErrorMessage(); + } + + } + }); + root.add(input, 1, row); + } else if (propType.equals(Boolean.class) || propType.equals(boolean.class)) { + final ChoiceBox choiceBox = new ChoiceBox(); + choiceBox.getItems().addAll("Yes", "No"); + choiceBox.getSelectionModel().selectLast(); // NO is default + choiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() { + @Override + public void changed(ObservableValue<? extends String> observableValue, String s, String newValue) { + setPropsValue(prop.getVariableName(),newValue.equals("Yes"),propType); + } + }); + + root.add(choiceBox,1,row); + } else if (propType.equals(ResourceCategory.class)) { + final ChoiceBox choiceBox = new ChoiceBox(); + for (ResourceCategory cat : ResourceCategory.values()) { + choiceBox.getItems().add(cat.getLowerName()); + } + choiceBox.getSelectionModel().selectLast(); // service is default + choiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() { + @Override + public void changed(ObservableValue<? extends String> observableValue, String s, String newValue) { + ResourceCategory newCategory = ResourceCategory.valueOf(newValue.toUpperCase()); + setPropsValue(prop.getVariableName(),newCategory,propType); + } + }); + + root.add(choiceBox,1,row); + } else if (propType.equals(File.class)) { + // Can not add this directly, so add a button to trigger it + final Text text = new Text(); + text.setText("Pick a directory"); + root.add(text,1,row); + Button pickButton = new Button("Pick"); + pickButton.setOnAction(new EventHandler<ActionEvent>() { + @Override + public void handle(ActionEvent actionEvent) { + DirectoryChooser chooser = new DirectoryChooser(); + chooser.setTitle("Pick a directory where the plugin will be put in."); + File dir = chooser.showDialog(primaryStage); + if (dir != null) { + String dirName = dir.getAbsolutePath(); + props.setFileSystemRoot(dirName); + clearErrorMessage(); + text.setText(dirName); + } else { + setErrorMessage("No directory selected"); + text.setText("Pick a directory"); + } + } + }); + + root.add(pickButton,2,row); + } + + row++; + + } + + return row; + } + + private void setInfoMessage(String message) { + errorMessage.setText(message); + errorMessage.setFill(Color.DARKGREEN); + } + private void setErrorMessage(String message) { + errorMessage.setText(message); + errorMessage.setFill(Color.RED); + } + + private void clearErrorMessage() { + errorMessage.setText(""); + errorMessage.setFill(Color.WHITE); + } + + private void setPropsValue(String variableName, Object value, Class type) { + + String var = variableName.substring(0,1).toUpperCase() + variableName.substring(1); + String setterName = "set"+ var; + + try { + Method setter = Props.class.getDeclaredMethod(setterName,type); + setter.invoke(props,value); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); // TODO: Customise this generated block + setErrorMessage(e.getMessage()); + } + } + +} diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java index 223a57f..64b5509 100644 --- a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java +++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java @@ -115,7 +115,7 @@ public class PluginGen { * Do some post processing over the input received. * @param props The properties just recorded from the user input */ - private void postprocess(Props props) { + protected void postprocess(Props props) {
// Set the package String pkg = props.getPackagePrefix() + "." + props.getName(); @@ -231,7 +231,7 @@ public class PluginGen { * Trigger the generation of the directory hierarchy. * @param props Parameters to take into account */ - private void generate(Props props) { + protected void generate(Props props) {
log.info("Generating...");
diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Prop.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Prop.java new file mode 100644 index 0000000..73c4cd9 --- /dev/null +++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Prop.java @@ -0,0 +1,114 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2013 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +package org.rhq.helpers.pluginGen; + +import java.io.File; + +/** + * All the properties that can be configured along with type, description and simple validation rules + * @author Heiko W. Rupp + */ +public enum Prop { + + PLUGIN_NAME("pluginName", String.class,"Name of the plugin", "\w+" , true ), + PLUGIN_DESCRIPTION("pluginDescription", String.class,"Description of the plugin",".*" , true ), + PACKAGE("packagePrefix", String.class,"Default Package","[a-zA-Z\.]+",true ), + FILE_ROOT("fileSystemRoot", File.class,"Root directory to put the plugin",".*",true ), + RHQ_VERSION("rhqVersion",String.class,"RHQ version to use","[0-9][0-9\.]+",true), + + CATEGORY("category", ResourceCategory.class, "Category of the resource type (platform = host level)",null), + TYPE_NAME("name", String.class, "Name of the resource type", "\w+"), + DESCRIPTION("description", String.class, "Description of the type", ".*"), + DISCOVERY_CLASS("discoveryClass", String.class, "Discovery class", "[A-Z][a-zA-Z0-9]*"), + COMPONENT_CLASS("componentClass", String.class, "Discovery class", "[A-Z][a-zA-Z0-9]*"), + IS_SINGLETON("singleton",Boolean.class,"Is this type a singleton, which means that" + + " there can only be one resource of that type for the given parent?",null), + HAS_METRICS("hasMetrics",boolean.class,"Does this type support taking metrics?",null), + HAS_OPERATIONS("hasOperations",boolean.class,"Does this type support operations?",null), + HAS_EVENTS("events",boolean.class,"Does this type support events?",null), + HAS_SUPPORT_FACET("supportFacet",boolean.class,"Does this type support the support facet?",null), + RESOURCE_CONFIGURATION("resourceConfiguration",boolean.class,"Does this type support " + + "configuring the resource?",".*"), + CAN_CREATE_CHILDREN("createChildren",boolean.class,"Can the type create child resources?",null), + CAN_DELETE_CHILDREN("deleteChildren",boolean.class,"Can the type delete child resources?",null), + + // TODO add the remaining properties from Prop.class + + ; + + private String variableName; + private Class type; + private String description; + private boolean pluginLevel; + private String validationRegex; + + private Prop(String variableName, Class type, String description, String validationRegex, boolean pluginLevel) { + this.variableName = variableName; + this.type = type; + this.description = description; + this.validationRegex = validationRegex; + this.pluginLevel = pluginLevel; + } + + private Prop(String variableName, Class type, String description, String validationRegex) { + this.variableName = variableName; + this.type = type; + this.description = description; + this.validationRegex = validationRegex; + } + + public String getVariableName() { + return variableName; + } + + public Class getType() { + return type; + } + + public String getDescription() { + return description; + } + + public boolean isPluginLevel() { + return pluginLevel; + } + + public String getValidationRegex() { + return validationRegex; + } + + public String readableName() { + + String name = name(); + name = name.replaceAll("_", " "); + String[] parts = name.split(" "); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + part = part.substring(0,1).toUpperCase() + part.substring(1).toLowerCase(); + builder.append(part); + if (i < parts.length-1) { + builder.append(" "); + } + } + return builder.toString(); + } + +} diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java index 484d591..237f5ad 100644 --- a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java +++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java @@ -36,7 +36,7 @@ import org.rhq.helpers.pluginAnnotations.agent.Units; public class Props {
/** What category is this ? */ - private ResourceCategory category; + private ResourceCategory category = ResourceCategory.SERVICE; /** The name of this item */ private String name; /** A description of the plugin */