modules/helpers/pluginAnnotations/src/main/java/org/rhq/helpers/pluginAnnotations/agent/Parameter.java | 5 modules/helpers/pluginAnnotations/src/main/java/org/rhq/helpers/pluginAnnotations/agent/RhqType.java | 77 +++ modules/helpers/pluginGen/pom.xml | 7 modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/AnnotationProcessor.java | 44 + modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/DirectoryClassLoader.java | 142 ++++++ modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Generator.java | 229 ++++++---- modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/PluginGen.java | 31 + modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Prop.java | 59 +- modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/Props.java | 110 ++++ modules/helpers/pluginGen/src/main/resources/component.ftl | 9 modules/helpers/pluginGen/src/main/resources/descriptor.ftl | 5 modules/helpers/pluginGen/src/main/resources/descriptorMain.ftl | 17 modules/helpers/pluginGen/src/main/resources/pom.ftl | 15 modules/helpers/pluginGen/src/test/java/org/rhq/helpers/pluginGen/test/FooBean.java | 55 ++ 14 files changed, 671 insertions(+), 134 deletions(-)
New commits: commit ae96f1c0ad6e797e889923dc47a1f3c55c8eb394 Author: Heiko W. Rupp hwr@redhat.com Date: Wed Jul 17 11:06:21 2013 +0200
Allow to specify a directory with classes to scan for plugin annotations and to auto-create metrics+operations from them.
diff --git a/modules/helpers/pluginAnnotations/src/main/java/org/rhq/helpers/pluginAnnotations/agent/Parameter.java b/modules/helpers/pluginAnnotations/src/main/java/org/rhq/helpers/pluginAnnotations/agent/Parameter.java index 4b82a13..29dcc1e 100644 --- a/modules/helpers/pluginAnnotations/src/main/java/org/rhq/helpers/pluginAnnotations/agent/Parameter.java +++ b/modules/helpers/pluginAnnotations/src/main/java/org/rhq/helpers/pluginAnnotations/agent/Parameter.java @@ -29,13 +29,14 @@ import java.lang.annotation.Target;
/** * Parameter. - * + * * @author Galder ZamarreƱo * @since 4.0 */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Parameter { - String name() default ""; + String name() ; String description() default ""; + RhqType type() default RhqType.VOID; } diff --git a/modules/helpers/pluginAnnotations/src/main/java/org/rhq/helpers/pluginAnnotations/agent/RhqType.java b/modules/helpers/pluginAnnotations/src/main/java/org/rhq/helpers/pluginAnnotations/agent/RhqType.java new file mode 100644 index 0000000..1487a51 --- /dev/null +++ b/modules/helpers/pluginAnnotations/src/main/java/org/rhq/helpers/pluginAnnotations/agent/RhqType.java @@ -0,0 +1,77 @@ +/* + * 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.pluginAnnotations.agent; + +import java.io.File; + + +/** + * Base data types from RHQ for properties + * @author Heiko W. Rupp + */ +public enum RhqType { + INTEGER(new Class<?>[]{Integer.class,int.class},Boolean.class), + LONG(new Class<?>[]{Long.class,long.class},Long.class), + DOUBLE(new Class<?>[]{Double.class,double.class},Double.class), + STRING(new Class<?>[]{String.class},String.class), + LONG_STRING(new Class<?>[]{},String.class), + PASSWORD(new Class<?>[]{},String.class), + BOOLEAN(new Class<?>[]{Boolean.class, boolean.class},Boolean.class), + FLOAT(new Class<?>[]{Float.class, float.class},Float.class), + FILE(new Class<?>[]{File.class},File.class), + DIRECTORY(new Class<?>[]{},File.class), + VOID(new Class<?>[]{Void.class,void.class},Void.class) + ; + private Class<?>[] fromClasses; + private Class<?> toClass; + + private RhqType(Class<?>[] fromClasses,Class<?> toClass) { + + this.fromClasses = fromClasses; + this.toClass = toClass; + } + + public Class<?>[] getFromClasses() { + return fromClasses; + } + + public Class<?> getToClass() { + return toClass; + } + + public static RhqType findType(Class<?> clazz) { + for (RhqType type : RhqType.values()) { + for (Class from : type.getFromClasses()) { + if (clazz.equals(from)) { + return type; + } + } + } + return null; + } + + public String getRhqName() { + String name = name().toLowerCase(); + if (name.equals("long_string")) { + name = "longString"; + } + return name; + } +} diff --git a/modules/helpers/pluginGen/pom.xml b/modules/helpers/pluginGen/pom.xml index 5aa512c..e7744e4 100644 --- a/modules/helpers/pluginGen/pom.xml +++ b/modules/helpers/pluginGen/pom.xml @@ -19,6 +19,11 @@ <name>RHQ plugin generator</name> <description>Helper to generate plugin skeletons</description>
+ <properties> + <!-- we are using JDK 1.7 here, as JavaFX needs this and the generator is standalone anyway --> + <animal.sniffer.java.signature.artifactId>java17</animal.sniffer.java.signature.artifactId> + </properties> + <build> <plugins>
@@ -104,7 +109,7 @@ <dependency> <groupId>org.rhq.helpers</groupId> <artifactId>rhq-pluginAnnotations</artifactId> - <version>4.8.0-SNAPSHOT</version> + <version>4.9.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.oracle</groupId> diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/AnnotationProcessor.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/AnnotationProcessor.java new file mode 100644 index 0000000..3c90b7b --- /dev/null +++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/AnnotationProcessor.java @@ -0,0 +1,44 @@ +/* + * 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.util.List; + +/** + * Processor that scans a directory for annotated classes and generates metrics etc. from them. + * @author Heiko W. Rupp + */ +public class AnnotationProcessor { + + private List<Class> classList; + private final DirectoryClassLoader classLoader; + + public AnnotationProcessor(String baseDirectory) { + classLoader = new DirectoryClassLoader(); + classLoader.setBaseDir(baseDirectory); + } + + public void populate(Props props) { + classList = classLoader.findClasses(); + + props.populateMetrics(classList); + props.populateOperations(classList); + } +} diff --git a/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/DirectoryClassLoader.java b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/DirectoryClassLoader.java new file mode 100644 index 0000000..b4a729f --- /dev/null +++ b/modules/helpers/pluginGen/src/main/java/org/rhq/helpers/pluginGen/DirectoryClassLoader.java @@ -0,0 +1,142 @@ +/* + * 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.ByteArrayOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +/** + * Classloader to load from a given directory + * @author Heiko W. Rupp + */ +public class DirectoryClassLoader extends ClassLoader { + private Hashtable classes = new Hashtable(); //used to cache already defined classes + private String baseDir; + + @Override + protected Class<?> findClass(String pathName) throws ClassNotFoundException { + + + if (baseDir==null) { + throw new IllegalStateException("Must set baseDir first"); + } + + byte classByte[]; + Class result = null; + + String className = pathName.substring(baseDir.length()+1); // remove base dir + className = className.substring(0,className.length()-6); // remove .class + className = className.replaceAll(File.separator,"."); // change / -> . + + result = (Class) classes.get(className); //checks in cached classes + if (result != null) { + return result; + } + try { + File classFile = new File(pathName); + FileInputStream fis = new FileInputStream(classFile); + + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + int nextValue = fis.read(); + while (-1 != nextValue) { + byteStream.write(nextValue); + nextValue = fis.read(); + } + + classByte = byteStream.toByteArray(); + result = defineClass(className, classByte, 0, classByte.length, null); + classes.put(className, result); + return result; + } catch (Exception e) { + return null; + } + } + + public void setBaseDir(String baseDir) { + this.baseDir = baseDir; + } + + public List<Class> findClasses() { + if (baseDir==null) { + throw new IllegalStateException("Must set baseDir first"); + } + + File baseFile = new File(baseDir); + if(!baseFile.isDirectory()) { + throw new IllegalStateException("BaseDir is no directory"); + } + if (!baseFile.canRead()) { + throw new IllegalStateException("BaseDir is not readable"); + } + + List<File> files = walk(baseFile); + + List<Class> classes = new ArrayList<>(); + for (File file : files) { + String fileName = file.getAbsolutePath(); + + Class clazz = null; + try { + clazz = findClass(fileName); + } catch (ClassNotFoundException e) { + e.printStackTrace(); // TODO: Customise this generated block + } + classes.add(clazz); + + } + + return classes; + } + + private List<File> walk(File path) { + + List<File> files = new ArrayList<>(); + + File[] list = path.listFiles(); + + if (list == null) { + return files; + } + + for ( File f : list ) { + if ( f.isDirectory() ) { + List<File> newFiles = walk( f ); + System.out.println( "Dir:" + f.getAbsoluteFile() ); + files.addAll(newFiles); + } + else { + System.out.println( "File:" + f.getAbsoluteFile() ); + if (f.getName().endsWith(".class") && !f.getName().contains("$")) { + files.add(f); + } + + } + } + return files; + } +} 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 index e7da952..21d0d4d 100644 --- 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 @@ -149,9 +149,12 @@ public class Generator extends Application{ Label label = new Label("Messages:"); msgBox.getChildren().add(label); errorMessage = new Text(); - errorMessage.setFont(Font.font("Arial", FontWeight.SEMI_BOLD, 12)); + errorMessage.setFont(Font.font("Arial", FontWeight.SEMI_BOLD, 15)); errorMessage.setId("errorMessage"); msgBox.getChildren().add(errorMessage); + msgBox.setPadding(new Insets(5)); + msgBox.setSpacing(3); + msgBox.setAlignment(Pos.BASELINE_LEFT); return msgBox; }
@@ -172,94 +175,14 @@ public class Generator extends Application{ // 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); + addStringField(root, descriptionField, row, prop); } 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); - } - }); - Tooltip tooltip = new Tooltip(prop.getDescription()); // TODO make this a hover listener - choiceBox.setTooltip(tooltip); - - root.add(choiceBox, 1, row); + addBooleanField(root, row, prop); } 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); - } - }); - Tooltip tooltip = new Tooltip(prop.getDescription()); // TODO make this a hover listener - choiceBox.setTooltip(tooltip); - root.add(choiceBox,1,row); + addResourceTypeChooser(root, row, prop); } 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); - Tooltip tooltip = new Tooltip("Pick the (parent) directory where the plugin will be put in."); - Button pickButton = new Button("Pick"); - pickButton.setTooltip(tooltip); - 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); + addDirectoryChooserField(root, row, prop, descriptionField); + }
row++; @@ -269,6 +192,115 @@ public class Generator extends Application{ return row; }
+ private void addDirectoryChooserField(GridPane root, int row, final Prop prop, final Text descriptionField) { + // Can not add this directly, so add a button to trigger it + final TextField input = new TextField(); + root.add(input,1,row); + Tooltip tooltip = new Tooltip(prop.getDescription()); + Button pickButton = new Button("Pick"); + input.setTooltip(tooltip); + pickButton.setTooltip(tooltip); + pickButton.setOnAction(new EventHandler<ActionEvent>() { + @Override + public void handle(ActionEvent actionEvent) { + DirectoryChooser chooser = new DirectoryChooser(); + chooser.setTitle(prop.getDescription()); + File dir = chooser.showDialog(primaryStage); + if (dir != null) { + String dirName = dir.getAbsolutePath(); + setPropsValue(prop.getVariableName(), dirName, String.class); + clearErrorMessage(); + input.setText(dirName); + } else { + setErrorMessage("No directory selected"); + input.setText("Pick a directory"); + } + } + }); + input.focusedProperty().addListener(new ShowFieldDescriptionHandler(prop,descriptionField,input)); + // Add validation of the input + input.textProperty().addListener(new ChangeListener<String>() { + @Override + public void changed(ObservableValue<? extends String> observableValue, String s, String newText) { + File file = new File(newText); + if (!file.isDirectory()) { + setErrorMessage(newText + " is no directory"); + } else if (prop.isDirectoryWriteable() && !file.canWrite()) { + setErrorMessage(newText + " is not writable"); + } else if (!prop.isDirectoryWriteable() && !file.canRead()) { + setErrorMessage(newText + " is not readable"); + } else { + clearErrorMessage(); + } + + } + }); + + + + root.add(pickButton,2,row); + } + + private void addResourceTypeChooser(GridPane root, int row, final Prop prop) { + 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,prop.getType()); + } + }); + Tooltip tooltip = new Tooltip(prop.getDescription()); // TODO make this a hover listener + choiceBox.setTooltip(tooltip); + root.add(choiceBox,1,row); + } + + private void addBooleanField(GridPane root, int row, final Prop prop) { + 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"), prop.getType()); + } + }); + Tooltip tooltip = new Tooltip(prop.getDescription()); // TODO make this a hover listener + choiceBox.setTooltip(tooltip); + + root.add(choiceBox, 1, row); + } + + private void addStringField(GridPane root, final Text descriptionField, int row, final Prop prop) { + final Pattern pattern = Pattern.compile(prop.getValidationRegex()); + + final TextField input = new TextField(); + if (prop.getDefaultValue()!=null && !prop.getDefaultValue().isEmpty()) { + input.setText(prop.getDefaultValue()); + setPropsValue(prop.getVariableName(),prop.getDefaultValue(),prop.getType()); + } + // Add field leave event to fill in the props with the result + input.focusedProperty().addListener(new ShowFieldDescriptionHandler(prop,descriptionField,input)); + // 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); + } + private void setInfoMessage(String message) { errorMessage.setText(message); errorMessage.setFill(Color.DARKGREEN); @@ -297,4 +329,29 @@ public class Generator extends Application{ } }
+ + private class ShowFieldDescriptionHandler implements ChangeListener<Boolean> { + + private Prop prop; + private Text descriptionField; + private TextField input; + + private ShowFieldDescriptionHandler(Prop prop,Text descriptionField, TextField input) { + this.prop = prop; + this.descriptionField = descriptionField; + this.input = input; + } + + @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(), String.class); // TODO right place? + } + } + } } 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 64b5509..8722446 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 @@ -51,6 +51,19 @@ public class PluginGen { private final Log log = LogFactory.getLog(PluginGen.class);
public static void main(String[] arg) throws Exception { + + if (arg.length>0) { + if (arg[0].equals("-ui")) { + Generator.main(arg); + + } + else { + System.out.println("use option -ui to start the UI version"); + } + System.exit(0); + } + + PluginGen pg = new PluginGen(); pg.run();
@@ -121,10 +134,24 @@ public class PluginGen { String pkg = props.getPackagePrefix() + "." + props.getName(); props.setPkg(pkg);
+ String name = props.getName(); // Type name + + if (props.getComponentClass().contains("{name}")) { + props.setComponentClass(props.getComponentClass().replace("{name}",name)); + } + + if (props.getDiscoveryClass().contains("{name}")) { + props.setDiscoveryClass(props.getDiscoveryClass().replace("{name}",name)); + } + for (Props cProp : props.getChildren()) { cProp.setPkg(pkg); }
+ if (props.getScanForAnnotations()!=null) { + AnnotationProcessor ap = new AnnotationProcessor(props.getScanForAnnotations()); + ap.populate(props); + } }
/** @@ -247,7 +274,7 @@ public class PluginGen { }
boolean success; - File activeDirectory = new File(props.getFileSystemRoot(), props.getName()); + File activeDirectory = new File(props.getFileSystemRoot(), props.getPluginName());
if (!activeDirectory.exists()) { success = activeDirectory.mkdir(); @@ -260,7 +287,7 @@ public class PluginGen { // write pom.xml createFile(props, "pom", "pom.xml", activeDirectory.getAbsolutePath());
- // Create java directory hierarchie + // Create java directory hierarchy String path = activeDirectory.getAbsolutePath() + File.separator + "src" + File.separator + "main" + File.separator;
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 index 4ed019a..40e729c 100644 --- 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 @@ -30,48 +30,62 @@ 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 ), + FILE_ROOT("fileSystemRoot", File.class,"Root directory to put the plugin into",".*",true , true,null), 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]*"), + DISCOVERY_CLASS("discoveryClass", String.class, "Name of the Discovery class. '{name}' will be replaced with the type name", "[A-Z][a-zA-Z0-9]*",false,false,"{name}Discovery"), + COMPONENT_CLASS("componentClass", String.class, "Name of the Discovery class. '{name}' will be replaced with the type name", "[A-Z][a-zA-Z0-9]*",false,false,"{name}Component"), 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), + " there can only be one resource of that type for the given parent?"), + HAS_METRICS("hasMetrics",boolean.class,"Does this type support taking metrics?"), + HAS_OPERATIONS("hasOperations",boolean.class,"Does this type support operations?"), + HAS_EVENTS("events",boolean.class,"Does this type support events?"), + HAS_SUPPORT_FACET("supportFacet",boolean.class,"Does this type support the support facet?"), 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 - + "configuring the resource?"), + CAN_CREATE_CHILDREN("createChildren",boolean.class,"Can the type create child resources?"), + CAN_DELETE_CHILDREN("deleteChildren",boolean.class,"Can the type delete child resources?"), + USE_EXTENAL_JARS("usesExternalJarsInPlugin",boolean.class,"Will the plugin use external jars in the plugin jar?"), + ALLOW_MANUAL_ADD("manualAddOfResourceType",boolean.class,"Should manually adding resource be supported?"), + USE_LIFECYLE_API("usePluginLifecycleListenerApi",boolean.class,"Should the plugin lifecycle api be supported?"), + DEPENDS_ON_JMX_PLUGIN("dependsOnJmxPlugin",boolean.class,"Does the plugin use JMX and extend the JMX Plugin?"), + DEPENDS_ON_AS7_PLUGIN("dependsOnAs7Plugin",boolean.class,"Does the plugin use DMR and extend the AS7 Plugin?"), + USE_SUPPORT_FACET("supportFacet",boolean.class,"Will the support facet be used?"), + + SCAN_FOR_ANNOTATIONS("scanForAnnotations",File.class,"Directory to scan for plugin annotations to include in type",null, false,false, null) ;
private String variableName; private Class type; private String description; private boolean pluginLevel; + private boolean directoryWriteable; + private String defaultValue; private String validationRegex;
- private Prop(String variableName, Class type, String description, String validationRegex, boolean pluginLevel) { + private Prop(String variableName, Class type, String description, String validationRegex, boolean pluginLevel, boolean directoryWriteable, String defaultValue) { this.variableName = variableName; this.type = type; this.description = description; this.validationRegex = validationRegex; this.pluginLevel = pluginLevel; + this.directoryWriteable = directoryWriteable; + this.defaultValue = defaultValue; + } + + private Prop(String variableName, Class type, String description, String validationRegex, boolean pluginLevel) { + this(variableName,type,description,validationRegex,pluginLevel,false,null); }
private Prop(String variableName, Class type, String description, String validationRegex) { - this.variableName = variableName; - this.type = type; - this.description = description; - this.validationRegex = validationRegex; + this(variableName,type,description,validationRegex,false,false,null); + } + + private Prop(String variableName, Class type, String description) { + this(variableName,type,description,null,false,false,null); }
public String getVariableName() { @@ -111,4 +125,11 @@ public enum Prop { return builder.toString(); }
+ public boolean isDirectoryWriteable() { + return directoryWriteable; + } + + public String getDefaultValue() { + return defaultValue; + } } 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 237f5ad..95be574 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 @@ -18,6 +18,9 @@ */ package org.rhq.helpers.pluginGen;
+import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -26,6 +29,9 @@ import java.util.Set; import org.rhq.helpers.pluginAnnotations.agent.DataType; import org.rhq.helpers.pluginAnnotations.agent.DisplayType; import org.rhq.helpers.pluginAnnotations.agent.Metric; +import org.rhq.helpers.pluginAnnotations.agent.Operation; +import org.rhq.helpers.pluginAnnotations.agent.Parameter; +import org.rhq.helpers.pluginAnnotations.agent.RhqType; import org.rhq.helpers.pluginAnnotations.agent.Units;
/** @@ -33,6 +39,7 @@ import org.rhq.helpers.pluginAnnotations.agent.Units; * * @author Heiko W. Rupp */ +@SuppressWarnings("unused") public class Props {
/** What category is this ? */ @@ -69,7 +76,7 @@ public class Props { private boolean createChildren; /** Can the service delete children ? */ private boolean deleteChildren; - /** Use externals chars in the plugin jar ? */ + /** Use externals jars in the plugin jar ? */ private boolean usesExternalJarsInPlugin; /** Does it support manual add of children ? */ private boolean manualAddOfResourceType; @@ -77,8 +84,12 @@ public class Props { private boolean usePluginLifecycleListenerApi; /** Depends on JMX plugin ? */ private boolean dependsOnJmxPlugin; + /** Depends on AS7 plugin ? */ + private boolean dependsOnAs7Plugin; + /** Directory with java files to scan for plugin annotations */ + private String scanForAnnotations; /** What version of RHQ should this plugin's pom use ? */ - private String rhqVersion = "3.0.0"; + private String rhqVersion = "4.8.0";
/** Embedded children */ private Set<Props> children = new HashSet<Props>(); @@ -336,22 +347,97 @@ public class Props { this.runsInsides = runsInsides; }
+ public boolean isDependsOnAs7Plugin() { + return dependsOnAs7Plugin; + } + + public void setDependsOnAs7Plugin(boolean dependsOnAs7Plugin) { + this.dependsOnAs7Plugin = dependsOnAs7Plugin; + } + + public String getScanForAnnotations() { + return scanForAnnotations; + } + + public void setScanForAnnotations(String scanForAnnotations) { + this.scanForAnnotations = scanForAnnotations; + } + public void populateMetrics(List<Class> classes) { - for (Class<?> clazz : classes) { - Metric metricAnnot = clazz.getAnnotation(Metric.class); - if (metricAnnot != null) { - MetricProps metric = new MetricProps(metricAnnot.property()); + for (Class<?> clazz : classes) { + for (Field field : clazz.getDeclaredFields()) { + Metric metricAnnot = field.getAnnotation(Metric.class); + addMetric(metricAnnot, field.getName()); + } + + for (Method method : clazz.getDeclaredMethods()) { + Metric metricAnnot = method.getAnnotation(Metric.class); + addMetric(metricAnnot, method.getName()); + } + } + } + + public void populateOperations(List<Class> classes) { + for (Class<?> clazz : classes) { + for (Method method : clazz.getDeclaredMethods()) { + Operation operationAnnot = method.getAnnotation(Operation.class); + if (operationAnnot != null) { + String property = operationAnnot.name(); + if (property.isEmpty()) { + property = method.getName(); + } + OperationProps op = new OperationProps(property); + op.setDisplayName(operationAnnot.displayName()); + op.setDescription(operationAnnot.description()); + RhqType type = RhqType.findType(method.getReturnType()); + if (type != RhqType.VOID) { + SimpleProperty simpleProperty = new SimpleProperty(type.getRhqName()); + op.setResult(simpleProperty); + } + + Class[] types = method.getParameterTypes(); + int i=0; + for (Annotation[] annotations : method.getParameterAnnotations() ) { + for (Annotation annotation : annotations) { + if (annotation instanceof Parameter) { + Parameter parameter = (Parameter) annotation; + SimpleProperty simpleProperty = new SimpleProperty(parameter.name()); + simpleProperty.setDescription(parameter.description()); + Class typeClass = types[i]; + RhqType rhqType = RhqType.findType(typeClass); + if (parameter.type()!=RhqType.VOID){ + rhqType = parameter.type(); + } + simpleProperty.setType(rhqType.getRhqName()); + op.getParams().add(simpleProperty); + } + } + i++; + } + operations.add(op); + } + + } + } + } + + private void addMetric(Metric metricAnnot, String name) { + if (metricAnnot != null) { + String property = metricAnnot.property(); + if (property.isEmpty()) { + property = name; + } + MetricProps metric = new MetricProps(property); metric.setDisplayName(metricAnnot.displayName()); metric.setDisplayType(metricAnnot.displayType()); metric.setDataType(metricAnnot.dataType()); metric.setDescription(metricAnnot.description()); + metric.setUnits(metricAnnot.units()); metrics.add(metric); - } - - } - } + } + }
- @Override + @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("Props"); @@ -387,7 +473,7 @@ public class Props { return sb.toString(); }
- public static class TypeKey { + public static class TypeKey { private String name; private String pluginName;
diff --git a/modules/helpers/pluginGen/src/main/resources/component.ftl b/modules/helpers/pluginGen/src/main/resources/component.ftl index 1b3dda1..b445008 100644 --- a/modules/helpers/pluginGen/src/main/resources/component.ftl +++ b/modules/helpers/pluginGen/src/main/resources/component.ftl @@ -187,7 +187,6 @@ public class ${props.componentClass} implements ResourceComponent<#if props.pare
<#if props.operations??>
- public void startOperationFacet(OperationContext context) {
} @@ -203,6 +202,13 @@ public class ${props.componentClass} implements ResourceComponent<#if props.pare public OperationResult invokeOperation(String name, Configuration params) throws Exception {
OperationResult res = new OperationResult(); +<#if props.operations?has_content> + <#list props.operations as operation> + if (name.equals("${operation.name}") { + // TODO implement me + } + </#list> +<#else> if ("dummyOperation".equals(name)) { // TODO implement me
@@ -210,6 +216,7 @@ public class ${props.componentClass} implements ResourceComponent<#if props.pare return res; } </#if> +</#if>
<#if props.resourceConfiguration> diff --git a/modules/helpers/pluginGen/src/main/resources/descriptor.ftl b/modules/helpers/pluginGen/src/main/resources/descriptor.ftl index 85195e8..1fe2a6b 100644 --- a/modules/helpers/pluginGen/src/main/resources/descriptor.ftl +++ b/modules/helpers/pluginGen/src/main/resources/descriptor.ftl @@ -1,7 +1,7 @@ <#-- /* * RHQ Management Platform - * Copyright (C) 2005-2008 Red Hat, Inc. + * Copyright (C) 2005-2013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -38,6 +38,9 @@ <#if props.dependsOnJmxPlugin> <depends plugin="JMX" useClasses="true"/> </#if> +<#if props.dependsOnAs7Plugin> + <depends plugin="JBossAS7" useClasses="true"/> +</#if>
<${props.category.lowerName} <#include "descriptorMain.ftl"/>
diff --git a/modules/helpers/pluginGen/src/main/resources/descriptorMain.ftl b/modules/helpers/pluginGen/src/main/resources/descriptorMain.ftl index b650f7a..5579806 100644 --- a/modules/helpers/pluginGen/src/main/resources/descriptorMain.ftl +++ b/modules/helpers/pluginGen/src/main/resources/descriptorMain.ftl @@ -1,7 +1,7 @@ <#-- /* * RHQ Management Platform - * Copyright (C) 2005-2010 Red Hat, Inc. + * Copyright (C) 2005-2013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -39,6 +39,11 @@ name="${props.name}" </#list> </runs-inside> </#if> + <#if props.dependsOnAs7Plugin> + <runs-inside> <!-- TODO adjust type --> + <parent-resource-type name="JBossAS7 Standalone Server" plugin="JBossAS7"/> + </runs-inside> + </#if>
<#if props.simpleProps?has_content> <plugin-configuration> @@ -57,14 +62,14 @@ name="${props.name}" </plugin-configuration> </#if>
- <#if props.hasOperations> + <#if props.hasOperations || props.operations?has_content> <#if props.operations?has_content> <#list props.operations as operation> - <operation name="${operation.name}" displayName="${operation.displayName}" description="${operation.description}"> + <operation name="${operation.name}" <#if operation.displayName?has_content>displayName="${operation.displayName}"</#if> description="${operation.description}"> <#if operation.params?has_content> <parameters> <#list operation.params as param> - <c:simple-property name="${param.name}" <#if param.description??>description="${param.description}"</#if>/> + <c:simple-property name="${param.name}" <#if param.description??>description="${param.description}"</#if> type="${param.type}"/> </#list> </parameters> </#if> @@ -82,10 +87,10 @@ name="${props.name}" </#if> </#if>
- <#if props.hasMetrics> + <#if props.hasMetrics || props.metrics?has_content> <#if props.metrics?has_content> <#list props.metrics as metric> - <metric property="${metric.property}" displayName="${metric.displayName}" displayType="${metric.displayType}" units="${metric.units}" dataType="${metric.dataType}" + <metric property="${metric.property}" <#if metric.displayName?has_content>displayName="${metric.displayName}"</#if> displayType="${metric.displayType}" units="${metric.units}" dataType="${metric.dataType}" description="${metric.description}" /> </#list> <#else> diff --git a/modules/helpers/pluginGen/src/main/resources/pom.ftl b/modules/helpers/pluginGen/src/main/resources/pom.ftl index 01daca1..7c799b8 100644 --- a/modules/helpers/pluginGen/src/main/resources/pom.ftl +++ b/modules/helpers/pluginGen/src/main/resources/pom.ftl @@ -2,7 +2,7 @@ <#-- /* * RHQ Management Platform - * Copyright (C) 2005-20012 Red Hat, Inc. + * Copyright (C) 2005-20013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -35,10 +35,10 @@ </parent>
<groupId>org.rhq</groupId> - <artifactId>${props.name}-plugin</artifactId> + <artifactId>${props.pluginName}-plugin</artifactId> <packaging>jar</packaging>
- <name>RHQ ${props.name} Plugin</name> + <name>RHQ ${props.pluginName} Plugin</name> <#if props.description??> <description>${props.description}</description> </#if> @@ -86,7 +86,6 @@ </executions> </plugin> </#if> - </plugins> </build>
@@ -232,6 +231,14 @@ <scope>provided</scope> </dependency> </#if> +<#if props.dependsOnAs7Plugin> + <dependency> + <groupId>org.rhq</groupId> + <artifactId>rhq-jboss-as-7-plugin</artifactId> + <version>${r"${project.version}"}</version> + <scope>provided</scope> + </dependency> +</#if>
<!-- TODO add your dependencies here -->
diff --git a/modules/helpers/pluginGen/src/test/java/org/rhq/helpers/pluginGen/test/FooBean.java b/modules/helpers/pluginGen/src/test/java/org/rhq/helpers/pluginGen/test/FooBean.java new file mode 100644 index 0000000..fbc571b --- /dev/null +++ b/modules/helpers/pluginGen/src/test/java/org/rhq/helpers/pluginGen/test/FooBean.java @@ -0,0 +1,55 @@ +/* + * 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.test; + +import org.rhq.helpers.pluginAnnotations.agent.DataType; +import org.rhq.helpers.pluginAnnotations.agent.DisplayType; +import org.rhq.helpers.pluginAnnotations.agent.MeasurementType; +import org.rhq.helpers.pluginAnnotations.agent.Metric; +import org.rhq.helpers.pluginAnnotations.agent.Operation; +import org.rhq.helpers.pluginAnnotations.agent.Parameter; +import org.rhq.helpers.pluginAnnotations.agent.RhqType; + +/** + * Just a sample + * @author Heiko W. Rupp + */ + +public class FooBean { + + @Metric(description = "How often was this bean invoked", displayType = DisplayType.SUMMARY, measurementType = MeasurementType.DYNAMIC) + int invocationCount; + + @Metric(description = "Just a foo", dataType = DataType.TRAIT) + String lastCommand; + + @Operation(description = "Increase the invocation count") + public int increaseCounter() { + invocationCount++; + return invocationCount; + } + + @Operation(description = "Decrease the counter") + public void decreaseCounter(@Parameter(description = "How much to decrease?", name = "by") int by) { + invocationCount -= by; + } + + +}
rhq-commits@lists.fedorahosted.org