diff --git a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/FacesScaffold.java b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/FacesScaffold.java
index 445e09b771..a381e69289 100644
--- a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/FacesScaffold.java
+++ b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/FacesScaffold.java
@@ -1,825 +1,787 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2011, 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.forge.scaffold.faces;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.enterprise.event.Event;
-import javax.inject.Inject;
-import javax.persistence.CascadeType;
-import javax.persistence.OneToOne;
-
-import org.jboss.forge.env.Configuration;
-import org.jboss.forge.parser.JavaParser;
-import org.jboss.forge.parser.java.Annotation;
-import org.jboss.forge.parser.java.Field;
-import org.jboss.forge.parser.java.JavaClass;
-import org.jboss.forge.parser.java.Method;
-import org.jboss.forge.parser.xml.Node;
-import org.jboss.forge.parser.xml.XMLParser;
-import org.jboss.forge.project.Project;
-import org.jboss.forge.project.dependencies.Dependency;
-import org.jboss.forge.project.dependencies.DependencyBuilder;
-import org.jboss.forge.project.facets.BaseFacet;
-import org.jboss.forge.project.facets.DependencyFacet;
-import org.jboss.forge.project.facets.JavaSourceFacet;
-import org.jboss.forge.project.facets.WebResourceFacet;
-import org.jboss.forge.project.facets.events.InstallFacets;
-import org.jboss.forge.resources.FileResource;
-import org.jboss.forge.resources.Resource;
-import org.jboss.forge.scaffold.AccessStrategy;
-import org.jboss.forge.scaffold.ScaffoldProvider;
-import org.jboss.forge.scaffold.TemplateStrategy;
-import org.jboss.forge.scaffold.faces.metawidget.config.ForgeConfigReader;
-import org.jboss.forge.scaffold.util.ScaffoldUtil;
-import org.jboss.forge.shell.ShellPrompt;
-import org.jboss.forge.shell.plugins.Alias;
-import org.jboss.forge.shell.plugins.RequiresFacet;
-import org.jboss.forge.shell.util.Streams;
-import org.jboss.forge.spec.javaee.CDIFacet;
-import org.jboss.forge.spec.javaee.EJBFacet;
-import org.jboss.forge.spec.javaee.FacesAPIFacet;
-import org.jboss.forge.spec.javaee.FacesFacet;
-import org.jboss.forge.spec.javaee.PersistenceFacet;
-import org.jboss.forge.spec.javaee.ServletFacet;
-import org.jboss.seam.render.TemplateCompiler;
-import org.jboss.seam.render.spi.TemplateResolver;
-import org.jboss.seam.render.template.CompiledTemplateResource;
-import org.jboss.seam.render.template.resolver.ClassLoaderTemplateResolver;
-import org.jboss.shrinkwrap.descriptor.api.spec.servlet.web.WebAppDescriptor;
-import org.metawidget.statically.StaticMetawidget;
-import org.metawidget.statically.StaticUtils.IndentedWriter;
-import org.metawidget.statically.StaticWidget;
-import org.metawidget.statically.faces.StaticFacesUtils;
-import org.metawidget.statically.faces.component.html.StaticHtmlMetawidget;
-import org.metawidget.statically.faces.component.html.widgetbuilder.HtmlOutcomeTargetLink;
-import org.metawidget.statically.faces.component.html.widgetbuilder.ReadOnlyWidgetBuilder;
-import org.metawidget.statically.faces.component.html.widgetbuilder.richfaces.RichFacesWidgetBuilder;
-import org.metawidget.statically.html.widgetbuilder.HtmlTag;
-import org.metawidget.statically.javacode.StaticJavaMetawidget;
-import org.metawidget.util.ArrayUtils;
-import org.metawidget.util.CollectionUtils;
-import org.metawidget.util.XmlUtils;
-import org.metawidget.util.simple.StringUtils;
-import org.metawidget.widgetbuilder.composite.CompositeWidgetBuilder;
-import org.metawidget.widgetbuilder.composite.CompositeWidgetBuilderConfig;
-import org.metawidget.widgetbuilder.iface.WidgetBuilder;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-
-/**
- * Facet to generate a Java Server Faces UI.
- *
- * This facet utilizes Metawidget internally. This enables the use of the Metawidget
- * SPI (pluggable WidgetBuilders, Layouts etc) for customizing the generated User Interface. For more information on
- * writing Metawidget plugins, see the Metawidget documentation .
- *
- * This Facet does not require Metawidget to be in the final project.
- *
- * @author Lincoln Baxter, III
- * @author Richard Kennard
- */
-
-@Alias("faces")
-@RequiresFacet({ WebResourceFacet.class,
- DependencyFacet.class,
- PersistenceFacet.class,
- EJBFacet.class,
- CDIFacet.class,
- FacesAPIFacet.class })
-public class FacesScaffold extends BaseFacet implements ScaffoldProvider
-{
- //
- // Private statics
- //
-
- private static final String XMLNS_PREFIX = "xmlns:";
-
- private static final String BACKING_BEAN_TEMPLATE = "scaffold/faces/BackingBean.jv";
- private static final String VIEW_UTILS_TEMPLATE = "scaffold/faces/ViewUtils.jv";
- private static final String TAGLIB_TEMPLATE = "scaffold/faces/forge.taglib.xml";
- private static final String VIEW_TEMPLATE = "scaffold/faces/view.xhtml";
- private static final String CREATE_TEMPLATE = "scaffold/faces/create.xhtml";
- private static final String SEARCH_TEMPLATE = "scaffold/faces/search.xhtml";
- private static final String NAVIGATION_TEMPLATE = "scaffold/faces/page.xhtml";
-
- private static final String ERROR_TEMPLATE = "scaffold/faces/error.xhtml";
- private static final String INDEX_TEMPLATE = "scaffold/faces/index.xhtml";
-
- private final Dependency richfaces3UI = DependencyBuilder.create("org.richfaces.ui:richfaces-ui");
- private final Dependency richfaces3Impl = DependencyBuilder.create("org.richfaces.framework:richfaces-impl");
- private final Dependency richfaces4UI = DependencyBuilder.create("org.richfaces.ui:richfaces-components-ui");
- private final Dependency richfaces4Impl = DependencyBuilder.create("org.richfaces.core:richfaces-core-impl");
-
- //
- // Protected members (nothing is private, to help subclassing)
- //
-
- protected CompiledTemplateResource backingBeanTemplate;
- protected int backingBeanTemplateQbeMetawidgetIndent;
-
- protected CompiledTemplateResource viewUtilsTemplate;
- protected CompiledTemplateResource taglibTemplate;
- protected CompiledTemplateResource viewTemplate;
- protected Map viewTemplateNamespaces;
- protected int viewTemplateEntityMetawidgetIndent;
-
- protected CompiledTemplateResource createTemplate;
- protected Map createTemplateNamespaces;
- protected int createTemplateEntityMetawidgetIndent;
-
- protected CompiledTemplateResource searchTemplate;
- protected Map searchTemplateNamespaces;
- protected int searchTemplateSearchMetawidgetIndent;
- protected int searchTemplateBeanMetawidgetIndent;
-
- protected CompiledTemplateResource navigationTemplate;
- protected int navigationTemplateIndent;
-
- protected CompiledTemplateResource errorTemplate;
- protected CompiledTemplateResource indexTemplate;
- protected TemplateResolver resolver;
-
- protected final ShellPrompt prompt;
- protected final TemplateCompiler compiler;
- protected final Event install;
- protected StaticHtmlMetawidget entityMetawidget;
- protected StaticHtmlMetawidget searchMetawidget;
- protected StaticHtmlMetawidget beanMetawidget;
- protected StaticJavaMetawidget qbeMetawidget;
-
- private Configuration config;
-
- //
- // Constructor
- //
-
- @Inject
- public FacesScaffold(final Configuration config,
- final ShellPrompt prompt,
- final TemplateCompiler compiler,
- final Event install)
- {
- this.config = config;
- this.prompt = prompt;
- this.compiler = compiler;
- this.install = install;
-
- this.resolver = new ClassLoaderTemplateResolver(FacesScaffold.class.getClassLoader());
-
- if (this.compiler != null)
- {
- this.compiler.getTemplateResolverFactory().addResolver(this.resolver);
- }
- }
-
- //
- // Public methods
- //
-
- @Override
- public List> setup(String targetDir, final Resource> template, final boolean overwrite)
- {
- List> resources = generateIndex(targetDir, template, overwrite);
- setupWebXML();
-
- return resources;
- }
-
- /**
- * Overridden to setup the Metawidgets.
- *
- * Metawidgets must be configured per project and per Forge invocation . It is not sufficient to simply
- * configure them in setup
because the user may restart Forge and not run scaffold setup
a
- * second time.
- */
-
- @Override
- public void setProject(Project project)
- {
- super.setProject(project);
-
- ForgeConfigReader configReader = new ForgeConfigReader(this.config, this.project);
-
- this.entityMetawidget = new StaticHtmlMetawidget();
- this.entityMetawidget.setConfigReader(configReader);
- this.entityMetawidget.setConfig("scaffold/faces/metawidget-entity.xml");
-
- this.searchMetawidget = new StaticHtmlMetawidget();
- this.searchMetawidget.setConfigReader(configReader);
- this.searchMetawidget.setConfig("scaffold/faces/metawidget-search.xml");
-
- this.beanMetawidget = new StaticHtmlMetawidget();
- this.beanMetawidget.setConfigReader(configReader);
- this.beanMetawidget.setConfig("scaffold/faces/metawidget-bean.xml");
-
- this.qbeMetawidget = new StaticJavaMetawidget();
- this.qbeMetawidget.setConfigReader(configReader);
- this.qbeMetawidget.setConfig("scaffold/faces/metawidget-qbe.xml");
- }
-
- @Override
- public List> generateFromEntity(String targetDir, final Resource> template, final JavaClass entity,
- final boolean overwrite)
- {
- // FORGE-460: setupRichFaces during generateFromEntity, not during setup, as generally 'richfaces setup' is called
- // *after* 'scaffold setup'
-
- setupRichFaces();
-
- // Track the list of resources generated
-
- List> result = new ArrayList>();
- try
- {
- JavaSourceFacet java = this.project.getFacet(JavaSourceFacet.class);
- WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
-
- loadTemplates();
- Map context = CollectionUtils.newHashMap();
- context.put("entity", entity);
- String ccEntity = StringUtils.decapitalize(entity.getName());
- context.put("ccEntity", ccEntity);
-
- // Prepare qbeMetawidget
- this.qbeMetawidget.setPath(entity.getQualifiedName());
- StringWriter stringWriter = new StringWriter();
- this.qbeMetawidget.write(stringWriter, this.backingBeanTemplateQbeMetawidgetIndent);
- context.put("qbeMetawidget", stringWriter.toString().trim());
- context.put("qbeMetawidgetImports",
- CollectionUtils.toString(this.qbeMetawidget.getImports(), ";\r\nimport ", true, false));
-
- // Create the Backing Bean for this entity
- JavaClass viewBean = JavaParser.parse(JavaClass.class, this.backingBeanTemplate.render(context));
- viewBean.setPackage(java.getBasePackage() + ".view");
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, java.getJavaResource(viewBean), viewBean.toString(),
- overwrite));
-
- // Set new context for view generation
- context = getTemplateContext(template);
- String beanName = StringUtils.decapitalize(viewBean.getName());
- context.put("beanName", beanName);
- context.put("ccEntity", ccEntity);
- context.put("entityName", StringUtils.uncamelCase(entity.getName()));
-
- // Prepare entityMetawidget
- this.entityMetawidget.setValue(StaticFacesUtils.wrapExpression(beanName + "." + ccEntity));
- this.entityMetawidget.setPath(entity.getQualifiedName());
- this.entityMetawidget.setReadOnly(false);
- this.entityMetawidget.setStyle(null);
-
- // Generate create
- writeEntityMetawidget(context, this.createTemplateEntityMetawidgetIndent, this.createTemplateNamespaces);
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
- web.getWebResource(targetDir + "/" + ccEntity + "/create.xhtml"),
- this.createTemplate.render(context),
- overwrite));
-
- // Generate view
- this.entityMetawidget.setReadOnly(true);
- writeEntityMetawidget(context, this.viewTemplateEntityMetawidgetIndent, this.viewTemplateNamespaces);
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
- web.getWebResource(targetDir + "/" + ccEntity + "/view.xhtml"),
- this.viewTemplate.render(context), overwrite));
-
- // Generate search
- this.searchMetawidget.setValue(StaticFacesUtils.wrapExpression(beanName + ".search"));
- this.searchMetawidget.setPath(entity.getQualifiedName());
- this.beanMetawidget.setValue(StaticFacesUtils.wrapExpression(beanName + ".pageItems"));
- this.beanMetawidget.setPath(viewBean.getQualifiedName() + "/pageItems");
- writeSearchAndBeanMetawidget(context, this.searchTemplateSearchMetawidgetIndent,
- this.searchTemplateBeanMetawidgetIndent, this.searchTemplateNamespaces);
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
- web.getWebResource(targetDir + "/" + ccEntity + "/search.xhtml"),
- this.searchTemplate.render(context), overwrite));
-
- // Generate navigation
- result.add(generateNavigation(targetDir, overwrite));
-
- // Need ViewUtils and forge.taglib.xml for forgeview:asList
- JavaClass viewUtils = JavaParser.parse(JavaClass.class, this.viewUtilsTemplate.render(context));
- viewUtils.setPackage(viewBean.getPackage());
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, java.getJavaResource(viewUtils), viewUtils.toString(),
- true));
-
- context.put("viewPackage", viewBean.getPackage());
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
- web.getWebResource("WEB-INF/classes/META-INF/forge.taglib.xml"),
- this.taglibTemplate.render(context), true));
-
- createInitializers(entity);
- this.project.getFacet(JavaSourceFacet.class).saveJavaSource(entity);
-
- }
- catch (Exception e)
- {
- throw new RuntimeException("Error generating default scaffolding: " + e.getMessage(), e);
- }
- return result;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public boolean install()
- {
- if (!(this.project.hasFacet(WebResourceFacet.class) && this.project.hasFacet(PersistenceFacet.class)
- && this.project.hasFacet(CDIFacet.class) && this.project.hasFacet(FacesFacet.class)))
- {
- this.install.fire(new InstallFacets(WebResourceFacet.class, PersistenceFacet.class, CDIFacet.class,
- FacesFacet.class));
- }
-
- return true;
- }
-
- @Override
- public boolean isInstalled()
- {
- return true;
- }
-
- @Override
- public List> generateIndex(String targetDir, final Resource> template, final boolean overwrite)
- {
- List> result = new ArrayList>();
- WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
-
- this.project.getFacet(ServletFacet.class).getConfig().welcomeFile("/index.html");
- loadTemplates();
-
- generateTemplates(targetDir, overwrite);
- HashMap context = getTemplateContext(template);
-
- // Basic pages
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/index.html"), getClass()
- .getResourceAsStream("/scaffold/faces/index.html"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/index.xhtml"),
- this.indexTemplate.render(context), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("error.xhtml"),
- this.errorTemplate.render(context), overwrite));
-
- // Static resources
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/add.png"),
- getClass().getResourceAsStream("/scaffold/faces/add.png"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/background.gif"),
- getClass().getResourceAsStream("/scaffold/faces/background.gif"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/false.png"),
- getClass().getResourceAsStream("/scaffold/faces/false.png"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/favicon.ico"),
- getClass().getResourceAsStream("/scaffold/faces/favicon.ico"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/forge-logo.png"),
- getClass().getResourceAsStream("/scaffold/faces/forge-logo.png"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/forge-style.css"),
- getClass().getResourceAsStream("/scaffold/faces/forge-style.css"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/jboss-community.png"),
- getClass().getResourceAsStream("/scaffold/faces/jboss-community.png"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/remove.png"),
- getClass().getResourceAsStream("/scaffold/faces/remove.png"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/search.png"),
- getClass().getResourceAsStream("/scaffold/faces/search.png"), overwrite));
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/true.png"),
- getClass().getResourceAsStream("/scaffold/faces/true.png"), overwrite));
-
- return result;
- }
-
- @Override
- public List> getGeneratedResources(String targetDir)
- {
- throw new RuntimeException("Not yet implemented!");
- }
-
- @Override
- public AccessStrategy getAccessStrategy()
- {
- return new FacesAccessStrategy(this.project);
- }
-
- @Override
- public TemplateStrategy getTemplateStrategy()
- {
- return new FacesTemplateStrategy(this.project);
- }
-
- @Override
- public List> generateTemplates(String targetDir, final boolean overwrite)
- {
- List> result = new ArrayList>();
-
- try
- {
- WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
-
- result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
- web.getWebResource("/resources/scaffold/paginator.xhtml"),
- getClass().getResourceAsStream("/scaffold/faces/paginator.xhtml"),
- overwrite));
-
- result.add(generateNavigation(targetDir, overwrite));
- }
- catch (Exception e)
- {
- throw new RuntimeException("Error generating default templates", e);
- }
-
- return result;
- }
-
- //
- // Protected methods (nothing is private, to help subclassing)
- //
-
- protected void loadTemplates()
- {
- if (this.backingBeanTemplate == null)
- {
- this.backingBeanTemplate = this.compiler.compile(BACKING_BEAN_TEMPLATE);
- String template = Streams.toString(this.backingBeanTemplate.getSourceTemplateResource().getInputStream());
- this.backingBeanTemplateQbeMetawidgetIndent = parseIndent(template, "@{qbeMetawidget}");
- }
- if (this.viewUtilsTemplate == null)
- {
- this.viewUtilsTemplate = this.compiler.compile(VIEW_UTILS_TEMPLATE);
- }
- if (this.taglibTemplate == null)
- {
- this.taglibTemplate = this.compiler.compile(TAGLIB_TEMPLATE);
- }
- if (this.viewTemplate == null)
- {
- this.viewTemplate = this.compiler.compile(VIEW_TEMPLATE);
- String template = Streams.toString(this.viewTemplate.getSourceTemplateResource().getInputStream());
- this.viewTemplateNamespaces = parseNamespaces(template);
- this.viewTemplateEntityMetawidgetIndent = parseIndent(template, "@{metawidget}");
- }
- if (this.createTemplate == null)
- {
- this.createTemplate = this.compiler.compile(CREATE_TEMPLATE);
- String template = Streams.toString(this.createTemplate.getSourceTemplateResource().getInputStream());
- this.createTemplateNamespaces = parseNamespaces(template);
- this.createTemplateEntityMetawidgetIndent = parseIndent(template, "@{metawidget}");
- }
- if (this.searchTemplate == null)
- {
- this.searchTemplate = this.compiler.compile(SEARCH_TEMPLATE);
- String template = Streams.toString(this.searchTemplate.getSourceTemplateResource().getInputStream());
- this.searchTemplateNamespaces = parseNamespaces(template);
- this.searchTemplateSearchMetawidgetIndent = parseIndent(template, "@{searchMetawidget}");
- this.searchTemplateBeanMetawidgetIndent = parseIndent(template, "@{beanMetawidget}");
- }
- if (this.navigationTemplate == null)
- {
- this.navigationTemplate = this.compiler.compile(NAVIGATION_TEMPLATE);
- String template = Streams.toString(this.navigationTemplate.getSourceTemplateResource().getInputStream());
- this.navigationTemplateIndent = parseIndent(template, "@{navigation}");
- }
- if (this.errorTemplate == null)
- {
- this.errorTemplate = this.compiler.compile(ERROR_TEMPLATE);
- }
- if (this.indexTemplate == null)
- {
- this.indexTemplate = this.compiler.compile(INDEX_TEMPLATE);
- }
- }
-
- protected void setupRichFaces()
- {
- if ((this.project.getFacet(DependencyFacet.class).hasEffectiveDependency(this.richfaces3UI)
- && this.project.getFacet(DependencyFacet.class).hasEffectiveDependency(this.richfaces3Impl))
- || (this.project.getFacet(DependencyFacet.class).hasEffectiveDependency(this.richfaces4UI)
- && this.project.getFacet(DependencyFacet.class).hasEffectiveDependency(this.richfaces4Impl)))
- {
- this.entityMetawidget
- .setWidgetBuilder(insertRichFacesWidgetBuilder((CompositeWidgetBuilder) this.entityMetawidget
- .getWidgetBuilder()));
-
- this.searchMetawidget
- .setWidgetBuilder(insertRichFacesWidgetBuilder((CompositeWidgetBuilder) this.searchMetawidget
- .getWidgetBuilder()));
-
- this.beanMetawidget
- .setWidgetBuilder(insertRichFacesWidgetBuilder((CompositeWidgetBuilder) this.beanMetawidget
- .getWidgetBuilder()));
- }
- }
-
- /**
- * Locates a ReadOnlyWidgetBuilder
in the list of WidgetBuilders, and inserts a
- * RichFacesWidgetBuilder
after it (unless there's a RichFacesWidgetBuilder
in there
- * already).
- */
-
- protected CompositeWidgetBuilder insertRichFacesWidgetBuilder(
- final CompositeWidgetBuilder compositeWidgetBuilder)
- {
- // Get the current WidgetBuilders...
-
- WidgetBuilder[] existingWidgetBuilders = compositeWidgetBuilder.getWidgetBuilders();
-
- // ...find the ReadOnlyWidgetBuilder (if any)...
-
- int addAt = 0;
-
- for (int loop = 0; loop < existingWidgetBuilders.length; loop++)
- {
- // ...(abort if there's already a RichFacesWidgetBuilder)...
-
- // Use an Object loop variable here to avoid a nasty Java/Generics compiler bug
- Object widgetBuilder = existingWidgetBuilders[loop];
- if (widgetBuilder instanceof RichFacesWidgetBuilder)
- {
- return compositeWidgetBuilder;
- }
-
- if (widgetBuilder instanceof ReadOnlyWidgetBuilder)
- {
- addAt = loop + 1;
- }
- }
-
- // ...and insert our RichFacesWidgetBuilder just after it
-
- @SuppressWarnings("unchecked")
- WidgetBuilder[] newWidgetBuilders = (WidgetBuilder[]) ArrayUtils
- .addAt(existingWidgetBuilders, addAt,
- new RichFacesWidgetBuilder());
-
- return new CompositeWidgetBuilder(
- new CompositeWidgetBuilderConfig()
- .setWidgetBuilders(newWidgetBuilders));
- }
-
- protected void createInitializers(final JavaClass entity)
- {
- for (Field field : entity.getFields())
- {
- if (field.hasAnnotation(OneToOne.class))
- {
- Annotation oneToOne = field.getAnnotation(OneToOne.class);
- if (oneToOne.getStringValue("mappedBy") == null)
- {
- oneToOne.setEnumValue("cascade", CascadeType.ALL);
- }
- String methodName = "new" + field.getTypeInspector().getName();
- if (!entity.hasMethodSignature(methodName))
- {
- entity.addMethod().setName(methodName).setReturnTypeVoid().setPublic()
- .setBody("this." + field.getName() + " = new " + field.getType() + "();");
- }
- }
- }
- for (Method method : entity.getMethods())
- {
- if (method.hasAnnotation(OneToOne.class))
- {
- Annotation oneToOne = method.getAnnotation(OneToOne.class);
- if (oneToOne.getStringValue("mappedBy") == null)
- {
- oneToOne.setEnumValue("cascade", CascadeType.ALL);
- }
- String methodName = "new" + method.getReturnTypeInspector().getName();
- if (!entity.hasMethodSignature(methodName))
- {
- entity.addMethod().setName(methodName).setReturnTypeVoid().setPublic()
- .setBody("this." + method.getName() + " = new " + method.getReturnType() + "();");
- }
- }
- }
- }
-
- protected HashMap getTemplateContext(final Resource> template)
- {
- HashMap context;
- context = new HashMap();
- context.put("template", template);
- context.put("templateStrategy", getTemplateStrategy());
- return context;
- }
-
- protected void setupWebXML()
- {
- ServletFacet servlet = this.project.getFacet(ServletFacet.class);
-
- Node webXML = removeConflictingErrorPages(servlet);
- servlet.getConfigFile().setContents(XMLParser.toXMLInputStream(webXML));
-
- WebAppDescriptor servletConfig = servlet.getConfig();
- WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
-
- // (prefer /faces/error.xhtml)
-
- String errorLocation = getAccessStrategy().getWebPaths(web.getWebResource("error.xhtml")).get(1);
- servletConfig.errorPage(404, errorLocation);
- servletConfig.errorPage(500, errorLocation);
-
- servlet.saveConfig(servletConfig);
- }
-
- protected Node removeConflictingErrorPages(final ServletFacet servlet)
- {
- Node webXML = XMLParser.parse(servlet.getConfigFile().getResourceInputStream());
- Node root = webXML.getRoot();
- List errorPages = root.get("error-page");
-
- for (String code : Arrays.asList("404", "500"))
- {
- for (Node errorPage : errorPages)
- {
- if (code.equals(errorPage.getSingle("error-code").getText())
- && this.prompt.promptBoolean("Your web.xml already contains an error page for " + code
- + " status codes, replace it?"))
- {
- root.removeChild(errorPage);
- }
- }
- }
- return webXML;
- }
-
- /**
- * Generates the navigation menu based on scaffolded entities.
- */
-
- protected Resource> generateNavigation(final String targetDir, final boolean overwrite)
- throws IOException
- {
- WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
- HtmlTag unorderedList = new HtmlTag("ul");
-
- for (Resource> resource : web.getWebResource(targetDir).listResources())
- {
- HtmlOutcomeTargetLink outcomeTargetLink = new HtmlOutcomeTargetLink();
- outcomeTargetLink.putAttribute("outcome", "/" + targetDir + "/" + resource.getName() + "/search");
- outcomeTargetLink.setValue(StringUtils.uncamelCase(resource.getName()));
-
- HtmlTag listItem = new HtmlTag("li");
- listItem.getChildren().add(outcomeTargetLink);
- unorderedList.getChildren().add(listItem);
- }
-
- Writer writer = new IndentedWriter(new StringWriter(), this.navigationTemplateIndent);
- unorderedList.write(writer);
- Map context = CollectionUtils.newHashMap();
- context.put("navigation", writer.toString().trim());
-
- if (this.navigationTemplate == null)
- {
- loadTemplates();
- }
-
- return ScaffoldUtil.createOrOverwrite(this.prompt, (FileResource>) getTemplateStrategy()
- .getDefaultTemplate(),
- this.navigationTemplate.render(context),
- overwrite);
- }
-
- /**
- * Parses the given XML and determines what namespaces it already declares. These are later removed from the list of
- * namespaces that Metawidget introduces.
- */
-
- protected Map parseNamespaces(final String template)
- {
- Map namespaces = CollectionUtils.newHashMap();
- Document document = XmlUtils.documentFromString(template);
- Element element = document.getDocumentElement();
- NamedNodeMap attributes = element.getAttributes();
-
- for (int loop = 0, length = attributes.getLength(); loop < length; loop++)
- {
- org.w3c.dom.Node node = attributes.item(loop);
- String nodeName = node.getNodeName();
- int indexOf = nodeName.indexOf(XMLNS_PREFIX);
-
- if (indexOf == -1)
- {
- continue;
- }
-
- namespaces.put(nodeName.substring(indexOf + XMLNS_PREFIX.length()), node.getNodeValue());
- }
-
- return namespaces;
- }
-
- /**
- * Parses the given XML and determines the indent of the given String namespaces that Metawidget introduces.
- */
-
- protected int parseIndent(final String template, final String indentOf)
- {
- int indent = 0;
- int indexOf = template.indexOf(indentOf);
-
- while ((indexOf >= 0) && (template.charAt(indexOf) != '\n'))
- {
- if (template.charAt(indexOf) == '\t')
- {
- indent++;
- }
-
- indexOf--;
- }
-
- return indent;
- }
-
- /**
- * Writes the entity Metawidget and its namespaces into the given context.
- */
-
- protected void writeEntityMetawidget(final Map context, final int entityMetawidgetIndent,
- final Map existingNamespaces)
- {
- StringWriter stringWriter = new StringWriter();
- this.entityMetawidget.write(stringWriter, entityMetawidgetIndent);
- context.put("metawidget", stringWriter.toString().trim());
-
- Map namespaces = this.entityMetawidget.getNamespaces();
- namespaces.keySet().removeAll(existingNamespaces.keySet());
- context.put("metawidgetNamespaces", namespacesToString(namespaces));
- }
-
- /**
- * Writes the search Metawidget, the bean Metawidget and their namespaces into the given context.
- */
-
- protected void writeSearchAndBeanMetawidget(final Map context, final int searchMetawidgetIndent,
- final int beanMetawidgetIndent,
- final Map existingNamespaces)
- {
- StringWriter stringWriter = new StringWriter();
- this.searchMetawidget.write(stringWriter, searchMetawidgetIndent);
- context.put("searchMetawidget", stringWriter.toString().trim());
-
- stringWriter = new StringWriter();
- this.beanMetawidget.write(stringWriter, beanMetawidgetIndent);
- context.put("beanMetawidget", stringWriter.toString().trim());
-
- Map namespaces = this.searchMetawidget.getNamespaces();
- namespaces.putAll(this.beanMetawidget.getNamespaces());
- namespaces.keySet().removeAll(existingNamespaces.keySet());
- context.put("metawidgetNamespaces", namespacesToString(namespaces));
- }
-
- protected String namespacesToString(final Map namespaces)
- {
- StringBuilder builder = new StringBuilder();
-
- for (Map.Entry entry : namespaces.entrySet())
- {
- // At the start, break out of the current quote. Field must be in quotes so that we're valid XML
-
- builder.append("\"\r\n\txmlns:");
- builder.append(entry.getKey());
- builder.append("=\"");
- builder.append(entry.getValue());
- }
-
- return builder.toString();
- }
-}
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011, 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.forge.scaffold.faces;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.enterprise.event.Event;
+import javax.inject.Inject;
+import javax.persistence.CascadeType;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+
+import org.jboss.forge.env.Configuration;
+import org.jboss.forge.parser.JavaParser;
+import org.jboss.forge.parser.java.*;
+import org.jboss.forge.parser.xml.Node;
+import org.jboss.forge.parser.xml.XMLParser;
+import org.jboss.forge.project.Project;
+import org.jboss.forge.project.dependencies.Dependency;
+import org.jboss.forge.project.dependencies.DependencyBuilder;
+import org.jboss.forge.project.facets.BaseFacet;
+import org.jboss.forge.project.facets.DependencyFacet;
+import org.jboss.forge.project.facets.JavaSourceFacet;
+import org.jboss.forge.project.facets.WebResourceFacet;
+import org.jboss.forge.project.facets.events.InstallFacets;
+import org.jboss.forge.resources.FileResource;
+import org.jboss.forge.resources.Resource;
+import org.jboss.forge.scaffold.AccessStrategy;
+import org.jboss.forge.scaffold.ScaffoldProvider;
+import org.jboss.forge.scaffold.TemplateStrategy;
+import org.jboss.forge.scaffold.faces.metawidget.config.ForgeConfigReader;
+import org.jboss.forge.scaffold.util.ScaffoldUtil;
+import org.jboss.forge.shell.ShellPrompt;
+import org.jboss.forge.shell.plugins.Alias;
+import org.jboss.forge.shell.plugins.RequiresFacet;
+import org.jboss.forge.shell.util.Streams;
+import org.jboss.forge.spec.javaee.CDIFacet;
+import org.jboss.forge.spec.javaee.EJBFacet;
+import org.jboss.forge.spec.javaee.FacesAPIFacet;
+import org.jboss.forge.spec.javaee.FacesFacet;
+import org.jboss.forge.spec.javaee.PersistenceFacet;
+import org.jboss.forge.spec.javaee.ServletFacet;
+import org.jboss.seam.render.TemplateCompiler;
+import org.jboss.seam.render.spi.TemplateResolver;
+import org.jboss.seam.render.template.CompiledTemplateResource;
+import org.jboss.seam.render.template.resolver.ClassLoaderTemplateResolver;
+import org.jboss.shrinkwrap.descriptor.api.spec.servlet.web.WebAppDescriptor;
+import org.metawidget.statically.StaticMetawidget;
+import org.metawidget.statically.StaticUtils.IndentedWriter;
+import org.metawidget.statically.StaticWidget;
+import org.metawidget.statically.faces.StaticFacesUtils;
+import org.metawidget.statically.faces.component.html.StaticHtmlMetawidget;
+import org.metawidget.statically.faces.component.html.widgetbuilder.HtmlOutcomeTargetLink;
+import org.metawidget.statically.faces.component.html.widgetbuilder.ReadOnlyWidgetBuilder;
+import org.metawidget.statically.faces.component.html.widgetbuilder.richfaces.RichFacesWidgetBuilder;
+import org.metawidget.statically.html.widgetbuilder.HtmlTag;
+import org.metawidget.statically.javacode.StaticJavaMetawidget;
+import org.metawidget.util.ArrayUtils;
+import org.metawidget.util.CollectionUtils;
+import org.metawidget.util.XmlUtils;
+import org.metawidget.util.simple.StringUtils;
+import org.metawidget.widgetbuilder.composite.CompositeWidgetBuilder;
+import org.metawidget.widgetbuilder.composite.CompositeWidgetBuilderConfig;
+import org.metawidget.widgetbuilder.iface.WidgetBuilder;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+/**
+ * Facet to generate a Java Server Faces UI. This facet utilizes Metawidget internally. This enables the use
+ * of the Metawidget SPI (pluggable WidgetBuilders, Layouts etc) for customizing
+ * the generated User Interface. For more information on writing Metawidget
+ * plugins, see the Metawidget
+ * documentation .
This Facet does not require Metawidget to be
+ * in the final project.
+ *
+ * @author Lincoln Baxter, III
+ * @author Richard Kennard
+ */
+@Alias("faces")
+@RequiresFacet({WebResourceFacet.class,
+ DependencyFacet.class,
+ PersistenceFacet.class,
+ EJBFacet.class,
+ CDIFacet.class,
+ FacesFacet.class})
+public class FacesScaffold extends BaseFacet implements ScaffoldProvider {
+ //
+ // Private statics
+ //
+
+ private static final String XMLNS_PREFIX = "xmlns:";
+ private static final String BACKING_BEAN_TEMPLATE = "scaffold/faces/BackingBean.jv";
+ private static final String VIEW_UTILS_TEMPLATE = "scaffold/faces/ViewUtils.jv";
+ private static final String TAGLIB_TEMPLATE = "scaffold/faces/forge.taglib.xml";
+ private static final String VIEW_TEMPLATE = "scaffold/faces/view.xhtml";
+ private static final String CREATE_TEMPLATE = "scaffold/faces/create.xhtml";
+ private static final String SEARCH_TEMPLATE = "scaffold/faces/search.xhtml";
+ private static final String NAVIGATION_TEMPLATE = "scaffold/faces/page.xhtml";
+ private static final String ERROR_TEMPLATE = "scaffold/faces/error.xhtml";
+ private static final String INDEX_TEMPLATE = "scaffold/faces/index.xhtml";
+ private final Dependency richfaces3UI = DependencyBuilder.create("org.richfaces.ui:richfaces-ui");
+ private final Dependency richfaces3Impl = DependencyBuilder.create("org.richfaces.framework:richfaces-impl");
+ private final Dependency richfaces4UI = DependencyBuilder.create("org.richfaces.ui:richfaces-components-ui");
+ private final Dependency richfaces4Impl = DependencyBuilder.create("org.richfaces.core:richfaces-core-impl");
+ //
+ // Protected members (nothing is private, to help subclassing)
+ //
+ protected CompiledTemplateResource backingBeanTemplate;
+ protected int backingBeanTemplateQbeMetawidgetIndent;
+ protected CompiledTemplateResource viewUtilsTemplate;
+ protected CompiledTemplateResource taglibTemplate;
+ protected CompiledTemplateResource viewTemplate;
+ protected Map viewTemplateNamespaces;
+ protected int viewTemplateEntityMetawidgetIndent;
+ protected CompiledTemplateResource createTemplate;
+ protected Map createTemplateNamespaces;
+ protected int createTemplateEntityMetawidgetIndent;
+ protected CompiledTemplateResource searchTemplate;
+ protected Map searchTemplateNamespaces;
+ protected int searchTemplateSearchMetawidgetIndent;
+ protected int searchTemplateBeanMetawidgetIndent;
+ protected CompiledTemplateResource navigationTemplate;
+ protected int navigationTemplateIndent;
+ protected CompiledTemplateResource errorTemplate;
+ protected CompiledTemplateResource indexTemplate;
+ protected TemplateResolver resolver;
+ protected final ShellPrompt prompt;
+ protected final TemplateCompiler compiler;
+ protected final Event install;
+ protected StaticHtmlMetawidget entityMetawidget;
+ protected StaticHtmlMetawidget searchMetawidget;
+ protected StaticHtmlMetawidget beanMetawidget;
+ protected StaticJavaMetawidget qbeMetawidget;
+// @Inject AnnotationLookup annotationLookup;
+// @Inject RelationResolverWidgetProcessor relationResolver;
+// @Inject RelationResolverWidgetProcessorConfig relationResolverConfig;
+
+ private Configuration config;
+
+ //
+ // Constructor
+ //
+ @Inject
+ public FacesScaffold(final Configuration config,
+ final ShellPrompt prompt,
+ final TemplateCompiler compiler,
+ final Event install)
+ {
+ this.config = config;
+ this.prompt = prompt;
+ this.compiler = compiler;
+ this.install = install;
+
+ this.resolver = new ClassLoaderTemplateResolver(FacesScaffold.class.getClassLoader());
+
+ if (this.compiler != null) {
+ this.compiler.getTemplateResolverFactory().addResolver(this.resolver);
+ }
+ }
+
+ //
+ // Public methods
+ //
+ @Override
+ public List> setup(String targetDir, final Resource> template, final boolean overwrite)
+ {
+ List> resources = generateIndex(targetDir, template, overwrite);
+ setupWebXML();
+
+ return resources;
+ }
+
+ /**
+ * Overridden to setup the Metawidgets. Metawidgets must be configured
+ * per project and per Forge invocation . It is not sufficient to
+ * simply configure them in
+ * setup
because the user may restart Forge and not run
+ * scaffold setup
a second time.
+ */
+ @Override
+ public void setProject(Project project) {
+ super.setProject(project);
+
+ ForgeConfigReader configReader = new ForgeConfigReader(this.config, this.project);
+
+ this.entityMetawidget = new StaticHtmlMetawidget();
+ this.entityMetawidget.setConfigReader(configReader);
+ this.entityMetawidget.setConfig("scaffold/faces/metawidget-entity.xml");
+
+ this.searchMetawidget = new StaticHtmlMetawidget();
+ this.searchMetawidget.setConfigReader(configReader);
+ this.searchMetawidget.setConfig("scaffold/faces/metawidget-search.xml");
+
+ this.beanMetawidget = new StaticHtmlMetawidget();
+ this.beanMetawidget.setConfigReader(configReader);
+ this.beanMetawidget.setConfig("scaffold/faces/metawidget-bean.xml");
+
+ this.qbeMetawidget = new StaticJavaMetawidget();
+ this.qbeMetawidget.setConfigReader(configReader);
+ this.qbeMetawidget.setConfig("scaffold/faces/metawidget-qbe.xml");
+
+ }
+
+ @Override
+ public List> generateFromEntity(String targetDir, final Resource> template, final JavaClass entity,
+ final boolean overwrite)
+ {
+ // FORGE-460: setupRichFaces during generateFromEntity, not during setup, as generally 'richfaces setup' is called
+ // *after* 'scaffold setup'
+
+ setupRichFaces();
+
+ // Track the list of resources generated
+
+ List> result = new ArrayList>();
+ try {
+ JavaSourceFacet java = this.project.getFacet(JavaSourceFacet.class);
+ WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
+
+ loadTemplates();
+ Map context = CollectionUtils.newHashMap();
+ context.put("entity", entity);
+ String ccEntity = StringUtils.decapitalize(entity.getName());
+ context.put("ccEntity", ccEntity);
+ setPrimaryKeyMetaData(context, entity);
+
+ // Prepare qbeMetawidget
+ this.qbeMetawidget.setPath(entity.getQualifiedName());
+ StringWriter stringWriter = new StringWriter();
+ this.qbeMetawidget.write(stringWriter, this.backingBeanTemplateQbeMetawidgetIndent);
+
+ context.put("qbeMetawidget", stringWriter.toString().trim());
+ context.put("qbeMetawidgetImports",
+ CollectionUtils.toString(this.qbeMetawidget.getImports(), ";\r\nimport ", true, false));
+
+ // Create the Backing Bean for this entity
+ JavaClass viewBean = JavaParser.parse(JavaClass.class, this.backingBeanTemplate.render(context));
+ viewBean.setPackage(java.getBasePackage() + ".view");
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, java.getJavaResource(viewBean), viewBean.toString(),
+ overwrite));
+
+ // Set new context for view generation
+ context = getTemplateContext(template);
+ String beanName = StringUtils.decapitalize(viewBean.getName());
+ context.put("beanName", beanName);
+ context.put("ccEntity", ccEntity);
+ context.put("entityName", StringUtils.uncamelCase(entity.getName()));
+ setPrimaryKeyMetaData(context, entity);
+
+ // Prepare entityMetawidget
+ this.entityMetawidget.setValue(StaticFacesUtils.wrapExpression(beanName + "." + ccEntity));
+ this.entityMetawidget.setPath(entity.getQualifiedName());
+ this.entityMetawidget.setReadOnly(false);
+ this.entityMetawidget.setStyle(null);
+
+ // Generate create
+ writeEntityMetawidget(context, this.createTemplateEntityMetawidgetIndent, this.createTemplateNamespaces);
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
+ web.getWebResource(targetDir + "/" + ccEntity + "/create.xhtml"),
+ this.createTemplate.render(context),
+ overwrite));
+
+ // Generate view
+ this.entityMetawidget.setReadOnly(true);
+ writeEntityMetawidget(context, this.viewTemplateEntityMetawidgetIndent, this.viewTemplateNamespaces);
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
+ web.getWebResource(targetDir + "/" + ccEntity + "/view.xhtml"),
+ this.viewTemplate.render(context), overwrite));
+
+ // Generate search
+ this.searchMetawidget.setValue(StaticFacesUtils.wrapExpression(beanName + ".search"));
+ this.searchMetawidget.setPath(entity.getQualifiedName());
+ this.beanMetawidget.setValue(StaticFacesUtils.wrapExpression(beanName + ".pageItems"));
+ this.beanMetawidget.setPath(viewBean.getQualifiedName() + "/pageItems");
+ writeSearchAndBeanMetawidget(context, this.searchTemplateSearchMetawidgetIndent,
+ this.searchTemplateBeanMetawidgetIndent, this.searchTemplateNamespaces);
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
+ web.getWebResource(targetDir + "/" + ccEntity + "/search.xhtml"),
+ this.searchTemplate.render(context), overwrite));
+
+ // Generate navigation
+ result.add(generateNavigation(targetDir, overwrite));
+
+ // Need ViewUtils and forge.taglib.xml for forgeview:asList
+ JavaClass viewUtils = JavaParser.parse(JavaClass.class, this.viewUtilsTemplate.render(context));
+ viewUtils.setPackage(viewBean.getPackage());
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, java.getJavaResource(viewUtils), viewUtils.toString(),
+ true));
+
+ context.put("viewPackage", viewBean.getPackage());
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
+ web.getWebResource("WEB-INF/classes/META-INF/forge.taglib.xml"),
+ this.taglibTemplate.render(context), true));
+
+ createInitializers(entity);
+ this.project.getFacet(JavaSourceFacet.class).saveJavaSource(entity);
+
+ } catch (Exception e) {
+ throw new RuntimeException("Error generating default scaffolding: " + e.getMessage(), e);
+ }
+ return result;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean install() {
+ if (!(this.project.hasFacet(WebResourceFacet.class) && this.project.hasFacet(PersistenceFacet.class)
+ && this.project.hasFacet(CDIFacet.class) && this.project.hasFacet(FacesFacet.class))) {
+ this.install.fire(new InstallFacets(WebResourceFacet.class, PersistenceFacet.class, CDIFacet.class,
+ FacesFacet.class));
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean isInstalled() {
+ return true;
+ }
+
+ @Override
+ public List> generateIndex(String targetDir, final Resource> template, final boolean overwrite)
+ {
+ List> result = new ArrayList>();
+ WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
+
+ this.project.getFacet(ServletFacet.class).getConfig().welcomeFile("/index.html");
+ loadTemplates();
+
+ generateTemplates(targetDir, overwrite);
+ HashMap context = getTemplateContext(template);
+
+ // Basic pages
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/index.html"), getClass()
+ .getResourceAsStream("/scaffold/faces/index.html"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/index.xhtml"),
+ this.indexTemplate.render(context), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("error.xhtml"),
+ this.errorTemplate.render(context), overwrite));
+
+ // Static resources
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/add.png"),
+ getClass().getResourceAsStream("/scaffold/faces/add.png"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/background.gif"),
+ getClass().getResourceAsStream("/scaffold/faces/background.gif"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/false.png"),
+ getClass().getResourceAsStream("/scaffold/faces/false.png"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/favicon.ico"),
+ getClass().getResourceAsStream("/scaffold/faces/favicon.ico"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/forge-logo.png"),
+ getClass().getResourceAsStream("/scaffold/faces/forge-logo.png"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/forge-style.css"),
+ getClass().getResourceAsStream("/scaffold/faces/forge-style.css"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/jboss-community.png"),
+ getClass().getResourceAsStream("/scaffold/faces/jboss-community.png"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/remove.png"),
+ getClass().getResourceAsStream("/scaffold/faces/remove.png"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/search.png"),
+ getClass().getResourceAsStream("/scaffold/faces/search.png"), overwrite));
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt, web.getWebResource("/resources/true.png"),
+ getClass().getResourceAsStream("/scaffold/faces/true.png"), overwrite));
+
+ return result;
+ }
+
+ @Override
+ public List> getGeneratedResources(String targetDir)
+ {
+ throw new RuntimeException("Not yet implemented!");
+ }
+
+ @Override
+ public AccessStrategy getAccessStrategy() {
+ return new FacesAccessStrategy(this.project);
+ }
+
+ @Override
+ public TemplateStrategy getTemplateStrategy() {
+ return new FacesTemplateStrategy(this.project);
+ }
+
+ @Override
+ public List> generateTemplates(String targetDir, final boolean overwrite)
+ {
+ List> result = new ArrayList>();
+
+ try {
+ WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
+
+ result.add(ScaffoldUtil.createOrOverwrite(this.prompt,
+ web.getWebResource("/resources/scaffold/paginator.xhtml"),
+ getClass().getResourceAsStream("/scaffold/faces/paginator.xhtml"),
+ overwrite));
+
+ result.add(generateNavigation(targetDir, overwrite));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Error generating default templates", e);
+ }
+
+ return result;
+ }
+
+ //
+ // Protected methods (nothing is private, to help subclassing)
+ //
+ protected void loadTemplates() {
+ if (this.backingBeanTemplate == null) {
+ this.backingBeanTemplate = this.compiler.compile(BACKING_BEAN_TEMPLATE);
+ String template = Streams.toString(this.backingBeanTemplate.getSourceTemplateResource().getInputStream());
+ this.backingBeanTemplateQbeMetawidgetIndent = parseIndent(template, "@{qbeMetawidget}");
+ }
+ if (this.viewUtilsTemplate == null) {
+ this.viewUtilsTemplate = this.compiler.compile(VIEW_UTILS_TEMPLATE);
+ }
+ if (this.taglibTemplate == null) {
+ this.taglibTemplate = this.compiler.compile(TAGLIB_TEMPLATE);
+ }
+ if (this.viewTemplate == null) {
+ this.viewTemplate = this.compiler.compile(VIEW_TEMPLATE);
+ String template = Streams.toString(this.viewTemplate.getSourceTemplateResource().getInputStream());
+ this.viewTemplateNamespaces = parseNamespaces(template);
+ this.viewTemplateEntityMetawidgetIndent = parseIndent(template, "@{metawidget}");
+ }
+ if (this.createTemplate == null) {
+ this.createTemplate = this.compiler.compile(CREATE_TEMPLATE);
+ String template = Streams.toString(this.createTemplate.getSourceTemplateResource().getInputStream());
+ this.createTemplateNamespaces = parseNamespaces(template);
+ this.createTemplateEntityMetawidgetIndent = parseIndent(template, "@{metawidget}");
+ }
+ if (this.searchTemplate == null) {
+ this.searchTemplate = this.compiler.compile(SEARCH_TEMPLATE);
+ String template = Streams.toString(this.searchTemplate.getSourceTemplateResource().getInputStream());
+ this.searchTemplateNamespaces = parseNamespaces(template);
+ this.searchTemplateSearchMetawidgetIndent = parseIndent(template, "@{searchMetawidget}");
+ this.searchTemplateBeanMetawidgetIndent = parseIndent(template, "@{beanMetawidget}");
+ }
+ if (this.navigationTemplate == null) {
+ this.navigationTemplate = this.compiler.compile(NAVIGATION_TEMPLATE);
+ String template = Streams.toString(this.navigationTemplate.getSourceTemplateResource().getInputStream());
+ this.navigationTemplateIndent = parseIndent(template, "@{navigation}");
+ }
+ if (this.errorTemplate == null) {
+ this.errorTemplate = this.compiler.compile(ERROR_TEMPLATE);
+ }
+ if (this.indexTemplate == null) {
+ this.indexTemplate = this.compiler.compile(INDEX_TEMPLATE);
+ }
+ }
+
+ protected void setupRichFaces() {
+ if ((this.project.getFacet(DependencyFacet.class).hasEffectiveDependency(this.richfaces3UI)
+ && this.project.getFacet(DependencyFacet.class).hasEffectiveDependency(this.richfaces3Impl))
+ || (this.project.getFacet(DependencyFacet.class).hasEffectiveDependency(this.richfaces4UI)
+ && this.project.getFacet(DependencyFacet.class).hasEffectiveDependency(this.richfaces4Impl))) {
+ this.entityMetawidget.setWidgetBuilder(insertRichFacesWidgetBuilder((CompositeWidgetBuilder) this.entityMetawidget.getWidgetBuilder()));
+
+ this.searchMetawidget.setWidgetBuilder(insertRichFacesWidgetBuilder((CompositeWidgetBuilder) this.searchMetawidget.getWidgetBuilder()));
+
+ this.beanMetawidget.setWidgetBuilder(insertRichFacesWidgetBuilder((CompositeWidgetBuilder) this.beanMetawidget.getWidgetBuilder()));
+ }
+ }
+
+ /**
+ * Locates a
+ * ReadOnlyWidgetBuilder
in the list of WidgetBuilders, and
+ * inserts a
+ * RichFacesWidgetBuilder
after it (unless there's a
+ * RichFacesWidgetBuilder
in there already).
+ */
+ protected CompositeWidgetBuilder insertRichFacesWidgetBuilder(
+ final CompositeWidgetBuilder compositeWidgetBuilder) {
+ // Get the current WidgetBuilders...
+
+ WidgetBuilder[] existingWidgetBuilders = compositeWidgetBuilder.getWidgetBuilders();
+
+ // ...find the ReadOnlyWidgetBuilder (if any)...
+
+ int addAt = 0;
+
+ for (int loop = 0; loop < existingWidgetBuilders.length; loop++) {
+ // ...(abort if there's already a RichFacesWidgetBuilder)...
+
+ // Use an Object loop variable here to avoid a nasty Java/Generics compiler bug
+ Object widgetBuilder = existingWidgetBuilders[loop];
+ if (widgetBuilder instanceof RichFacesWidgetBuilder) {
+ return compositeWidgetBuilder;
+ }
+
+ if (widgetBuilder instanceof ReadOnlyWidgetBuilder) {
+ addAt = loop + 1;
+ }
+ }
+
+ // ...and insert our RichFacesWidgetBuilder just after it
+
+ @SuppressWarnings("unchecked")
+ WidgetBuilder[] newWidgetBuilders = (WidgetBuilder[]) ArrayUtils.addAt(existingWidgetBuilders, addAt,
+ new RichFacesWidgetBuilder());
+
+ return new CompositeWidgetBuilder(
+ new CompositeWidgetBuilderConfig().setWidgetBuilders(newWidgetBuilders));
+ }
+
+ protected void createInitializers(final JavaClass entity) {
+ for (Field field : entity.getFields()) {
+ if (field.hasAnnotation(OneToOne.class)) {
+ Annotation oneToOne = field.getAnnotation(OneToOne.class);
+ if (oneToOne.getStringValue("mappedBy") == null) {
+ oneToOne.setEnumValue("cascade", CascadeType.ALL);
+ }
+ String methodName = "new" + field.getTypeInspector().getName();
+ if (!entity.hasMethodSignature(methodName)) {
+ entity.addMethod().setName(methodName).setReturnTypeVoid().setPublic().setBody("this." + field.getName() + " = new " + field.getType() + "();");
+ }
+ }
+ }
+ for (Method method : entity.getMethods()) {
+ if (method.hasAnnotation(OneToOne.class)) {
+ Annotation oneToOne = method.getAnnotation(OneToOne.class);
+ if (oneToOne.getStringValue("mappedBy") == null) {
+ oneToOne.setEnumValue("cascade", CascadeType.ALL);
+ }
+ String methodName = "new" + method.getReturnTypeInspector().getName();
+ if (!entity.hasMethodSignature(methodName)) {
+ entity.addMethod().setName(methodName).setReturnTypeVoid().setPublic().setBody("this." + method.getName() + " = new " + method.getReturnType() + "();");
+ }
+ }
+ }
+ }
+
+ protected HashMap getTemplateContext(final Resource> template) {
+ HashMap context;
+ context = new HashMap();
+ context.put("template", template);
+ context.put("templateStrategy", getTemplateStrategy());
+ return context;
+ }
+
+ protected void setupWebXML() {
+ ServletFacet servlet = this.project.getFacet(ServletFacet.class);
+
+ Node webXML = removeConflictingErrorPages(servlet);
+ servlet.getConfigFile().setContents(XMLParser.toXMLInputStream(webXML));
+
+ WebAppDescriptor servletConfig = servlet.getConfig();
+ WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
+
+ // (prefer /faces/error.xhtml)
+
+ String errorLocation = getAccessStrategy().getWebPaths(web.getWebResource("error.xhtml")).get(1);
+ servletConfig.errorPage(404, errorLocation);
+ servletConfig.errorPage(500, errorLocation);
+
+ servlet.saveConfig(servletConfig);
+ }
+
+ protected Node removeConflictingErrorPages(final ServletFacet servlet) {
+ Node webXML = XMLParser.parse(servlet.getConfigFile().getResourceInputStream());
+ Node root = webXML.getRoot();
+ List errorPages = root.get("error-page");
+
+ for (String code : Arrays.asList("404", "500")) {
+ for (Node errorPage : errorPages) {
+ if (code.equals(errorPage.getSingle("error-code").getText())
+ && this.prompt.promptBoolean("Your web.xml already contains an error page for " + code
+ + " status codes, replace it?")) {
+ root.removeChild(errorPage);
+ }
+ }
+ }
+ return webXML;
+ }
+
+ /**
+ * Generates the navigation menu based on scaffolded entities.
+ */
+
+ protected Resource> generateNavigation(final String targetDir, final boolean overwrite)
+ throws IOException
+ {
+ WebResourceFacet web = this.project.getFacet(WebResourceFacet.class);
+ HtmlTag unorderedList = new HtmlTag("ul");
+
+ for (Resource> resource : web.getWebResource(targetDir).listResources())
+ {
+ HtmlOutcomeTargetLink outcomeTargetLink = new HtmlOutcomeTargetLink();
+ outcomeTargetLink.putAttribute("outcome", "/" + targetDir + "/" + resource.getName() + "/search");
+ outcomeTargetLink.setValue(StringUtils.uncamelCase(resource.getName()));
+
+ HtmlTag listItem = new HtmlTag("li");
+ listItem.getChildren().add(outcomeTargetLink);
+ unorderedList.getChildren().add(listItem);
+ }
+
+ Writer writer = new IndentedWriter(new StringWriter(), this.navigationTemplateIndent);
+ unorderedList.write(writer);
+ Map context = CollectionUtils.newHashMap();
+ context.put("navigation", writer.toString().trim());
+
+ if (this.navigationTemplate == null) {
+ loadTemplates();
+ }
+
+ return ScaffoldUtil.createOrOverwrite(this.prompt, (FileResource>) getTemplateStrategy().getDefaultTemplate(),
+ this.navigationTemplate.render(context),
+ overwrite);
+ }
+
+ /**
+ * Parses the given XML and determines what namespaces it already declares.
+ * These are later removed from the list of namespaces that Metawidget
+ * introduces.
+ */
+ protected Map parseNamespaces(final String template) {
+ Map namespaces = CollectionUtils.newHashMap();
+ Document document = XmlUtils.documentFromString(template);
+ Element element = document.getDocumentElement();
+ NamedNodeMap attributes = element.getAttributes();
+
+ for (int loop = 0, length = attributes.getLength(); loop < length; loop++) {
+ org.w3c.dom.Node node = attributes.item(loop);
+ String nodeName = node.getNodeName();
+ int indexOf = nodeName.indexOf(XMLNS_PREFIX);
+
+ if (indexOf == -1) {
+ continue;
+ }
+
+ namespaces.put(nodeName.substring(indexOf + XMLNS_PREFIX.length()), node.getNodeValue());
+ }
+
+ return namespaces;
+ }
+
+ /**
+ * Parses the given XML and determines the indent of the given String
+ * namespaces that Metawidget introduces.
+ */
+ protected int parseIndent(final String template, final String indentOf) {
+ int indent = 0;
+ int indexOf = template.indexOf(indentOf);
+
+ while ((indexOf >= 0) && (template.charAt(indexOf) != '\n')) {
+ if (template.charAt(indexOf) == '\t') {
+ indent++;
+ }
+
+ indexOf--;
+ }
+
+ return indent;
+ }
+
+ /**
+ * Writes the entity Metawidget and its namespaces into the given context.
+ */
+ protected void writeEntityMetawidget(final Map context, final int entityMetawidgetIndent,
+ final Map existingNamespaces) {
+ StringWriter stringWriter = new StringWriter();
+ this.entityMetawidget.write(stringWriter, entityMetawidgetIndent);
+ context.put("metawidget", stringWriter.toString().trim());
+
+ Map namespaces = this.entityMetawidget.getNamespaces();
+ namespaces.keySet().removeAll(existingNamespaces.keySet());
+ context.put("metawidgetNamespaces", namespacesToString(namespaces));
+ }
+
+ /**
+ * Writes the search Metawidget, the bean Metawidget and their namespaces
+ * into the given context.
+ */
+ protected void writeSearchAndBeanMetawidget(final Map context, final int searchMetawidgetIndent,
+ final int beanMetawidgetIndent,
+ final Map existingNamespaces) {
+ StringWriter stringWriter = new StringWriter();
+ this.searchMetawidget.write(stringWriter, searchMetawidgetIndent);
+ context.put("searchMetawidget", stringWriter.toString().trim());
+
+ stringWriter = new StringWriter();
+ this.beanMetawidget.write(stringWriter, beanMetawidgetIndent);
+ context.put("beanMetawidget", stringWriter.toString().trim());
+
+ Map namespaces = this.searchMetawidget.getNamespaces();
+ namespaces.putAll(this.beanMetawidget.getNamespaces());
+ namespaces.keySet().removeAll(existingNamespaces.keySet());
+ context.put("metawidgetNamespaces", namespacesToString(namespaces));
+ }
+
+ protected String namespacesToString(final Map namespaces) {
+ StringBuilder builder = new StringBuilder();
+
+ for (Map.Entry entry : namespaces.entrySet()) {
+ // At the start, break out of the current quote. Field must be in quotes so that we're valid XML
+
+ builder.append("\"\r\n\txmlns:");
+ builder.append(entry.getKey());
+ builder.append("=\"");
+ builder.append(entry.getValue());
+ }
+
+ return builder.toString();
+ }
+
+ private void setPrimaryKeyMetaData(Map context, final JavaClass entity) {
+ String pkName = "id";
+ String pkType = "Long";
+ String nullablePkType = "Long";
+ for (Member m : entity.getMembers()) {
+ if (m.hasAnnotation(Id.class)) {
+ if (m instanceof Field) {
+ Field field = (Field) m;
+ pkName = field.getName();
+ pkType = field.getType();
+ break;
+ } else if (m instanceof Member) {
+ Method method = (Method) m;
+ pkName = method.getName().substring(3);
+ if (method.getName().startsWith("get")) {
+ pkType = method.getReturnType();
+ } else {
+ pkType = ((Parameter) method.getParameters().get(0)).getType();
+ }
+ break;
+ }
+ }
+ }
+
+ if ("int".equals(pkType)) {
+ nullablePkType = Integer.class.getSimpleName();
+ } else if ("short".equals(pkType)) {
+ nullablePkType = Short.class.getSimpleName();
+ } else if ("byte".equals(pkType)) {
+ nullablePkType = Byte.class.getSimpleName();
+ }
+
+ context.put("primaryKey", pkName);
+ context.put("primaryKeyCC", StringUtils.capitalize(pkName));
+ context.put("primaryKeyType", pkType);
+ context.put("nullablePrimaryKeyType", nullablePkType);
+ }
+}
diff --git a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/config/ForgeConfigReader.java b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/config/ForgeConfigReader.java
index 021b410434..5dba48d9ab 100644
--- a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/config/ForgeConfigReader.java
+++ b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/config/ForgeConfigReader.java
@@ -23,6 +23,7 @@
import org.jboss.forge.env.Configuration;
import org.jboss.forge.project.Project;
+import org.jboss.forge.scaffold.faces.util.AnnotationLookup;
import org.metawidget.config.impl.BaseConfigReader;
/**
@@ -42,12 +43,15 @@ public class ForgeConfigReader
private static final String PROJECT_ELEMENT_NAME = "forgeProject";
+ private static final String ANNOTATION_LOOKUP = "annotationLookup";
+
//
// Private members
//
private Configuration config;
private Project project;
+ private AnnotationLookup annotationLookup;
//
// Constructor
@@ -57,6 +61,7 @@ public ForgeConfigReader(Configuration config, Project project)
{
this.config = config;
this.project = project;
+ this.annotationLookup = new AnnotationLookup(project);
}
//
@@ -66,7 +71,7 @@ public ForgeConfigReader(Configuration config, Project project)
@Override
protected boolean isNative(String name)
{
- if (PROJECT_ELEMENT_NAME.equals(name))
+ if (PROJECT_ELEMENT_NAME.equals(name) || ANNOTATION_LOOKUP.equals(name))
{
return true;
}
@@ -86,6 +91,9 @@ protected Object createNative(String name, Class> namespace, String recordedTe
{
return this.project;
}
+ if (ANNOTATION_LOOKUP.equals(name)) {
+ return this.annotationLookup;
+ }
if(CONFIG_ELEMENT_NAME.equals(name))
{
@@ -94,4 +102,5 @@ protected Object createNative(String name, Class> namespace, String recordedTe
return super.createNative(name, namespace, recordedText);
}
+
}
diff --git a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectionResultConstants.java b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectionResultConstants.java
index a85e7c99ec..6d7ed0c9f4 100644
--- a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectionResultConstants.java
+++ b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectionResultConstants.java
@@ -37,6 +37,16 @@ public final class ForgeInspectionResultConstants
public static final String ONE_TO_ONE = "one-to-one";
+ public static final String PRIMARY_KEY = "primary-key";
+
+ public static final String PRIMARY_KEY_NOT_GENERATED = "primary-key-not-generated";
+
+ public static final String ENTITY_PRIMARY_KEY = "entity-primary-key";
+
+ public static final String REVERSE_PRIMARY_KEY = "reverse-primary-key";
+
+ public static final String REVERSE_PRIMARY_KEY_TYPE = "reverse-primary-key-type";
+
//
// Private constructor
//
diff --git a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspector.java b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspector.java
index 770581d495..7358571653 100644
--- a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspector.java
+++ b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspector.java
@@ -21,6 +21,7 @@
*/
package org.jboss.forge.scaffold.faces.metawidget.inspector;
+import org.jboss.forge.scaffold.faces.util.AnnotationLookup;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.*;
import static org.metawidget.inspector.InspectionResultConstants.*;
import static org.metawidget.inspector.faces.StaticFacesInspectionResultConstants.*;
@@ -28,15 +29,12 @@
import java.util.List;
import java.util.Map;
-import javax.persistence.Embedded;
-import javax.persistence.ManyToMany;
-import javax.persistence.ManyToOne;
-import javax.persistence.OneToMany;
-import javax.persistence.OneToOne;
+import javax.persistence.*;
import org.jboss.forge.parser.java.EnumConstant;
import org.jboss.forge.parser.java.JavaEnum;
import org.jboss.forge.scaffold.faces.metawidget.inspector.propertystyle.ForgePropertyStyle.ForgeProperty;
+import org.jboss.solder.logging.Logger;
import org.metawidget.inspector.impl.BaseObjectInspector;
import org.metawidget.inspector.impl.BaseObjectInspectorConfig;
import org.metawidget.inspector.impl.propertystyle.Property;
@@ -50,76 +48,65 @@
*
* @author Richard Kennard
*/
-
public class ForgeInspector
- extends BaseObjectInspector
-{
+ extends BaseObjectInspector {
+
+ ForgeInspectorConfig config;
+ Logger log = Logger.getLogger(getClass());
+
//
// Constructor
//
-
- public ForgeInspector()
- {
- this(new BaseObjectInspectorConfig());
+ public ForgeInspector() {
+ super(new BaseObjectInspectorConfig());
}
- public ForgeInspector(BaseObjectInspectorConfig config)
- {
+ public ForgeInspector(ForgeInspectorConfig config) {
super(config);
+ this.config = config;
}
//
// Protected methods
//
-
@Override
protected Map inspectProperty(Property property)
- throws Exception
- {
+ throws Exception {
Map attributes = CollectionUtils.newHashMap();
// OneToOne
- if (property.isAnnotationPresent(OneToOne.class) || property.isAnnotationPresent(Embedded.class))
- {
+ if (property.isAnnotationPresent(OneToOne.class) || property.isAnnotationPresent(Embedded.class)) {
attributes.put(ONE_TO_ONE, TRUE);
}
// ManyToOne
- if (property.isAnnotationPresent(ManyToOne.class))
- {
- attributes
- .put(FACES_LOOKUP,
- StaticFacesUtils.wrapExpression(StringUtils.decapitalize(ClassUtils.getSimpleName(property
- .getType())) + "Bean.all"));
-
- attributes
- .put(FACES_CONVERTER_ID,
- StaticFacesUtils.wrapExpression(StringUtils.decapitalize(ClassUtils.getSimpleName(property
- .getType())) + "Bean.converter"));
+ if (property.isAnnotationPresent(ManyToOne.class)) {
+ attributes.put(FACES_LOOKUP,
+ StaticFacesUtils.wrapExpression(StringUtils.decapitalize(ClassUtils.getSimpleName(property.getType())) + "Bean.all"));
+
+ attributes.put(FACES_CONVERTER_ID,
+ StaticFacesUtils.wrapExpression(StringUtils.decapitalize(ClassUtils.getSimpleName(property.getType())) + "Bean.converter"));
}
// OneToMany and ManyToMany
- if (property.isAnnotationPresent(OneToMany.class) || property.isAnnotationPresent(ManyToMany.class))
- {
+ if (property.isAnnotationPresent(OneToMany.class) || property.isAnnotationPresent(ManyToMany.class)) {
attributes.put(N_TO_MANY, TRUE);
}
// Enums
- if ( property instanceof ForgeProperty ) {
+ if (property instanceof ForgeProperty) {
List> enumConstants = ((ForgeProperty) property).getEnumConstants();
- if (enumConstants != null)
- {
+ if (enumConstants != null) {
List lookup = CollectionUtils.newArrayList();
- for (EnumConstant anEnum : enumConstants)
- {
+ for (EnumConstant anEnum : enumConstants) {
lookup.add(anEnum.getName());
}
@@ -127,6 +114,62 @@ protected Map inspectProperty(Property property)
}
}
+ // do @Id specific handling
+ if (null != property.getAnnotation(Id.class)) {
+ attributes.put(PRIMARY_KEY, property.getName());
+
+ if (null != property.getAnnotation(GeneratedValue.class)) {
+ attributes.put(PRIMARY_KEY_NOT_GENERATED, FALSE);
+ } else {
+ attributes.put(PRIMARY_KEY_NOT_GENERATED, TRUE);
+ }
+ }
+
+ if (null != property.getAnnotation(ManyToOne.class)) {
+ attributes.put(REVERSE_PRIMARY_KEY_TYPE, property.getType());
+ }
+
+ if (attributes.containsKey(PRIMARY_KEY) && !TRUE.equals(attributes.get(PRIMARY_KEY_NOT_GENERATED))) {
+ // if primary key is not generated it cannot be hidden in view
+ attributes.remove(HIDDEN);
+ attributes.put(REQUIRED, TRUE);
+ }
+
+ if (config != null && config.getAnnotationLookup() != null) {
+ final AnnotationLookup annotationLookup = config.getAnnotationLookup();
+
+ if (attributes.containsKey(REVERSE_PRIMARY_KEY_TYPE) && null != annotationLookup) {
+ try {
+ final String reverseKey = annotationLookup.getFieldName(Id.class, attributes.get(REVERSE_PRIMARY_KEY_TYPE));
+ attributes.put(REVERSE_PRIMARY_KEY, reverseKey);
+ } catch (Exception e) {
+ throw new RuntimeException("cannot resolve reverse primary key", e);
+ }
+ }
+ }
+
+ return attributes;
+ }
+
+ @Override
+ protected Map inspectEntity(String declaredClass, String actualClass) throws Exception {
+ Map attributes = CollectionUtils.newHashMap();
+ Map superMap = super.inspectEntity(declaredClass, actualClass);
+ if (superMap != null)
+ attributes.putAll(superMap);
+
+ if (config != null && config.getAnnotationLookup() != null) {
+ final AnnotationLookup annotationLookup = config.getAnnotationLookup();
+
+ try {
+ final String primaryKey = annotationLookup.getFieldName(Id.class, declaredClass);
+ attributes.put(PRIMARY_KEY, primaryKey);
+ } catch (Exception e) {
+ log.debug("cannot resolve primary key for class "+declaredClass, e);
+ }
+ }
return attributes;
}
+
+
}
diff --git a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectorConfig.java b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectorConfig.java
new file mode 100644
index 0000000000..afe9c572c2
--- /dev/null
+++ b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectorConfig.java
@@ -0,0 +1,65 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011, 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.forge.scaffold.faces.metawidget.inspector;
+
+import org.jboss.forge.project.Project;
+import org.jboss.forge.scaffold.faces.util.AnnotationLookup;
+import org.metawidget.config.iface.NeedsResourceResolver;
+import org.metawidget.config.iface.ResourceResolver;
+import org.metawidget.inspector.impl.BaseObjectInspectorConfig;
+
+/**
+ *
+ * @author Thomas Frühbeck
+ */
+public class ForgeInspectorConfig extends BaseObjectInspectorConfig implements NeedsResourceResolver {
+
+ ResourceResolver resolver;
+ Project project;
+ AnnotationLookup annotationLookup;
+
+ @Override
+ public void setResourceResolver(ResourceResolver resourceResolver) {
+ this.resolver = resourceResolver;
+ }
+
+ public ResourceResolver getResolver() {
+ return resolver;
+ }
+
+ public void setProject(Project project) {
+ this.project = project;
+ }
+
+ public Project getProject() {
+ return project;
+ }
+
+ public void setAnnotationLookup(AnnotationLookup annotationLookup) {
+ this.annotationLookup = annotationLookup;
+ }
+
+ public AnnotationLookup getAnnotationLookup() {
+ return annotationLookup;
+ }
+
+}
diff --git a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/processor/ForgeInspectionResultProcessor.java b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/processor/ForgeInspectionResultProcessor.java
new file mode 100644
index 0000000000..786066f26f
--- /dev/null
+++ b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/processor/ForgeInspectionResultProcessor.java
@@ -0,0 +1,87 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011, 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.forge.scaffold.faces.metawidget.processor;
+
+import java.util.Map;
+import static org.metawidget.inspector.InspectionResultConstants.*;
+import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.*;
+import org.jboss.forge.project.Project;
+import org.metawidget.inspectionresultprocessor.iface.InspectionResultProcessor;
+import org.metawidget.statically.StaticMetawidget;
+import org.metawidget.statically.javacode.StaticJavaMetawidget;
+import org.metawidget.util.XmlUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ *
+ * @author Thomas Frühbeck
+ */
+public class ForgeInspectionResultProcessor implements InspectionResultProcessor {
+
+ private Project project;
+
+ public ForgeInspectionResultProcessor() {
+ }
+
+ public void setProject(Project project) {
+ this.project = project;
+ }
+
+ @Override
+ public String processInspectionResult(String inspectionResult, StaticMetawidget metawidget, Object toInspect, String type, String... names) {
+
+ Document document = XmlUtils.documentFromString(inspectionResult);
+ NodeList entities = document.getElementsByTagName(ENTITY);
+
+ if (entities.getLength() > 0) {
+ for (int i=0; i attributes = XmlUtils.getAttributesAsMap(entity);
+
+ String primaryKey = attributes.get(PRIMARY_KEY);
+ if (null != primaryKey) {
+
+ NodeList properties = document.getElementsByTagName(PROPERTY);
+ if (properties.getLength() > 0) {
+ for (int j=0; j propAttribs = XmlUtils.getAttributesAsMap(property);
+ propAttribs.put(ENTITY_PRIMARY_KEY, primaryKey);
+
+ XmlUtils.setMapAsAttributes(property, propAttribs);
+ }
+ }
+ }
+ }
+ }
+
+ inspectionResult = XmlUtils.documentToString(document, false);
+
+ return inspectionResult;
+ }
+
+}
diff --git a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/widgetbuilder/EntityWidgetBuilder.java b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/widgetbuilder/EntityWidgetBuilder.java
index 2c764625f0..4eb9a4293f 100644
--- a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/widgetbuilder/EntityWidgetBuilder.java
+++ b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/widgetbuilder/EntityWidgetBuilder.java
@@ -151,10 +151,12 @@ public StaticXmlWidget buildWidget(String elementName, Map attri
(StaticUIMetawidget) metawidget);
}
+ String reverseKey = getReversePrimaryKey(attributes);
+
Param param = new Param();
param.putAttribute("name", "id");
param.putAttribute("value",
- StaticFacesUtils.wrapExpression(StaticFacesUtils.unwrapExpression(link.getValue()) + ".id"));
+ StaticFacesUtils.wrapExpression(StaticFacesUtils.unwrapExpression(link.getValue()) + "." + reverseKey));
link.getChildren().add(param);
return link;
@@ -257,6 +259,27 @@ public StaticXmlWidget buildWidget(String elementName, Map attri
// Protected methods
//
+ protected String getReversePrimaryKey(Map attributes) {
+ String reverseKey = "id";
+ if (attributes.containsKey(REVERSE_PRIMARY_KEY))
+ reverseKey = attributes.get(REVERSE_PRIMARY_KEY);
+ return reverseKey;
+ }
+
+ protected String getPrimaryKey(Map attributes) {
+ String reverseKey = "id";
+ if (attributes.containsKey(PRIMARY_KEY))
+ reverseKey = attributes.get(PRIMARY_KEY);
+ return reverseKey;
+ }
+
+ protected String getEntityPrimaryKey(Map attributes) {
+ String reverseKey = "id";
+ if (attributes.containsKey(ENTITY_PRIMARY_KEY))
+ reverseKey = attributes.get(ENTITY_PRIMARY_KEY);
+ return reverseKey;
+ }
+
/**
* Overridden to add row creation/deletion.
*/
@@ -541,7 +564,7 @@ protected void addColumnComponent(HtmlDataTable dataTable, Map t
Param param = new Param();
param.putAttribute("name", "id");
- param.putAttribute("value", StaticFacesUtils.wrapExpression(dataTable.getAttribute("var") + ".id"));
+ param.putAttribute("value", StaticFacesUtils.wrapExpression(dataTable.getAttribute("var") + "." + getEntityPrimaryKey(columnAttributes)));
link.getChildren().add(param);
link.getChildren().add(column.getChildren().remove(1));
column.getChildren().add(link);
diff --git a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/widgetbuilder/QueryByExampleWidgetBuilder.java b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/widgetbuilder/QueryByExampleWidgetBuilder.java
index fc45440967..8517885314 100644
--- a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/widgetbuilder/QueryByExampleWidgetBuilder.java
+++ b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/metawidget/widgetbuilder/QueryByExampleWidgetBuilder.java
@@ -16,6 +16,7 @@
package org.jboss.forge.scaffold.faces.metawidget.widgetbuilder;
+import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.*;
import static org.metawidget.inspector.InspectionResultConstants.*;
import static org.metawidget.inspector.faces.StaticFacesInspectionResultConstants.*;
@@ -50,7 +51,7 @@ public StaticJavaWidget buildWidget(String elementName, Map attr
// Suppress
- if (TRUE.equals(attributes.get(HIDDEN)))
+ if (TRUE.equals(attributes.get(HIDDEN)) && !Boolean.valueOf(attributes.get(PRIMARY_KEY_NOT_GENERATED)))
{
return new StaticJavaStub();
}
@@ -74,13 +75,13 @@ public StaticJavaWidget buildWidget(String elementName, Map attr
return toReturn;
}
- // int
+ // int or short
- if (int.class.equals(clazz))
+ if (int.class.equals(clazz) || short.class.equals(clazz) || byte.class.equals(clazz))
{
StaticJavaStub toReturn = new StaticJavaStub();
toReturn.getChildren().add(
- new JavaStatement("int " + name + " = this.search.get" + StringUtils.capitalize(name) + "()"));
+ new JavaStatement(clazz.getSimpleName() + " " + name + " = this.search.get" + StringUtils.capitalize(name) + "()"));
JavaStatement ifNotEmpty = new JavaStatement("if (" + name + " != 0)");
ifNotEmpty.getChildren().add(
new JavaStatement("predicatesList.add(builder.equal(root.get(\"" + name + "\"), " + name + "))"));
@@ -108,12 +109,16 @@ public StaticJavaWidget buildWidget(String elementName, Map attr
if (attributes.containsKey(FACES_LOOKUP))
{
- StaticJavaStub toReturn = new StaticJavaStub();
+ String reverseKey = "Id";
+ if (attributes.containsKey(REVERSE_PRIMARY_KEY))
+ reverseKey = StringUtils.capitalize(attributes.get(REVERSE_PRIMARY_KEY));
+
+ StaticJavaStub toReturn = new StaticJavaStub();
JavaStatement getValue = new JavaStatement(ClassUtils.getSimpleName(type) + " " + name + " = this.search.get"
+ StringUtils.capitalize(name) + "()");
getValue.putImport(type);
toReturn.getChildren().add(getValue);
- JavaStatement ifNotEmpty = new JavaStatement("if (" + name + " != null && " + name + ".getId() != null)");
+ JavaStatement ifNotEmpty = new JavaStatement("if (" + name + " != null && " + name + ".get" + reverseKey + "() != null)");
ifNotEmpty.getChildren().add(
new JavaStatement("predicatesList.add(builder.equal(root.get(\"" + name + "\"), " + name + "))"));
toReturn.getChildren().add(ifNotEmpty);
diff --git a/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/util/AnnotationLookup.java b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/util/AnnotationLookup.java
new file mode 100644
index 0000000000..cfe2a96fe0
--- /dev/null
+++ b/scaffold-faces/src/main/java/org/jboss/forge/scaffold/faces/util/AnnotationLookup.java
@@ -0,0 +1,107 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011, 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.forge.scaffold.faces.util;
+
+import java.io.FileNotFoundException;
+import org.jboss.forge.parser.java.Field;
+import org.jboss.forge.parser.java.JavaSource;
+import org.jboss.forge.parser.java.Member;
+import org.jboss.forge.parser.java.Method;
+import org.jboss.forge.project.Project;
+import org.jboss.forge.project.facets.JavaSourceFacet;
+import org.metawidget.util.simple.StringUtils;
+
+/**
+ * utility for easy lookup of fields or properties in related entities of the domain model
+ * @author Thomas Frühbeck
+ */
+public class AnnotationLookup {
+
+ public static final String JAVA_EXTENSION = ".java";
+
+ private Project project;
+
+ public AnnotationLookup(Project project) {
+ this.project = project;
+ }
+
+ /**
+ * lookup the annotated member of the class
+ * @param annotation
+ * @param qualifiedType
+ * @return
+ * @throws FileNotFoundException
+ */
+ public Member lookup (Class annotation, String qualifiedType) throws FileNotFoundException {
+ JavaSourceFacet java = project.getFacet(JavaSourceFacet.class);
+ JavaSource javaSource = java.getJavaResource(qualifiedType).getJavaSource();
+
+ Member member = lookup(javaSource, annotation);
+ return member;
+ }
+
+ /**
+ * convert the member to a field name, assumes JavaBeans notation
+ * @param member
+ * @return
+ */
+ public String getFieldName(Member member) {
+ if (null == member)
+ return null;
+ if (member instanceof Method) {
+ String methodName = member.getName();
+ return StringUtils.decapitalize(methodName.substring(3));
+ } else if (member instanceof Field) {
+ return member.getName();
+ }
+ return null;
+ }
+
+ /**
+ * get the field name of the annotated member of the class
+ * @param annotation
+ * @param qualifiedType
+ * @return
+ * @throws FileNotFoundException
+ */
+ public String getFieldName (Class annotation, String qualifiedType) throws FileNotFoundException {
+ Member member = lookup(annotation, qualifiedType);
+ return getFieldName(member);
+ }
+
+ /**
+ * find a member annotated with this annotation.
+ * @param javaSource
+ * @param ann
+ * @return
+ */
+ public Member lookup(JavaSource extends JavaSource> javaSource, Class ann) {
+ //@TODO Is not prepared for multiple PrimKeys
+ for (Member extends JavaSource,?> member : javaSource.getMembers()) {
+ if (member.hasAnnotation(ann)) {
+ return member;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/scaffold-faces/src/main/resources/scaffold/faces/BackingBean.jv b/scaffold-faces/src/main/resources/scaffold/faces/BackingBean.jv
index 30c24043da..b706c30032 100644
--- a/scaffold-faces/src/main/resources/scaffold/faces/BackingBean.jv
+++ b/scaffold-faces/src/main/resources/scaffold/faces/BackingBean.jv
@@ -45,13 +45,13 @@ public class @{entity.getName()}Bean implements Serializable {
* Support creating and retrieving @{entity.getName()} entities
*/
- private Long id;
+ private @{nullablePrimaryKeyType} id;
- public Long getId() {
+ public @{nullablePrimaryKeyType} getId() {
return this.id;
}
- public void setId(Long id) {
+ public void setId(@{nullablePrimaryKeyType} id) {
this.id = id;
}
@@ -103,7 +103,7 @@ public class @{entity.getName()}Bean implements Serializable {
return "search?faces-redirect=true";
} else {
this.entityManager.merge(this.@{ccEntity});
- return "view?faces-redirect=true&id=" + this.@{ccEntity}.getId();
+ return "view?faces-redirect=true&id=" + this.@{ccEntity}.get@{primaryKeyCC}();
}
} catch( Exception e ) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage( e.getMessage() ));
@@ -234,7 +234,7 @@ public class @{entity.getName()}Bean implements Serializable {
return "";
}
- return String.valueOf(((@{entity.getName()}) value).getId());
+ return String.valueOf(((@{entity.getName()}) value).get@{primaryKeyCC}());
}
};
}
diff --git a/scaffold-faces/src/main/resources/scaffold/faces/metawidget-bean.xml b/scaffold-faces/src/main/resources/scaffold/faces/metawidget-bean.xml
index 9650a0cd79..32555ce1c4 100644
--- a/scaffold-faces/src/main/resources/scaffold/faces/metawidget-bean.xml
+++ b/scaffold-faces/src/main/resources/scaffold/faces/metawidget-bean.xml
@@ -25,10 +25,16 @@
-
+
+
+
+
+
+
+
@@ -45,7 +51,17 @@
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scaffold-faces/src/main/resources/scaffold/faces/metawidget-entity.xml b/scaffold-faces/src/main/resources/scaffold/faces/metawidget-entity.xml
index 8d3c545aea..f03a29a675 100644
--- a/scaffold-faces/src/main/resources/scaffold/faces/metawidget-entity.xml
+++ b/scaffold-faces/src/main/resources/scaffold/faces/metawidget-entity.xml
@@ -25,10 +25,16 @@
-
+
+
+
+
+
+
+
@@ -44,6 +50,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/scaffold-faces/src/main/resources/scaffold/faces/metawidget-qbe.xml b/scaffold-faces/src/main/resources/scaffold/faces/metawidget-qbe.xml
index 03e3582cc5..90fac2db26 100644
--- a/scaffold-faces/src/main/resources/scaffold/faces/metawidget-qbe.xml
+++ b/scaffold-faces/src/main/resources/scaffold/faces/metawidget-qbe.xml
@@ -24,10 +24,16 @@
-
+
+
+
+
+
+
+
@@ -44,7 +50,17 @@
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scaffold-faces/src/main/resources/scaffold/faces/metawidget-search.xml b/scaffold-faces/src/main/resources/scaffold/faces/metawidget-search.xml
index 69baabe4d8..1e9f8f7c45 100644
--- a/scaffold-faces/src/main/resources/scaffold/faces/metawidget-search.xml
+++ b/scaffold-faces/src/main/resources/scaffold/faces/metawidget-search.xml
@@ -24,10 +24,16 @@
-
+
+
+
+
+
+
+
@@ -44,7 +50,17 @@
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/PrimaryKeyFacesScaffoldTest.java b/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/PrimaryKeyFacesScaffoldTest.java
new file mode 100644
index 0000000000..8d8e7714ad
--- /dev/null
+++ b/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/PrimaryKeyFacesScaffoldTest.java
@@ -0,0 +1,242 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.jboss.forge.scaffold.faces;
+
+import java.io.FileNotFoundException;
+import java.io.Serializable;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.persistence.*;
+import junit.framework.Assert;
+import org.jboss.arquillian.protocol.servlet.arq514hack.descriptors.impl.web.Strings;
+import org.jboss.forge.parser.JavaParser;
+import org.jboss.forge.parser.java.Field;
+import org.jboss.forge.parser.java.JavaClass;
+import org.jboss.forge.parser.java.Method;
+import org.jboss.forge.parser.java.util.Refactory;
+import org.jboss.forge.project.Project;
+import org.jboss.forge.project.facets.JavaSourceFacet;
+import org.jboss.forge.project.facets.WebResourceFacet;
+import org.jboss.forge.project.services.ResourceFactory;
+import org.jboss.forge.resources.FileResource;
+import org.jboss.forge.resources.java.JavaResource;
+import org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspector;
+import org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectorConfig;
+import org.jboss.forge.scaffold.faces.util.AnnotationLookup;
+import org.jboss.forge.shell.util.Streams;
+import org.junit.Test;
+import org.metawidget.util.XmlUtils;
+import org.metawidget.util.simple.StringUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import static org.junit.Assert.*;
+import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.*;
+import org.jboss.forge.scaffold.faces.metawidget.inspector.propertystyle.ForgePropertyStyle;
+import org.jboss.forge.scaffold.faces.metawidget.inspector.propertystyle.ForgePropertyStyleConfig;
+import org.jboss.forge.scaffold.faces.metawidget.processor.ForgeInspectionResultProcessor;
+import static org.metawidget.inspector.InspectionResultConstants.*;
+
+/**
+ *
+ * @author Thomas Frühbeck
+ */
+public class PrimaryKeyFacesScaffoldTest extends AbstractFacesScaffoldTest {
+
+ @Inject
+ private ResourceFactory factory;
+
+ @Test
+ public void testGenerateFromLegacyPrimaryKey() throws Exception {
+ final String parentPrimaryKey = "parentPrimaryKey";
+ final String parentPrimaryKeyCC = StringUtils.capitalize(parentPrimaryKey);
+
+ Project project = setupScaffoldProject();
+
+ queueInputLines("");
+ generateAlternateEntity(project, "com.test.model", "Parent", parentPrimaryKey);
+
+ getShell().execute("entity --named Child");
+ getShell().execute("field string --named name");
+ getShell().execute("field manyToOne --named parent --fieldType com.test.model.Parent.java --inverseFieldName children");
+
+ queueInputLines("", "", "");
+ getShell().execute("scaffold from-entity com.test.model.* --scaffoldType faces");
+
+ WebResourceFacet web = project.getFacet(WebResourceFacet.class);
+ JavaSourceFacet java = project.getFacet(JavaSourceFacet.class);
+ // Code
+ JavaResource parentBean = java.getJavaResource("com.test.view.ParentBean");
+ JavaResource childBean = java.getJavaResource("com.test.view.ChildBean");
+
+ String parentContent = Streams.toString(parentBean.getResourceInputStream());
+ assertTrue(parentContent.contains("id=\" + this.parent.get" + parentPrimaryKeyCC + "()"));
+ assertTrue(parentContent.contains("valueOf(((Parent) value).get" + parentPrimaryKeyCC + "()"));
+
+ String childContent = Streams.toString(childBean.getResourceInputStream());
+ assertTrue(childContent.contains("this.child.getId()"));
+
+ // View
+ FileResource> view = web.getWebResource("scaffold/parent/view.xhtml");
+ assertTrue(view.exists());
+ String contents = Streams.toString(view.getResourceInputStream());
+ assertTrue(contents.contains(
+ "template=\"/resources/scaffold/page.xhtml"));
+
+ view = web.getWebResource("scaffold/parent/search.xhtml");
+ contents = Streams.toString(view.getResourceInputStream());
+ assertTrue(view.exists());
+ assertTrue(contents.contains(" "));
+
+ view = web.getWebResource("scaffold/child/view.xhtml");
+ contents = Streams.toString(view.getResourceInputStream());
+ assertTrue(view.exists());
+ assertTrue(contents.contains("childBean.child.parent." + parentPrimaryKey));
+}
+
+ private JavaResource generateAlternateEntity(Project project, String pkg, String entityName, String primaryKey) throws FileNotFoundException {
+ JavaSourceFacet java = project.getFacet(JavaSourceFacet.class);
+ JavaClass javaClass = JavaParser.create(JavaClass.class).setPackage(pkg).setName(entityName).setPublic().addAnnotation(Entity.class).getOrigin().addInterface(Serializable.class);
+
+ String idName = primaryKey;
+ if (idName == null) {
+ StringUtils.decapitalize(entityName + "Id");
+ }
+
+ Field id = javaClass.addField("private String " + idName + " = null;");
+ id.addAnnotation(Id.class);
+ id.addAnnotation(GeneratedValue.class).setEnumValue("strategy", GenerationType.AUTO);
+ id.addAnnotation(Column.class).setStringValue("name", idName).setLiteralValue("updatable", "false").setLiteralValue("nullable", "false");
+
+ Refactory.createGetterAndSetter(javaClass, id);
+
+ Field name = javaClass.addField("private String name = null;");
+ Refactory.createGetterAndSetter(javaClass, name);
+
+ Refactory.createToStringFromFields(javaClass, id);
+ Refactory.createHashCodeAndEquals(javaClass);
+
+ return java.saveJavaSource(javaClass);
+ }
+
+ @Test
+ public void testPrimaryKeys() throws Exception {
+ Project project = initializeJavaProject();
+ queueInputLines("HIBERNATE", "JBOSS_AS7", "");
+ getShell().execute("persistence setup");
+
+ for (PrimaryKeyTestBase testClass : new PrimaryKeyTestBase[]{
+ new PrimaryKeyFieldTest(), new PrimaryKeyPropertyTest(), new PrimaryKeyPropertyAssignedTest()}) {
+ testPrimaryKey(project, testClass);
+ }
+ }
+
+ public void testPrimaryKey(Project project, PrimaryKeyTestBase testClass) throws Exception {
+
+ final String parentPrimaryKey = "primaryKey";
+ final String parentPrimaryKeyCC = StringUtils.capitalize(parentPrimaryKey);
+
+ ForgeInspectorConfig config = new ForgeInspectorConfig();
+ config.setAnnotationLookup(new AnnotationLookup(project));
+ config.setPropertyStyle(new ForgePropertyStyle(new ForgePropertyStyleConfig().setProject(project)));
+ ForgeInspectionResultProcessor processor = new ForgeInspectionResultProcessor();
+
+ generatePkEntity(project, "org.test", "Parent", parentPrimaryKey, testClass);
+
+ String xml = new ForgeInspector(config).inspect(null, "org.test.Parent");
+ xml = processor.processInspectionResult(xml, null, project, xml, new String[]{});
+
+ Document document = XmlUtils.documentFromString(xml);
+ assertEquals("inspection-result", document.getFirstChild().getNodeName());
+ Element entity = (Element) document.getFirstChild().getFirstChild();
+ assertEquals(ENTITY, entity.getNodeName());
+
+ Map attributes = XmlUtils.getAttributesAsMap(entity);
+ assertEquals(parentPrimaryKey, attributes.get(PRIMARY_KEY));
+
+ NodeList properties = entity.getElementsByTagName(PROPERTY);
+ for (int i = 0; i < properties.getLength(); i++) {
+ Element prop = (Element) properties.item(i);
+ attributes = XmlUtils.getAttributesAsMap(prop);
+
+ if (!(testClass instanceof PrimaryKeyPropertyAssignedTest)) {
+ assertTrue(attributes.containsKey(PRIMARY_KEY_NOT_GENERATED));
+ }
+ }
+ Element property = (Element) entity.getFirstChild();
+ attributes = XmlUtils.getAttributesAsMap(property);
+ assertEquals(parentPrimaryKey, attributes.get(PRIMARY_KEY));
+ assertEquals(parentPrimaryKey, attributes.get(ENTITY_PRIMARY_KEY));
+
+ }
+
+ private JavaResource generatePkEntity(Project project, String pkg, String entityName, String primaryKey, PrimaryKeyTestBase pkTest) throws FileNotFoundException {
+ JavaSourceFacet java = project.getFacet(JavaSourceFacet.class);
+ JavaClass javaClass = JavaParser.create(JavaClass.class).setPackage(pkg).setName(entityName).setPublic().addAnnotation(Entity.class).getOrigin().addInterface(Serializable.class);
+
+ String idName = primaryKey;
+ if (idName == null) {
+ StringUtils.decapitalize(entityName + "Id");
+ }
+
+ Field id = javaClass.addField("private String " + idName + " = null;");
+ if (pkTest.field) {
+ id.addAnnotation(Id.class);
+ if (pkTest.generated) {
+ id.addAnnotation(GeneratedValue.class).setEnumValue("strategy", GenerationType.AUTO);
+ id.addAnnotation(Column.class).setStringValue("name", idName).setLiteralValue("updatable", "false").setLiteralValue("nullable", "false");
+ }
+ }
+
+
+
+ Refactory.createGetterAndSetter(javaClass, id);
+ if (!pkTest.field) {
+ Method getPk = javaClass.getMethod("get" + StringUtils.capitalize(idName));
+ getPk.addAnnotation(Id.class);
+ if (pkTest.generated) {
+ getPk.addAnnotation(GeneratedValue.class).setEnumValue("strategy", GenerationType.AUTO);
+ getPk.addAnnotation(Column.class).setStringValue("name", idName).setLiteralValue("updatable", "false").setLiteralValue("nullable", "false");
+ }
+ }
+
+ Field name = javaClass.addField("private String name = null;");
+ Refactory.createGetterAndSetter(javaClass, name);
+ Field type = javaClass.addField("private String type = null;");
+ Refactory.createGetterAndSetter(javaClass, type);
+
+ return java.saveJavaSource(javaClass);
+ }
+
+
+ class PrimaryKeyTestBase {
+
+ public boolean generated, field;
+ }
+
+ class PrimaryKeyFieldTest extends PrimaryKeyTestBase {
+
+ {
+ generated = true;
+ field = true;
+ }
+ }
+
+ class PrimaryKeyPropertyTest extends PrimaryKeyTestBase {
+
+ {
+ generated = true;
+ field = false;
+ }
+ }
+
+ class PrimaryKeyPropertyAssignedTest extends PrimaryKeyTestBase {
+
+ {
+ generated = false;
+ field = true;
+ }
+ }
+}
diff --git a/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectorTest.java b/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectorTest.java
index 1e5280b052..e1accb29af 100644
--- a/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectorTest.java
+++ b/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/metawidget/inspector/ForgeInspectorTest.java
@@ -72,7 +72,7 @@ public void testRelationships()
assertEquals("manyToOne", property.getAttribute(NAME));
assertEquals("#{forgeInspectorTest$BarBean.all}", property.getAttribute(FACES_LOOKUP));
assertEquals("#{forgeInspectorTest$BarBean.converter}", property.getAttribute(FACES_CONVERTER_ID));
- assertEquals(3, property.getAttributes().getLength());
+ assertEquals(4, property.getAttributes().getLength());
property = XmlUtils.getNextSiblingElement(property);
assertEquals(PROPERTY, property.getNodeName());
diff --git a/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/scenario/petclinic/FacesScaffoldPetClinicTest.java b/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/scenario/petclinic/FacesScaffoldPetClinicTest.java
index a80df48298..38142d22f4 100644
--- a/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/scenario/petclinic/FacesScaffoldPetClinicTest.java
+++ b/scaffold-faces/src/test/java/org/jboss/forge/scaffold/faces/scenario/petclinic/FacesScaffoldPetClinicTest.java
@@ -54,7 +54,8 @@ public class FacesScaffoldPetClinicTest extends AbstractFacesScaffoldTest
public void testGenerate() throws Exception
{
Project current = getShell().getCurrentProject();
- Project project = setupScaffoldProject("petClinic");
+ final String targetDir = "petClinic";
+ Project project = setupScaffoldProject(targetDir);
queueInputLines("");
getShell().execute("entity --named Owner");
@@ -97,7 +98,7 @@ public void testGenerate() throws Exception
// Check search screen has h:message
- FileResource> search = web.getWebResource("petClinic/pet/search.xhtml");
+ FileResource> search = web.getWebResource(targetDir+"/pet/search.xhtml");
Assert.assertTrue(search.exists());
String contents = Streams.toString(search.getResourceInputStream());
@@ -111,14 +112,14 @@ public void testGenerate() throws Exception
// Check search screen has boolean graphic
- metawidget = "\t\t\t\t\t\r\n";
+ metawidget = "\t\t\t\t\t\r\n";
metawidget += "\t\t\t\t\t\t\r\n";
metawidget += "\t\t\t\t\t\t \r\n";
metawidget += "\t\t\t\t\t \r\n";
Assert.assertTrue(contents.contains(metawidget));
- metawidget = "\t\t\t\t\t\r\n";
+ metawidget = "\t\t\t\t\t\r\n";
metawidget += "\t\t\t\t\t\t\r\n";
metawidget += "\t\t\t\t\t\t\r\n";
metawidget += "\t\t\t\t\t \r\n";
@@ -127,7 +128,7 @@ public void testGenerate() throws Exception
// Check create screen has h:selectBooleanCheckbox
- FileResource> create = web.getWebResource("petClinic/pet/create.xhtml");
+ FileResource> create = web.getWebResource(targetDir+"/pet/create.xhtml");
Assert.assertTrue(create.exists());
contents = Streams.toString(create.getResourceInputStream());
@@ -141,7 +142,7 @@ public void testGenerate() throws Exception
// Check view screen has boolean graphic
- FileResource> view = web.getWebResource("petClinic/pet/view.xhtml");
+ FileResource> view = web.getWebResource(targetDir+"/pet/view.xhtml");
Assert.assertTrue(view.exists());
contents = Streams.toString(view.getResourceInputStream());