Skip to content

Commit

Permalink
FORGE-916 Implementation of support for bidirectional deletes
Browse files Browse the repository at this point in the history
Added support into ForgeInspector to detect the owning and inverse sides of a bi-directional relationship.
Based on the availability of these attributes during the RemoveEntityWidget Metawidget construction, enhanced deletion logic is made available given the knowledege of the bidirectional relationships. The relationships are modified in both directions during deletion of a JPA entity.
  • Loading branch information
VineetReynolds committed Jun 25, 2013
1 parent bad139e commit 2d5a5ea
Show file tree
Hide file tree
Showing 8 changed files with 687 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public class FacesScaffold extends BaseFacet implements ScaffoldProvider
//
protected CompiledTemplateResource backingBeanTemplate;
protected int backingBeanTemplateQbeMetawidgetIndent;
protected int backingBeanTemplateRmEntityMetawidgetIndent;
protected CompiledTemplateResource viewUtilsTemplate;
protected CompiledTemplateResource taglibTemplate;
protected CompiledTemplateResource viewTemplate;
Expand All @@ -163,6 +164,7 @@ public class FacesScaffold extends BaseFacet implements ScaffoldProvider
protected StaticHtmlMetawidget searchMetawidget;
protected StaticHtmlMetawidget beanMetawidget;
protected StaticJavaMetawidget qbeMetawidget;
protected StaticJavaMetawidget rmEntityMetawidget;

private Configuration config;
private ShellPrintWriter writer;
Expand Down Expand Up @@ -239,6 +241,10 @@ private void resetMetaWidgets()
this.qbeMetawidget = new StaticJavaMetawidget();
this.qbeMetawidget.setConfigReader(configReader);
this.qbeMetawidget.setConfig("scaffold/faces/metawidget-qbe.xml");

this.rmEntityMetawidget = new StaticJavaMetawidget();
this.rmEntityMetawidget.setConfigReader(configReader);
this.rmEntityMetawidget.setConfig("scaffold/faces/metawidget-remove-entity.xml");
}

@Override
Expand Down Expand Up @@ -270,18 +276,30 @@ public List<Resource<?>> generateFromEntity(String targetDir, final Resource<?>
context.put("entity", entity);
String ccEntity = StringUtils.decapitalize(entity.getName());
context.put("ccEntity", ccEntity);
context.put("rmEntity", ccEntity + "ToDelete");
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());

// Prepare removeEntityMetawidget
this.rmEntityMetawidget.setPath(entity.getQualifiedName());
stringWriter = new StringWriter();
this.rmEntityMetawidget.write(stringWriter, this.backingBeanTemplateRmEntityMetawidgetIndent);
context.put("rmEntityMetawidget", stringWriter.toString().trim());

// Prepare Java imports
Set<String> qbeMetawidgetImports = this.qbeMetawidget.getImports();
qbeMetawidgetImports.remove(entity.getQualifiedName());
context.put("qbeMetawidgetImports",
CollectionUtils.toString(qbeMetawidgetImports, ";\r\nimport ", true, false));
Set<String> rmEntityMetawidgetImports = this.rmEntityMetawidget.getImports();
Set<String> metawidgetImports = CollectionUtils.newHashSet();
metawidgetImports.addAll(qbeMetawidgetImports);
metawidgetImports.addAll(rmEntityMetawidgetImports);
metawidgetImports.remove(entity.getQualifiedName());
context.put("metawidgetImports",
CollectionUtils.toString(metawidgetImports, ";\r\nimport ", true, false));

// Create the Backing Bean for this entity
JavaClass viewBean = JavaParser.parse(JavaClass.class, this.backingBeanTemplate.render(context));
Expand Down Expand Up @@ -484,6 +502,7 @@ protected void loadTemplates()
this.backingBeanTemplate = this.compiler.compile(BACKING_BEAN_TEMPLATE);
String template = Streams.toString(this.backingBeanTemplate.getSourceTemplateResource().getInputStream());
this.backingBeanTemplateQbeMetawidgetIndent = parseIndent(template, "@{qbeMetawidget}");
this.backingBeanTemplateRmEntityMetawidgetIndent = parseIndent(template, "@{rmEntityMetawidget}");
}
if (this.viewUtilsTemplate == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ public final class ForgeInspectionResultConstants
public static final String N_TO_MANY = "n-to-many";

public static final String ONE_TO_ONE = "one-to-one";

public static final String JPA_ONE_TO_ONE = "one-to-one";

public static final String JPA_MANY_TO_ONE = "many-to-one";

public static final String JPA_ONE_TO_MANY = "one-to-many";

public static final String JPA_MANY_TO_MANY = "many-to-many";

public static final String JPA_REL_TYPE = "jpa-relation-type";

/**
* Whether the field is an Id.
Expand All @@ -38,6 +48,16 @@ public final class ForgeInspectionResultConstants
* Whether the field represents a generated value
*/
public static final String GENERATED_VALUE = "generated-value";

/**
* The owning field of a bi-directional relationship
*/
public static final String OWNING_FIELD = "owning-field";

/**
* The inverse field of a bi-directional relationship
*/
public static final String INVERSE_FIELD = "inverse-field";

//
// Private constructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@
package org.jboss.forge.scaffold.faces.metawidget.inspector;

import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.GENERATED_VALUE;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.INVERSE_FIELD;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.JPA_MANY_TO_MANY;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.JPA_MANY_TO_ONE;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.JPA_ONE_TO_ONE;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.N_TO_MANY;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.JPA_ONE_TO_MANY;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.ONE_TO_ONE;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.OWNING_FIELD;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.PRIMARY_KEY;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.JPA_REL_TYPE;
import static org.jboss.forge.scaffold.faces.metawidget.inspector.ForgeInspectionResultConstants.REVERSE_PRIMARY_KEY;
import static org.metawidget.inspector.InspectionResultConstants.LOOKUP;
import static org.metawidget.inspector.InspectionResultConstants.TRUE;
Expand Down Expand Up @@ -37,6 +44,7 @@
import org.metawidget.util.ClassUtils;
import org.metawidget.util.CollectionUtils;
import org.metawidget.util.simple.StringUtils;
import org.w3c.dom.Element;

/**
* Inspects Forge-specific metadata.
Expand All @@ -46,6 +54,7 @@
public class ForgeInspector
extends BaseObjectInspector
{

//
// Constructor
//
Expand All @@ -60,6 +69,11 @@ public ForgeInspector(BaseObjectInspectorConfig config)
super(config);
}

@Override
public Element inspectAsDom( Object toInspect, String type, String... names ) {
return super.inspectAsDom(toInspect, type, names);
}

//
// Protected methods
//
Expand All @@ -75,12 +89,19 @@ protected Map<String, String> inspectProperty(Property property)
if (property.isAnnotationPresent(OneToOne.class) || property.isAnnotationPresent(Embedded.class))
{
attributes.put(ONE_TO_ONE, TRUE);
attributes.put(JPA_REL_TYPE, JPA_ONE_TO_ONE);
getReversePrimaryKey(property, attributes);
if (property.isAnnotationPresent(OneToOne.class))
{
getOneToOneBidirectionalProperties(property, attributes);
}
}

// ManyToOne

if (property.isAnnotationPresent(ManyToOne.class))
{
attributes.put(JPA_REL_TYPE, JPA_MANY_TO_ONE);
attributes
.put(FACES_LOOKUP,
StaticFacesUtils.wrapExpression(StringUtils.decapitalize(ClassUtils.getSimpleName(property
Expand All @@ -93,21 +114,26 @@ protected Map<String, String> inspectProperty(Property property)

// Reverse primary key

for (Property reverseProperty : getProperties(property.getType()).values())
{
if (reverseProperty.isAnnotationPresent(Id.class))
{
attributes.put(REVERSE_PRIMARY_KEY, reverseProperty.getName());
break;
}
}
getReversePrimaryKey(property, attributes);
getManyToOneBidirectionalProperties(property, attributes);
}

// OneToMany and ManyToMany

if (property.isAnnotationPresent(OneToMany.class) || property.isAnnotationPresent(ManyToMany.class))
{
attributes.put(N_TO_MANY, TRUE);
getCollectionReversePrimaryKey(property, attributes);
if (property.isAnnotationPresent(OneToMany.class))
{
attributes.put(JPA_REL_TYPE, JPA_ONE_TO_MANY);
getOneToManyBidirectionalProperties(property, attributes);
}
else
{
attributes.put(JPA_REL_TYPE, JPA_MANY_TO_MANY);
getManyToManyBidirectionalProperties(property, attributes);
}
}

// Enums
Expand Down Expand Up @@ -142,4 +168,125 @@ protected Map<String, String> inspectProperty(Property property)

return attributes;
}

private void getReversePrimaryKey(Property property, Map<String, String> attributes)
{
// Reverse primary key

for (Property reverseProperty : getProperties(property.getType()).values())
{
if (reverseProperty.isAnnotationPresent(Id.class))
{
attributes.put(REVERSE_PRIMARY_KEY, reverseProperty.getName());
break;
}
}
}

private void getCollectionReversePrimaryKey(Property property, Map<String, String> attributes)
{
// Reverse primary key

for (Property reverseProperty : getProperties(property.getGenericType()).values())
{
if (reverseProperty.isAnnotationPresent(Id.class))
{
attributes.put(REVERSE_PRIMARY_KEY, reverseProperty.getName());
break;
}
}
}

private void getOneToOneBidirectionalProperties(Property property, Map<String, String> attributes)
{
String owningProperty = property.getAnnotation(OneToOne.class).mappedBy();
/*
* Set the inverse association only when the mappedBy attribute is available. We do not support the ability to
* identify the owning and inverse sides through JoinColumn or PrimaryKeyJoinColumn annotations yet.
*/
if (!owningProperty.isEmpty())
{
attributes.put(INVERSE_FIELD, property.getName());
for (Property reverseProperty : getProperties(property.getType()).values())
{
String reversePropertyName = reverseProperty.getName();
if (reversePropertyName.equals(owningProperty))
{
attributes.put(OWNING_FIELD, reversePropertyName);
break;
}
}
}
}

private void getManyToOneBidirectionalProperties(Property property, Map<String, String> attributes)
{
String propertyName = property.getName();
// The ManyToOne side is always the owning side
attributes.put(OWNING_FIELD, propertyName);
for (Property reverseProperty : getProperties(property.getType()).values())
{
if (reverseProperty.isAnnotationPresent(OneToMany.class))
{
String mappedPropertyName = reverseProperty.getAnnotation(OneToMany.class).mappedBy();
/*
* Set the inverse association only when the mappedBy attribute is available. This is as per the JPA
* specification. We'll ignore the ability of JPA providers like Hibernate to automatically treat a
* OneToMany field as the inverse side of the association.
*/
if (mappedPropertyName.equals(propertyName))
{
attributes.put(INVERSE_FIELD, reverseProperty.getName());
break;
}
}
}
}

private void getOneToManyBidirectionalProperties(Property property, Map<String, String> attributes)
{
String owningProperty = property.getAnnotation(OneToMany.class).mappedBy();
/*
* Set the inverse association only when the mappedBy attribute is available. This is as per the JPA
* specification. We'll ignore the ability of JPA providers like Hibernate to automatically treat a OneToMany
* field as the inverse side of the association.
*/
if (!owningProperty.isEmpty())
{
attributes.put(INVERSE_FIELD, property.getName());
for (Property reverseProperty : getProperties(property.getGenericType()).values())
{
String reversePropertyName = reverseProperty.getName();
if (reversePropertyName.equals(owningProperty))
{
attributes.put(OWNING_FIELD, reversePropertyName);
break;
}
}
}
}

private void getManyToManyBidirectionalProperties(Property property, Map<String, String> attributes)
{
String owningProperty = property.getAnnotation(ManyToMany.class).mappedBy();
/*
* Set the inverse association only when the mappedBy attribute is available. This is as per the JPA
* specification. We'll ignore the ability of JPA providers like Hibernate to automatically treat a ManyToMany
* field as the inverse side of the association.
*/
if (!owningProperty.isEmpty())
{
attributes.put(INVERSE_FIELD, property.getName());
for (Property reverseProperty : getProperties(property.getGenericType()).values())
{
String reversePropertyName = reverseProperty.getName();
if (reversePropertyName.equals(owningProperty))
{
attributes.put(OWNING_FIELD, reversePropertyName);
break;
}
}
}
}

}
Loading

0 comments on commit 2d5a5ea

Please sign in to comment.