Created
December 6, 2010 19:57
-
-
Save lincolnthree/730830 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, by Red Hat. | |
* Copyright 2010, Red Hat, Inc., and individual contributors | |
* by the @authors tag. See the copyright.txt in the distribution for a | |
* full listing of individual contributors. | |
* | |
* This is free software; you can redistribute it and/or modify it | |
* under the terms of the GNU Lesser General Public License as | |
* published by the Free Software Foundation; either version 2.1 of | |
* the License, or (at your option) any later version. | |
* | |
* This software 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 | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this software; if not, write to the Free | |
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. | |
*/ | |
package org.jboss.seam.forge.shell.command; | |
import org.jboss.seam.forge.project.Resource; | |
import org.jboss.seam.forge.project.util.Annotations; | |
import org.jboss.seam.forge.shell.plugins.*; | |
import javax.enterprise.event.Observes; | |
import javax.enterprise.inject.spi.Bean; | |
import javax.enterprise.inject.spi.Extension; | |
import javax.enterprise.inject.spi.ProcessBean; | |
import javax.inject.Named; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Method; | |
import java.util.*; | |
/** | |
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> | |
*/ | |
public class CommandLibraryExtension implements Extension | |
{ | |
private final Map<String, List<PluginMetadata>> plugins = new HashMap<String, List<PluginMetadata>>(); | |
public Map<String, List<PluginMetadata>> getPlugins() | |
{ | |
return plugins; | |
} | |
@SuppressWarnings("unchecked") | |
public void scan(@Observes final ProcessBean<?> event) | |
{ | |
Bean<?> bean = event.getBean(); | |
Class<?> clazz = bean.getBeanClass(); | |
if (Plugin.class.isAssignableFrom(clazz)) | |
{ | |
PluginMetadata pluginMeta = getMetadataFor((Class<? extends Plugin>) clazz); | |
if (!plugins.containsKey(pluginMeta.getName())) | |
{ | |
plugins.put(pluginMeta.getName(), new ArrayList<PluginMetadata>()); | |
} | |
plugins.get(pluginMeta.getName()).add(pluginMeta); | |
} | |
} | |
public PluginMetadata getMetadataFor(final Class<? extends Plugin> plugin) | |
{ | |
String name = getPluginName(plugin); | |
PluginMetadata pluginMeta = new PluginMetadata(); | |
pluginMeta.setName(name); | |
pluginMeta.setType(plugin); | |
if (Annotations.isAnnotationPresent(plugin, Help.class)) | |
{ | |
pluginMeta.setHelp(Annotations.getAnnotation(plugin, Help.class).value()); | |
} | |
else | |
{ | |
pluginMeta.setHelp(""); | |
} | |
if (Annotations.isAnnotationPresent(plugin, ResourceScope.class)) | |
{ | |
List<Class<? extends Resource<?>>> resourceTypes = Arrays.asList(Annotations.getAnnotation(plugin, | |
ResourceScope.class).value()); | |
pluginMeta.setResourceScopes(resourceTypes); | |
} | |
if (Annotations.isAnnotationPresent(plugin, Topic.class)) | |
{ | |
pluginMeta.setTopic(Annotations.getAnnotation(plugin, Topic.class).value()); | |
} | |
processPluginCommands(pluginMeta, plugin); | |
return pluginMeta; | |
} | |
private List<CommandMetadata> processPluginCommands(final PluginMetadata pluginMeta, final Class<?> plugin) | |
{ | |
List<CommandMetadata> results = new ArrayList<CommandMetadata>(); | |
for (Method method : plugin.getMethods()) | |
{ | |
if (Annotations.isAnnotationPresent(method, Command.class)) | |
{ | |
Command command = Annotations.getAnnotation(method, Command.class); | |
CommandMetadata commandMeta = new CommandMetadata(); | |
commandMeta.setMethod(method); | |
commandMeta.setHelp(command.help()); | |
commandMeta.setParent(pluginMeta); | |
// Default commands are invoked via the name of the plug-in, not by | |
// plug-in + command | |
if ("".equals(command.value())) | |
{ | |
commandMeta.setName(method.getName().trim().toLowerCase()); | |
} | |
else | |
{ | |
commandMeta.setName(command.value()); | |
} | |
// This works because @DefaultCommand is annotated by @Command | |
if (Annotations.isAnnotationPresent(method, DefaultCommand.class)) | |
{ | |
if (pluginMeta.hasDefaultCommand()) | |
{ | |
throw new IllegalStateException("Plugins may only have one @" | |
+ DefaultCommand.class.getSimpleName() | |
+ ", but [" + pluginMeta.getType() + "] has more than one."); | |
} | |
commandMeta.setDefault(true); | |
commandMeta.setName(pluginMeta.getName()); | |
// favor help text from this annotation over others | |
DefaultCommand def = Annotations.getAnnotation(method, DefaultCommand.class); | |
if ((def.help() != null) && !def.help().trim().isEmpty()) | |
{ | |
commandMeta.setHelp(def.help()); | |
} | |
} | |
if (Annotations.isAnnotationPresent(method, ResourceScope.class)) | |
{ | |
List<Class<? extends Resource>> resourceTypes = new ArrayList<Class<? extends Resource>>( | |
pluginMeta.getResourceScopes()); | |
resourceTypes.addAll(Arrays.asList(Annotations.getAnnotation(method, ResourceScope.class).value())); | |
commandMeta.setResourceScopes(resourceTypes); | |
} | |
// fall back to the pluginMetadata for help text | |
if ((commandMeta.getHelp() == null) || commandMeta.getHelp().trim().isEmpty()) | |
{ | |
commandMeta.setHelp(pluginMeta.getHelp()); | |
} | |
Class<?>[] parameterTypes = method.getParameterTypes(); | |
Annotation[][] parameterAnnotations = method.getParameterAnnotations(); | |
int i = 0; | |
int effectiveIndex = 0; | |
for (Class<?> clazz : parameterTypes) | |
{ | |
OptionMetadata optionMeta = new OptionMetadata(); | |
optionMeta.setType(clazz); | |
optionMeta.setIndex(i); | |
optionMeta.setEffectiveIndex(effectiveIndex); | |
if (PipeOut.class.isAssignableFrom(clazz)) | |
{ | |
optionMeta.setPipeOut(true); | |
} | |
for (Annotation annotation : parameterAnnotations[i]) | |
{ | |
if (annotation instanceof Option) | |
{ | |
Option option = (Option) annotation; | |
optionMeta.setParent(commandMeta); | |
optionMeta.setName(option.name()); | |
optionMeta.setShortName(option.shortName()); | |
optionMeta.setFlagOnly(option.flagOnly()); | |
optionMeta.setDescription(option.description()); | |
optionMeta.setDefaultValue(option.defaultValue()); | |
optionMeta.setHelp(option.help()); | |
optionMeta.setRequired(option.required()); | |
optionMeta.setPromptType(option.type()); | |
effectiveIndex++; | |
} | |
else if (annotation instanceof PipeIn) | |
{ | |
PipeIn pipeIn = (PipeIn) annotation; | |
optionMeta.setPipeIn(true); | |
} | |
} | |
commandMeta.addOption(optionMeta); | |
i++; | |
} | |
results.add(commandMeta); | |
} | |
} | |
pluginMeta.addCommands(results); | |
for (Method method : plugin.getMethods()) | |
{ | |
} | |
return results; | |
} | |
private String getPluginName(final Class<?> plugin) | |
{ | |
String name = null; | |
if (Annotations.isAnnotationPresent(plugin, OverloadedName.class)) | |
{ | |
OverloadedName named = Annotations.getAnnotation(plugin, OverloadedName.class); | |
if (named != null) | |
{ | |
name = named.value(); | |
} | |
if ((name == null) || "".equals(name.trim())) | |
{ | |
name = plugin.getSimpleName(); | |
} | |
} | |
else | |
{ | |
Named named = Annotations.getAnnotation(plugin, Named.class); | |
if (named != null) | |
{ | |
name = named.value(); | |
} | |
if ((name == null) || "".equals(name.trim())) | |
{ | |
name = plugin.getSimpleName(); | |
} | |
} | |
return name.toLowerCase(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, by Red Hat. | |
* Copyright 2010, Red Hat, Inc., and individual contributors | |
* by the @authors tag. See the copyright.txt in the distribution for a | |
* full listing of individual contributors. | |
* | |
* This is free software; you can redistribute it and/or modify it | |
* under the terms of the GNU Lesser General Public License as | |
* published by the Free Software Foundation; either version 2.1 of | |
* the License, or (at your option) any later version. | |
* | |
* This software 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 | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this software; if not, write to the Free | |
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. | |
*/ | |
package org.jboss.seam.forge.project; | |
import org.jboss.seam.forge.project.constraints.RequiresFacet; | |
import org.jboss.seam.forge.project.constraints.RequiresFacets; | |
import org.jboss.seam.forge.project.constraints.RequiresPackagingType; | |
import org.jboss.seam.forge.project.constraints.RequiresPackagingTypes; | |
/** | |
* Represents a standardized piece of a project, on which certain plugins may rely for a set of domain-specific | |
* operations. Facets are an access point to common functionality, file manipulations, descriptors that extend a basic | |
* {@link Project}. | |
* <p> | |
* Facets may be annotated with any of the following constraints in order to ensure proper dependencies are satisfied at | |
* runtime: {@link RequiresFacet}, {@link RequiresFacets}, {@link RequiresPackagingTypes}, {@link RequiresPackagingType} | |
* | |
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> | |
* | |
*/ | |
public interface Facet | |
{ | |
/** | |
* Return the {@link Project} instance on which this {@link Facet} operates. | |
*/ | |
Project getProject(); | |
/** | |
* Initialize this {@link Facet} for operation on the given {@link Project}. This method is responsible for ensuring | |
* that the {@link Facet} instance is ready for use, and must be called before any other methods. | |
*/ | |
void setProject(Project project); | |
/** | |
* Perform necessary setup for this {@link Facet} to be considered installed in the given {@link Project}. If | |
* installation is successful, the {@link Facet} should be registered in the {@link Project} by calling | |
* {@link Project#registerFacet(Facet)} | |
* | |
* @return a builder pattern reference to this {@link Facet} | |
*/ | |
Facet install(); | |
/** | |
* Return true if the {@link Facet} is available for the given {@link Project}, false if otherwise. | |
*/ | |
boolean isInstalled(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, Home of Professional Open Source | |
* Copyright 2010, Red Hat, Inc., and individual contributors | |
* by the @authors tag. See the copyright.txt in the distribution for a | |
* full listing of individual contributors. | |
* | |
* This is free software; you can redistribute it and/or modify it | |
* under the terms of the GNU Lesser General Public License as | |
* published by the Free Software Foundation; either version 2.1 of | |
* the License, or (at your option) any later version. | |
* | |
* This software 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 | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this software; if not, write to the Free | |
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. | |
*/ | |
package org.jboss.seam.forge.persistence; | |
import java.io.FileNotFoundException; | |
import javax.enterprise.inject.Instance; | |
import javax.inject.Inject; | |
import javax.inject.Named; | |
import javax.persistence.Column; | |
import javax.persistence.Entity; | |
import javax.persistence.GeneratedValue; | |
import javax.persistence.GenerationType; | |
import javax.persistence.Id; | |
import javax.persistence.Version; | |
import org.jboss.seam.forge.parser.JavaParser; | |
import org.jboss.seam.forge.parser.java.Field; | |
import org.jboss.seam.forge.parser.java.JavaClass; | |
import org.jboss.seam.forge.parser.java.util.Refactory; | |
import org.jboss.seam.forge.project.Project; | |
import org.jboss.seam.forge.project.constraints.RequiresFacet; | |
import org.jboss.seam.forge.project.constraints.RequiresProject; | |
import org.jboss.seam.forge.project.facets.JavaSourceFacet; | |
import org.jboss.seam.forge.project.resources.builtin.JavaResource; | |
import org.jboss.seam.forge.shell.PromptType; | |
import org.jboss.seam.forge.shell.Shell; | |
import org.jboss.seam.forge.shell.plugins.DefaultCommand; | |
import org.jboss.seam.forge.shell.plugins.Help; | |
import org.jboss.seam.forge.shell.plugins.Option; | |
import org.jboss.seam.forge.shell.plugins.Plugin; | |
import org.jboss.seam.forge.shell.plugins.Topic; | |
/** | |
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> | |
*/ | |
@Named("new-entity") | |
@Topic("Project") | |
@RequiresProject | |
@RequiresFacet(PersistenceFacet.class) | |
@Help("A plugin to manage simple @Entity and View creation; a basic MVC framework plugin.") | |
public class NewEntityPlugin implements Plugin | |
{ | |
private final Instance<Project> projectInstance; | |
private final Shell shell; | |
@Inject | |
public NewEntityPlugin(final Instance<Project> projectInstance, final Shell shell) | |
{ | |
this.projectInstance = projectInstance; | |
this.shell = shell; | |
} | |
@DefaultCommand(help = "Create a JPA @Entity") | |
public void newEntity( | |
@Option(required = true, | |
name = "named", | |
description = "The @Entity name") final String entityName) throws FileNotFoundException | |
{ | |
// TODO this should accept a qualified name as a parameter instead of | |
// prompting for the package later | |
Project project = projectInstance.get(); | |
PersistenceFacet scaffold = project.getFacet(PersistenceFacet.class); | |
JavaSourceFacet java = project.getFacet(JavaSourceFacet.class); | |
String entityPackage = shell.promptCommon( | |
"In which package you'd like to create this @Entity, or enter for default:", | |
PromptType.JAVA_PACKAGE, scaffold.getEntityPackage()); | |
JavaClass javaClass = JavaParser.createClass() | |
.setPackage(entityPackage) | |
.setName(entityName) | |
.setPublic() | |
.addAnnotation(Entity.class) | |
.getOrigin(); | |
Field id = javaClass.addField("private long id = 0;"); | |
id.addAnnotation(Id.class); | |
id.addAnnotation(GeneratedValue.class) | |
.setEnumValue("strategy", GenerationType.AUTO); | |
id.addAnnotation(Column.class) | |
.setStringValue("name", "id") | |
.setLiteralValue("updatable", "false") | |
.setLiteralValue("nullable", "false"); | |
Field version = javaClass.addField("private int version = 0;"); | |
version.addAnnotation(Version.class); | |
version.addAnnotation(Column.class).setStringValue("name", "version"); | |
Refactory.createGetterAndSetter(javaClass, id); | |
Refactory.createGetterAndSetter(javaClass, version); | |
JavaResource javaFileLocation = java.saveJavaClass(javaClass); | |
shell.println("Created @Entity [" + javaClass.getQualifiedName() + "]"); | |
/** | |
* Pick up the generated resource. | |
*/ | |
shell.execute("pick-up " + javaFileLocation.getFullyQualifiedName()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, Home of Professional Open Source | |
* Copyright 2010, Red Hat, Inc., and individual contributors | |
* by the @authors tag. See the copyright.txt in the distribution for a | |
* full listing of individual contributors. | |
* | |
* This is free software; you can redistribute it and/or modify it | |
* under the terms of the GNU Lesser General Public License as | |
* published by the Free Software Foundation; either version 2.1 of | |
* the License, or (at your option) any later version. | |
* | |
* This software 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 | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this software; if not, write to the Free | |
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. | |
*/ | |
package org.jboss.seam.forge.persistence; | |
import java.io.FileNotFoundException; | |
import java.lang.annotation.Annotation; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Set; | |
import javax.enterprise.inject.Instance; | |
import javax.inject.Inject; | |
import javax.inject.Named; | |
import javax.persistence.Column; | |
import javax.persistence.ManyToMany; | |
import javax.persistence.ManyToOne; | |
import javax.persistence.OneToMany; | |
import javax.persistence.OneToOne; | |
import org.jboss.seam.forge.parser.java.Field; | |
import org.jboss.seam.forge.parser.java.JavaClass; | |
import org.jboss.seam.forge.parser.java.util.Refactory; | |
import org.jboss.seam.forge.parser.java.util.Types; | |
import org.jboss.seam.forge.project.Project; | |
import org.jboss.seam.forge.project.constraints.RequiresFacet; | |
import org.jboss.seam.forge.project.constraints.RequiresProject; | |
import org.jboss.seam.forge.project.facets.JavaSourceFacet; | |
import org.jboss.seam.forge.project.resources.builtin.JavaResource; | |
import org.jboss.seam.forge.shell.PromptType; | |
import org.jboss.seam.forge.shell.Shell; | |
import org.jboss.seam.forge.shell.plugins.Command; | |
import org.jboss.seam.forge.shell.plugins.DefaultCommand; | |
import org.jboss.seam.forge.shell.plugins.Help; | |
import org.jboss.seam.forge.shell.plugins.Option; | |
import org.jboss.seam.forge.shell.plugins.Plugin; | |
import org.jboss.seam.forge.shell.plugins.ResourceScope; | |
import org.jboss.seam.forge.shell.plugins.Topic; | |
/** | |
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> | |
*/ | |
@Named("new-field") | |
@Topic("File & Resources") | |
@RequiresProject | |
@RequiresFacet(PersistenceFacet.class) | |
@ResourceScope(JavaResource.class) | |
@Help("A plugin to manage simple @Entity and View creation; a basic MVC framework plugin.") | |
public class NewFieldPlugin implements Plugin | |
{ | |
private final Instance<Project> projectInstance; | |
private final Shell shell; | |
@Inject | |
public NewFieldPlugin(final Instance<Project> project, final Shell shell) | |
{ | |
this.projectInstance = project; | |
this.shell = shell; | |
} | |
@DefaultCommand(help = "Add many custom field to an existing @Entity class") | |
public void newExpressionField( | |
@Option(required = true, description = "The field descriptor") final String... fields) | |
{ | |
System.out.println(Arrays.asList(fields)); | |
} | |
@Command(value = "custom", help = "Add a custom field to an existing @Entity class") | |
public void newCustomField( | |
@Option(name = "fieldName", | |
required = true, | |
description = "The field name", | |
type = PromptType.JAVA_VARIABLE_NAME) final String fieldName, | |
@Option(name = "type", | |
required = true, | |
type = PromptType.JAVA_CLASS, | |
description = "The qualified Class to be used as this field's type") final String type | |
) | |
{ | |
try | |
{ | |
JavaClass entity = getJavaClass(); | |
addFieldTo(entity, type, fieldName, Column.class); | |
} | |
catch (FileNotFoundException e) | |
{ | |
shell.println("Could not locate the @Entity requested. No update was made."); | |
} | |
} | |
@Command(value = "boolean", help = "Add a boolean field to an existing @Entity class") | |
public void newBooleanField( | |
@Option(name = "fieldName", | |
required = true, | |
description = "The field name", | |
type = PromptType.JAVA_VARIABLE_NAME) final String fieldName, | |
@Option(name = "primitive", | |
required = false, | |
defaultValue = "true", | |
description = "Marks this field to be created as a primitive.", | |
type = PromptType.JAVA_VARIABLE_NAME) final boolean primitive) | |
{ | |
try | |
{ | |
JavaClass entity = getJavaClass(); | |
if (primitive) | |
{ | |
addFieldTo(entity, boolean.class, fieldName, Column.class); | |
} | |
else | |
{ | |
addFieldTo(entity, Boolean.class, fieldName, Column.class); | |
} | |
} | |
catch (FileNotFoundException e) | |
{ | |
shell.println("Could not locate the @Entity requested. No update was made."); | |
} | |
} | |
@Command(value = "int", help = "Add an int field to an existing @Entity class") | |
public void newIntField( | |
@Option(name = "fieldName", | |
required = true, | |
description = "The field name", | |
type = PromptType.JAVA_VARIABLE_NAME) final String fieldName, | |
@Option(name = "primitive", | |
required = false, | |
defaultValue = "true", | |
description = "Marks this field to be created as a primitive.", | |
type = PromptType.JAVA_VARIABLE_NAME) final boolean primitive) | |
{ | |
try | |
{ | |
JavaClass entity = getJavaClass(); | |
if (primitive) | |
{ | |
addFieldTo(entity, int.class, fieldName, Column.class); | |
} | |
else | |
{ | |
addFieldTo(entity, Integer.class, fieldName, Column.class); | |
} | |
} | |
catch (FileNotFoundException e) | |
{ | |
shell.println("Could not locate the @Entity requested. No update was made."); | |
} | |
} | |
@Command(value = "long", help = "Add a long field to an existing @Entity class") | |
public void newLongField( | |
@Option(name = "fieldName", | |
required = true, | |
description = "The field name", | |
type = PromptType.JAVA_VARIABLE_NAME) final String fieldName, | |
@Option(name = "primitive", | |
required = false, | |
defaultValue = "true", | |
description = "Marks this field to be created as a primitive.", | |
type = PromptType.JAVA_VARIABLE_NAME) final boolean primitive) | |
{ | |
try | |
{ | |
JavaClass entity = getJavaClass(); | |
if (primitive) | |
{ | |
addFieldTo(entity, long.class, fieldName, Column.class); | |
} | |
else | |
{ | |
addFieldTo(entity, Long.class, fieldName, Column.class); | |
} | |
} | |
catch (FileNotFoundException e) | |
{ | |
shell.println("Could not locate the @Entity requested. No update was made."); | |
} | |
} | |
@Command(value = "number", help = "Add a number field to an existing @Entity class") | |
public void newNumberField( | |
@Option(name = "fieldName", | |
required = true, | |
description = "The field name", | |
type = PromptType.JAVA_VARIABLE_NAME) final String fieldName, | |
@Option(name = "type", | |
required = true, | |
type = PromptType.JAVA_CLASS, | |
description = "The qualified Class to be used as this field's type") final String type) | |
{ | |
try | |
{ | |
JavaClass entity = getJavaClass(); | |
addFieldTo(entity, Class.forName(type), fieldName, Column.class); | |
} | |
catch (FileNotFoundException e) | |
{ | |
shell.println("Could not locate the @Entity requested. No update was made."); | |
} | |
catch (ClassNotFoundException e) | |
{ | |
shell.println("Sorry, I don't think [" + type | |
+ "] is a valid Java number type. Try something in the 'java.lang.* or java.math*' packages."); | |
} | |
} | |
@Command(value = "string", help = "Add a String field to an existing @Entity class") | |
public void newLongField( | |
@Option(name = "fieldName", | |
required = true, | |
description = "The field name", | |
type = PromptType.JAVA_VARIABLE_NAME) final String fieldName, | |
@Option(name = "addToClass", | |
required = false, | |
type = PromptType.JAVA_CLASS, | |
description = "The @Entity to which this field will be added") final String entityName) | |
{ | |
try | |
{ | |
JavaClass entity = getJavaClass(); | |
addFieldTo(entity, String.class, fieldName, Column.class); | |
} | |
catch (FileNotFoundException e) | |
{ | |
shell.println("Could not locate the @Entity requested. No update was made."); | |
} | |
} | |
@Command(value = "oneToOne", help = "Add a One-to-one relationship field to an existing @Entity class") | |
public void newOneToOneRelationship( | |
@Option(name = "fieldName", | |
required = true, | |
description = "The field name", | |
type = PromptType.JAVA_VARIABLE_NAME) final String fieldName, | |
@Option(name = "fieldType", | |
required = true, | |
description = "The @Entity type to which this field is a relationship", | |
type = PromptType.JAVA_CLASS) final String fieldType, | |
@Option(name = "inverseFieldName", | |
required = false, | |
description = "Create a bi-directional relationship, using this value as the name of the inverse field.", | |
type = PromptType.JAVA_VARIABLE_NAME) final String inverseFieldName) | |
{ | |
try | |
{ | |
JavaClass field = findEntity(fieldType); | |
JavaClass entity = getJavaClass(); | |
addFieldTo(entity, field, fieldName, OneToOne.class); | |
if ((inverseFieldName != null) && !inverseFieldName.isEmpty()) | |
{ | |
addFieldTo(field, entity, inverseFieldName, OneToOne.class); | |
} | |
} | |
catch (FileNotFoundException e) | |
{ | |
shell.println("Could not locate the @Entity requested. No update was made."); | |
} | |
} | |
@Command(value = "manyToMany", help = "Add a many-to-many relationship field (java.lang.Set<?>) to an existing @Entity class") | |
public void newManyToManyRelationship( | |
@Option(name = "fieldName", | |
required = true, | |
description = "The field name", | |
type = PromptType.JAVA_VARIABLE_NAME) final String fieldName, | |
@Option(name = "fieldType", | |
required = true, | |
description = "The @Entity type to which this field is a relationship", | |
type = PromptType.JAVA_CLASS) final String fieldType, | |
@Option(name = "inverseFieldName", | |
required = false, | |
description = "Create an bi-directional relationship, using this value as the name of the inverse field.", | |
type = PromptType.JAVA_VARIABLE_NAME) final String inverseFieldName) | |
{ | |
Project project = getCurrentProject(); | |
JavaSourceFacet java = project.getFacet(JavaSourceFacet.class); | |
try | |
{ | |
JavaClass entity = getJavaClass(); | |
JavaClass otherEntity = findEntity(fieldType); | |
entity.addImport(Set.class); | |
entity.addImport(HashSet.class); | |
entity.addImport(otherEntity.getQualifiedName()); | |
Field field = entity.addField("private Set<" + otherEntity.getName() + "> " + fieldName + "= new HashSet<" | |
+ otherEntity.getName() + ">();"); | |
org.jboss.seam.forge.parser.java.Annotation annotation = field.addAnnotation(ManyToMany.class); | |
Refactory.createGetterAndSetter(entity, field); | |
if ((inverseFieldName != null) && !inverseFieldName.isEmpty()) | |
{ | |
annotation.setStringValue("mappedBy", inverseFieldName); | |
otherEntity.addImport(Set.class); | |
otherEntity.addImport(HashSet.class); | |
otherEntity.addImport(entity.getQualifiedName()); | |
Field otherField = otherEntity.addField("private Set<" + entity.getName() + "> " + inverseFieldName | |
+ "= new HashSet<" + entity.getName() + ">();"); | |
otherField.addAnnotation(ManyToMany.class); | |
Refactory.createGetterAndSetter(otherEntity, otherField); | |
java.saveJavaClass(otherEntity); | |
} | |
java.saveJavaClass(entity); | |
} | |
catch (FileNotFoundException e) | |
{ | |
shell.println("Could not locate the @Entity requested. No update was made."); | |
} | |
} | |
@Command(value = "oneToMany", help = "Add a one-to-many relationship field (java.lang.Set<?>) to an existing @Entity class") | |
public void newOneToManyRelationship( | |
@Option(name = "fieldName", | |
required = true, | |
description = "The field name", | |
type = PromptType.JAVA_VARIABLE_NAME) final String fieldName, | |
@Option(name = "fieldType", | |
required = true, | |
description = "The @Entity representing the 'many' side of the relationship.", | |
type = PromptType.JAVA_CLASS) final String fieldType, | |
@Option(name = "inverseFieldName", | |
required = false, | |
description = "Create an bi-directional relationship, using this value as the name of the inverse field.", | |
type = PromptType.JAVA_VARIABLE_NAME) final String inverseFieldName) | |
{ | |
Project project = getCurrentProject(); | |
JavaSourceFacet java = project.getFacet(JavaSourceFacet.class); | |
try | |
{ | |
JavaClass entity = getJavaClass(); | |
JavaClass otherEntity = findEntity(fieldType); | |
entity.addImport(Set.class); | |
entity.addImport(HashSet.class); | |
entity.addImport(otherEntity.getQualifiedName()); | |
Field field = entity.addField("private Set<" + otherEntity.getName() + "> " + fieldName + "= new HashSet<" | |
+ otherEntity.getName() + ">();"); | |
org.jboss.seam.forge.parser.java.Annotation annotation = field.addAnnotation(OneToMany.class); | |
Refactory.createGetterAndSetter(entity, field); | |
if ((inverseFieldName != null) && !inverseFieldName.isEmpty()) | |
{ | |
annotation.setStringValue("mappedBy", inverseFieldName); | |
otherEntity.addImport(Set.class); | |
otherEntity.addImport(HashSet.class); | |
otherEntity.addImport(entity.getQualifiedName()); | |
otherEntity.addField("private Set<" + entity.getName() + "> " + inverseFieldName | |
+ "= new HashSet<" + entity.getName() + ">();") | |
.addAnnotation(ManyToOne.class); | |
java.saveJavaClass(otherEntity); | |
} | |
java.saveJavaClass(entity); | |
} | |
catch (FileNotFoundException e) | |
{ | |
shell.println("Could not locate the @Entity requested. No update was made."); | |
} | |
} | |
/* | |
* Helpers | |
*/ | |
private void addFieldTo(final JavaClass targetEntity, final JavaClass fieldEntity, final String fieldName, | |
final Class<? extends Annotation> annotation) throws FileNotFoundException | |
{ | |
Project project = getCurrentProject(); | |
JavaSourceFacet java = project.getFacet(JavaSourceFacet.class); | |
Field field = targetEntity.addField(); | |
field.setName(fieldName).setPrivate().setType(fieldEntity.getName()).addAnnotation(annotation); | |
targetEntity.addImport(fieldEntity.getQualifiedName()); | |
Refactory.createGetterAndSetter(targetEntity, field); | |
java.saveJavaClass(targetEntity); | |
shell.println("Added field to " + targetEntity.getQualifiedName() + ": " + field); | |
} | |
private void addFieldTo(final JavaClass targetEntity, final String fieldType, final String fieldName, | |
final Class<Column> annotation) throws FileNotFoundException | |
{ | |
Project project = getCurrentProject(); | |
JavaSourceFacet java = project.getFacet(JavaSourceFacet.class); | |
Field field = targetEntity.addField(); | |
field.setName(fieldName).setPrivate().setType(Types.toSimpleName(fieldType)).addAnnotation(annotation); | |
targetEntity.addImport(fieldType); | |
Refactory.createGetterAndSetter(targetEntity, field); | |
java.saveJavaClass(targetEntity); | |
shell.println("Added field to " + targetEntity.getQualifiedName() + ": " + field); | |
} | |
private void addFieldTo(final JavaClass targetEntity, final Class<?> fieldType, final String fieldName, | |
final Class<? extends Annotation> annotation) throws FileNotFoundException | |
{ | |
Project project = getCurrentProject(); | |
JavaSourceFacet java = project.getFacet(JavaSourceFacet.class); | |
Field field = targetEntity.addField(); | |
field.setName(fieldName).setPrivate().setType(fieldType).addAnnotation(annotation); | |
if (!fieldType.getName().startsWith("java.lang.") && !fieldType.isPrimitive()) | |
{ | |
targetEntity.addImport(fieldType); | |
} | |
Refactory.createGetterAndSetter(targetEntity, field); | |
java.saveJavaClass(targetEntity); | |
shell.println("Added field to " + targetEntity.getQualifiedName() + ": " + field); | |
} | |
public Project getCurrentProject() | |
{ | |
return projectInstance.get(); | |
} | |
private JavaClass getJavaClass() throws FileNotFoundException | |
{ | |
if (shell.getCurrentResource() instanceof JavaResource) | |
{ | |
return ((JavaResource) shell.getCurrentResource()).getJavaClass(); | |
} | |
else | |
{ | |
throw new RuntimeException("current resource is not a JavaResource!"); | |
} | |
} | |
private JavaClass findEntity(final String entity) throws FileNotFoundException | |
{ | |
JavaClass result = null; | |
Project project = getCurrentProject(); | |
PersistenceFacet scaffold = project.getFacet(PersistenceFacet.class); | |
JavaSourceFacet java = project.getFacet(JavaSourceFacet.class); | |
if (entity != null) | |
{ | |
result = java.getJavaResource(entity).getJavaClass(); | |
if (result == null) | |
{ | |
result = java.getJavaResource(scaffold.getEntityPackage() + "." + entity).getJavaClass(); | |
} | |
} | |
if (result == null) | |
{ | |
result = promptForEntity(); | |
} | |
if (result == null) | |
{ | |
throw new FileNotFoundException("Could not locate JavaClass on which to operate."); | |
} | |
return result; | |
} | |
private JavaClass promptForEntity() | |
{ | |
Project project = getCurrentProject(); | |
PersistenceFacet scaffold = project.getFacet(PersistenceFacet.class); | |
List<JavaClass> entities = scaffold.getAllEntities(); | |
List<String> entityNames = new ArrayList<String>(); | |
for (JavaClass javaClass : entities) | |
{ | |
String fullName = javaClass.getPackage(); | |
if (!fullName.isEmpty()) | |
{ | |
fullName += "."; | |
} | |
fullName += javaClass.getName(); | |
entityNames.add(fullName); | |
} | |
if (!entityNames.isEmpty()) | |
{ | |
int index = shell.promptChoice("Which entity would you like to modify?", entityNames); | |
return entities.get(index); | |
} | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, Home of Professional Open Source | |
* Copyright 2010, Red Hat, Inc., and individual contributors | |
* by the @authors tag. See the copyright.txt in the distribution for a | |
* full listing of individual contributors. | |
* | |
* This is free software; you can redistribute it and/or modify it | |
* under the terms of the GNU Lesser General Public License as | |
* published by the Free Software Foundation; either version 2.1 of | |
* the License, or (at your option) any later version. | |
* | |
* This software 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 | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this software; if not, write to the Free | |
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. | |
*/ | |
package org.jboss.seam.forge.persistence; | |
import java.io.File; | |
import java.io.FileNotFoundException; | |
import java.util.ArrayList; | |
import java.util.List; | |
import javax.inject.Named; | |
import javax.persistence.Entity; | |
import org.jboss.seam.forge.parser.JavaParser; | |
import org.jboss.seam.forge.parser.java.JavaClass; | |
import org.jboss.seam.forge.project.Facet; | |
import org.jboss.seam.forge.project.PackagingType; | |
import org.jboss.seam.forge.project.Project; | |
import org.jboss.seam.forge.project.Resource; | |
import org.jboss.seam.forge.project.constraints.RequiresFacets; | |
import org.jboss.seam.forge.project.constraints.RequiresPackagingTypes; | |
import org.jboss.seam.forge.project.dependencies.Dependency; | |
import org.jboss.seam.forge.project.dependencies.DependencyBuilder; | |
import org.jboss.seam.forge.project.facets.DependencyFacet; | |
import org.jboss.seam.forge.project.facets.JavaSourceFacet; | |
import org.jboss.seam.forge.project.facets.ResourceFacet; | |
import org.jboss.seam.forge.project.resources.FileResource; | |
import org.jboss.seam.forge.project.resources.builtin.DirectoryResource; | |
import org.jboss.seam.forge.project.resources.builtin.JavaResource; | |
import org.jboss.shrinkwrap.descriptor.api.DescriptorImporter; | |
import org.jboss.shrinkwrap.descriptor.api.Descriptors; | |
import org.jboss.shrinkwrap.descriptor.api.spec.jpa.persistence.PersistenceDescriptor; | |
import org.jboss.shrinkwrap.descriptor.api.spec.jpa.persistence.PersistenceUnitDef; | |
import org.jboss.shrinkwrap.descriptor.api.spec.jpa.persistence.ProviderType; | |
import org.jboss.shrinkwrap.descriptor.api.spec.jpa.persistence.SchemaGenerationModeType; | |
import org.jboss.shrinkwrap.descriptor.api.spec.jpa.persistence.TransactionType; | |
import org.jboss.shrinkwrap.descriptor.impl.spec.jpa.persistence.PersistenceDescriptorImpl; | |
import org.jboss.shrinkwrap.descriptor.impl.spec.jpa.persistence.PersistenceModel; | |
import org.jboss.shrinkwrap.descriptor.spi.SchemaDescriptorProvider; | |
/** | |
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> | |
*/ | |
@Named("persistence") | |
@RequiresFacets({ JavaSourceFacet.class, ResourceFacet.class, DependencyFacet.class }) | |
@RequiresPackagingTypes({ PackagingType.JAR, PackagingType.WAR }) | |
public class PersistenceFacet implements Facet | |
{ | |
private static final Dependency dep = | |
DependencyBuilder.create("org.jboss.spec:jboss-javaee-6.0:1.0.0.CR1:provided:basic"); | |
private Project project; | |
@Override | |
public Project getProject() | |
{ | |
return project; | |
} | |
@Override | |
public void setProject(final Project project) | |
{ | |
this.project = project; | |
} | |
@Override | |
public Facet install() | |
{ | |
if (!isInstalled()) | |
{ | |
DependencyFacet deps = project.getFacet(DependencyFacet.class); | |
if (!deps.hasDependency(dep)) | |
{ | |
deps.addDependency(dep); | |
} | |
DirectoryResource entityRoot = getEntityPackageFile(); | |
if (!entityRoot.exists()) | |
{ | |
entityRoot.mkdirs(); | |
} | |
installUtils(); | |
FileResource<?> descriptor = getConfigFile(); | |
if (!descriptor.exists()) | |
{ | |
PersistenceUnitDef unit = Descriptors.create(PersistenceDescriptor.class) | |
.persistenceUnit("default") | |
.description("The Seam Forge default Persistence Unit") | |
.transactionType(TransactionType.JTA) | |
.provider(ProviderType.HIBERNATE) | |
.jtaDataSource("java:/DefaultDS") | |
.includeUnlistedClasses() | |
.schemaGenerationMode(SchemaGenerationModeType.CREATE_DROP) | |
.showSql() | |
.formatSql() | |
.property("hibernate.transaction.flush_before_completion", true); | |
descriptor.setContents(unit.exportAsString()); | |
} | |
} | |
project.registerFacet(this); | |
return this; | |
} | |
private void installUtils() | |
{ | |
ClassLoader loader = Thread.currentThread().getContextClassLoader(); | |
JavaClass util = JavaParser.parse(loader.getResourceAsStream("templates/PersistenceUtil.java")); | |
JavaClass producer = JavaParser.parse(loader.getResourceAsStream("templates/DatasourceProducer.java")); | |
JavaSourceFacet java = project.getFacet(JavaSourceFacet.class); | |
util.setPackage(java.getBasePackage() + ".persist"); | |
producer.setPackage(java.getBasePackage() + ".persist"); | |
try | |
{ | |
java.saveJavaClass(producer); | |
java.saveJavaClass(util); | |
} | |
catch (FileNotFoundException e) | |
{ | |
throw new RuntimeException(e); | |
} | |
} | |
@Override | |
public boolean isInstalled() | |
{ | |
DependencyFacet deps = project.getFacet(DependencyFacet.class); | |
boolean hasDependency = deps.hasDependency(dep); | |
return hasDependency && getEntityPackageFile().exists() && getConfigFile().exists(); | |
} | |
public String getEntityPackage() | |
{ | |
JavaSourceFacet sourceFacet = project.getFacet(JavaSourceFacet.class); | |
return sourceFacet.getBasePackage() + ".domain"; | |
} | |
public DirectoryResource getEntityPackageFile() | |
{ | |
JavaSourceFacet sourceFacet = project.getFacet(JavaSourceFacet.class); | |
return (DirectoryResource) sourceFacet.getBasePackageResource().getChildDirectory("domain"); | |
} | |
@SuppressWarnings("unchecked") | |
public PersistenceModel getConfig() | |
{ | |
DescriptorImporter<PersistenceDescriptor> importer = Descriptors.importAs(PersistenceDescriptor.class); | |
PersistenceDescriptor descriptor = importer.from(getConfigFile().getResourceInputStream()); | |
PersistenceModel model = ((SchemaDescriptorProvider<PersistenceModel>) descriptor).getSchemaModel(); | |
return model; | |
} | |
public void saveConfig(final PersistenceModel model) | |
{ | |
PersistenceDescriptor descriptor = new PersistenceDescriptorImpl(model); | |
String output = descriptor.exportAsString(); | |
getConfigFile().setContents(output); | |
} | |
private FileResource<?> getConfigFile() | |
{ | |
ResourceFacet resources = project.getFacet(ResourceFacet.class); | |
return (FileResource<?>) resources.getResourceFolder().getChild("META-INF" + File.separator + "persistence.xml"); | |
} | |
public List<JavaClass> getAllEntities() | |
{ | |
DirectoryResource packageFile = getEntityPackageFile(); | |
return findEntitiesInFolder(packageFile); | |
} | |
private List<JavaClass> findEntitiesInFolder(final DirectoryResource packageFile) | |
{ | |
List<JavaClass> result = new ArrayList<JavaClass>(); | |
if (packageFile.exists()) | |
{ | |
for (Resource<?> source : packageFile.listResources()) | |
{ | |
if (source instanceof JavaResource) | |
{ | |
try | |
{ | |
JavaClass javaClass = ((JavaResource) source).getJavaClass(); | |
if (javaClass.hasAnnotation(Entity.class)) | |
{ | |
result.add(javaClass); | |
} | |
} | |
catch (FileNotFoundException e) | |
{ | |
throw new IllegalStateException(e); | |
} | |
} | |
} | |
for (Resource<?> source : packageFile.listResources()) | |
{ | |
if (source instanceof DirectoryResource) | |
{ | |
List<JavaClass> subResults = findEntitiesInFolder((DirectoryResource) source); | |
result.addAll(subResults); | |
} | |
} | |
} | |
return result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, by Red Hat. | |
* Copyright 2010, Red Hat, Inc., and individual contributors | |
* by the @authors tag. See the copyright.txt in the distribution for a | |
* full listing of individual contributors. | |
* | |
* This is free software; you can redistribute it and/or modify it | |
* under the terms of the GNU Lesser General Public License as | |
* published by the Free Software Foundation; either version 2.1 of | |
* the License, or (at your option) any later version. | |
* | |
* This software 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 | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with this software; if not, write to the Free | |
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. | |
*/ | |
package org.jboss.seam.forge.shell.plugins; | |
/** | |
* A custom {@link Plugin} must implement this interface in order to be detected and installed at framework boot-time. | |
* In order to create plugin shell-commands, one must create a method annotated with @{@link Command}. Any command | |
* method parameters to be provided as input through the shell must be individually annotated with the @{@link Option} | |
* annotation; other (non-annotated) command parameters are ignored. | |
* | |
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a> | |
* | |
*/ | |
public interface Plugin | |
{ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment