de.tsl2.nano.bean.def.Composition Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tsl2.nano.descriptor Show documentation
Show all versions of tsl2.nano.descriptor Show documentation
TSL2 Framework Descriptor (currency-handling, generic formatter, descriptors for beans, collections, actions and values)
/*
* File: $HeadURL$
* Id : $Id$
*
* created by: ts
* created on: 28.07.2013
*
* Copyright: (c) Thomas Schneider 2013, all rights reserved
*/
package de.tsl2.nano.bean.def;
import java.util.ArrayList;
import java.util.Collection;
import de.tsl2.nano.bean.BeanContainer;
import de.tsl2.nano.core.cls.BeanClass;
import de.tsl2.nano.core.cls.IAttribute;
import de.tsl2.nano.core.util.StringUtil;
/**
*
* On relational models, a composition child (like the uml-composition) needs a connection to it's parent. If a new
* child is created, this child has to be put into the attribute list of it's parent.
*
* Example: Customer(1)==>(*)Address. But the address cannot exist without it's parent, the customer.
*
* If a relation model needs to resolve a connection of type: Group (*) ==> (*) Player, a new table 'PlayersGroup'
* should be created as resolver: Group (*) ==> (1) PlayersGroup (1) ==> (*) Player. The #target is required to resolve this
* many-to-many relation. In this example, the members are:
* parent = Group
* child = PlayersGroup
* target = Player
*
* a second case is:
*
* Group (1) ==> Players (*) ==> (1) Type
*
* here the resolver is a collection.
*
*
* @author ts
* @version $Revision$
*/
public class Composition {
/** parent-to-child attribute, holding the parent instance. the child works as a resolver in the middle */
BeanValue parent;
/** child-to-target attribute definition. the child works as a resolver in the middle */
@SuppressWarnings("rawtypes")
IAttribute target;
/**
* constructor
*
* @param parent see {@link #parent}
*/
public Composition(BeanValue parent) {
this(parent, null);
}
/**
* constructor
*
* @param parent see {@link #parent}
* @param target see {@link #target}
*/
public Composition(BeanValue parent, IAttribute> target) {
super();
this.parent = parent;
this.target = target;
}
/**
* @return Returns the parent.
*/
public Object getParent() {
return parent.getInstance();
}
/**
* getParentContainer
*
* @return parents container holding the child items
*/
@SuppressWarnings("unchecked")
protected Collection getParentContainer() {
return (Collection) parent.getValue();
}
/**
* add new item to parents container
*
* @param newItem new child item
*/
public void add(C newItem) {
add(newItem, null);
}
/**
* add new item to parents container
*
* @param newItem new child item (resolver)
* @param targetValue (optional) target to be assigned to the child item
*/
@SuppressWarnings("unchecked")
public void add(C newItem, Object targetValue) {
if (this.target != null && targetValue != null) {
this.target.setValue(newItem, targetValue);
}
getParentContainer().add(newItem);
}
/**
* remove item from its parent container
*
* @param item to be removed
*/
public void remove(C item) {
getParentContainer().remove(item);
}
/**
* @return Returns the target.
*/
public Class> getTargetType() {
return target != null ? target.getType() : null;
}
/**
* creates a new child, connecting it to the parent instance
*
* @return new child
*/
public C createChild() {
return createChild(null);
}
/**
* creates a new child (resolver), connecting it to the parent instance and to the given target instance. call this method, if
* your target describes the middle of the connection. assigns the target value to the child instance
*
* @param targetValue (optional) target value
* @return new child
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public C createChild(Object targetValue) {
BeanClass bc = BeanClass.getBeanClass(parent.getType());
C child = (C) bc.createInstance();
add(child, targetValue);//assign the target value to the child instance
return child;
}
/**
* creates a new child (resolver), connecting it to the parent instance and to the given target instance. call this when your
* target attribute describes the right side of the connection. assigns the child to the target instance
*
* @param targetInstance (optional) target instance
* @return new resolving child
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public C createChildOnTarget(Object targetInstance) {
// BeanClass bc = BeanClass.getBeanClass(Collection.class.isAssignableFrom(parent.getType()) ? parent.getGenericType(0) : parent.getType());
BeanDefinition bc = BeanDefinition.getBeanDefinition(Collection.class.isAssignableFrom(parent.getType()) ? parent.getGenericType(0) : parent.getType());
C child = (C) (target == null ? targetInstance : bc.createInstance());
if (this.target != null && targetInstance != null) {
if (Collection.class.isAssignableFrom(this.target.getType())) {
((Collection)this.target.getValue(targetInstance)).add(child);
bc.setValue(child, StringUtil.toFirstLower(target.getDeclaringClass().getSimpleName()), targetInstance);
} else {// standard: only a single target instance
BeanContainer.createId(child);
if (this.target.getType().isAssignableFrom(child.getClass()))
this.target.setValue(targetInstance, child);
}
} else {
BeanContainer.createId(child);
}
IAttribute attr = bc.getAttribute(parent.getDeclaringClass());
if (attr != null)
attr.setValue(child, parent.getInstance());
getParentContainer().add(child);
return child;
}
/**
* creates new childs (see {@link #createChild(Object)}) for all given targets.
*
* @param targets targets to create childs for
* @return new childs, connected to parent and target
*/
public Collection createChilds(Collection> targets) {
Collection childs = new ArrayList(targets.size());
for (Object t : targets) {
childs.add(createChild(t));
}
return childs;
}
}