/*
* Initial version copyright 2008 Lockheed Martin Corporation, except
* as stated in the file entitled Licensing-Information.
*
* Modifications:
* Copyright 2009 Data Access Technologies, Inc.
* Copyright 2013 Ivar Jacobson International SA
*
* Licensed under the Academic Free License version 3.0
* (http://www.opensource.org/licenses/afl-3.0.php), except as stated
* in the file entitled Licensing-Information.
*
* Contributors:
* MDS - initial API and implementation
* IJI
*
*/
package org.modeldriven.fuml.repository.model;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.modeldriven.fuml.repository.Repository;
import org.modeldriven.fuml.repository.RepositoryArtifact;
import org.modeldriven.fuml.repository.RepositoryMapping;
import org.modeldriven.fuml.repository.RepositorylException;
import UMLPrimitiveTypes.UnlimitedNatural;
import fUML.Syntax.Classes.Kernel.Association;
import fUML.Syntax.Classes.Kernel.Class_;
import fUML.Syntax.Classes.Kernel.Classifier;
import fUML.Syntax.Classes.Kernel.Enumeration;
import fUML.Syntax.Classes.Kernel.EnumerationLiteral;
import fUML.Syntax.Classes.Kernel.Generalization;
import fUML.Syntax.Classes.Kernel.InstanceSpecification;
import fUML.Syntax.Classes.Kernel.InstanceValue;
import fUML.Syntax.Classes.Kernel.LiteralBoolean;
import fUML.Syntax.Classes.Kernel.LiteralInteger;
import fUML.Syntax.Classes.Kernel.LiteralSpecification;
import fUML.Syntax.Classes.Kernel.LiteralString;
import fUML.Syntax.Classes.Kernel.LiteralUnlimitedNatural;
import fUML.Syntax.Classes.Kernel.Package;
import fUML.Syntax.Classes.Kernel.PrimitiveType;
import fUML.Syntax.Classes.Kernel.Property;
import fUML.Syntax.Classes.Kernel.ValueSpecification;
public class ModelFactory
{
private static Log log = LogFactory.getLog(ModelFactory.class);
protected RepositoryMapping mapping;
protected Repository model;
@SuppressWarnings("unused")
private ModelFactory() {}
public ModelFactory(RepositoryMapping mapping, Repository model) {
this.mapping = mapping;
this.model = model;
}
public Package createPackage(String name, String qualifiedName, String id, RepositoryArtifact artifact) {
return createPackage(name, qualifiedName, id, null, artifact);
}
public Package createPackage(String name, String qualifiedName, String id, Package parent, RepositoryArtifact artifact) {
Package p = new Package();
p.name = name;
p.qualifiedName = qualifiedName;
p.setHref(artifact.getURN() + "#" + p.qualifiedName);
p.setXmiId(id);
if (parent != null)
parent.addPackagedElement(p);
if (parent != null) {
parent.nestedPackage.add(p);
p.nestingPackage = parent;
}
return p;
}
public Class_ createClass(String name, String id, Package pkg) {
Class_ c = new Class_();
c.name = name;
c.qualifiedName = pkg.qualifiedName + "." + c.name;
c.setXmiId(id);
pkg.addPackagedElement(c);
c.package_ = pkg;
return c;
}
public Enumeration createEnumeration(String name, String id) {
Enumeration e = new Enumeration();
e.name = name;
e.setXmiId(id);
return e;
}
public PrimitiveType createPrimitiveType(String name, String id) {
PrimitiveType t = new PrimitiveType();
t.name = name;
t.setXmiId(id);
return t;
}
public PrimitiveType createPrimitiveType(String name, String id, Package pkg) {
PrimitiveType t = new PrimitiveType();
pkg.addPackagedElement(t);
t.name = name;
t.qualifiedName = pkg.qualifiedName + "." + t.name;
t.setXmiId(id);
return t;
}
public Association createAssociation(String name, String id, Property[] members) {
Association a = new Association();
a.name = name;
a.setXmiId(id);
for (int i = 0; i < members.length; i++) {
a.memberEnd.add(members[i]);
}
return a;
}
public Association createAssociation(String name, String id) {
Association a = new Association();
a.name = name;
a.setXmiId(id);
return a;
}
public Property[] createAssociationEnds(Association assoc, String ends) {
List<Property> props = new ArrayList<Property>();
StringTokenizer st = new StringTokenizer(ends);
while (st.hasMoreTokens()) {
String token = st.nextToken();
org.modeldriven.fuml.repository.Property prop = (org.modeldriven.fuml.repository.Property)model.getElementById(token);
if (prop.getAssociation() != null &&
!prop.getAssociation().getXmiId().equals(assoc.getXmiId()))
log.warn("found existing association ("
+ prop.getAssociation().getXmiId() + ") on property ("
+ prop.getXmiId() + ") - overwriting with association ("
+ assoc.getXmiId() + ")");
prop.setAssociation(assoc);
props.add(prop.getDelegate());
if (!assoc.memberEnd.contains(prop))
assoc.memberEnd.add(prop.getDelegate());
}
Property[] result = new Property[props.size()];
props.toArray(result);
return result;
}
public Generalization createGeneralization(Class_ c, String general) {
Generalization g = new Generalization();
org.modeldriven.fuml.repository.Classifier classifier = (org.modeldriven.fuml.repository.Classifier) model.getElementById(general);
g.general = classifier.getDelegate();
c.generalization.add(g);
return g;
}
public Property createProperty(Class_ c, String name, String id,
String typeName, String redefinedProperty,
boolean readOnly, boolean derived, boolean derivedUnion) {
Property p = createProperty(name, id, typeName,
redefinedProperty, readOnly, derived,
derivedUnion);
p.class_ = c;
c.ownedAttribute.add(p);
return p;
}
public Property createProperty(Association assoc, String name, String id,
String typeName, String subsettedProperty, String redefinedProperty,
boolean readOnly, boolean derived, boolean derivedUnion) {
Property p = createProperty(name, id, typeName,
redefinedProperty, readOnly, derived,
derivedUnion);
p.association = assoc;
assoc.ownedEnd.add(p);
p.owningAssociation = assoc;
return p;
}
public Property createProperty(String name, String id,
String typeName, String redefinedProperty,
boolean readOnly, boolean derived, boolean derivedUnion) {
Property p = new Property();
p.setName(name);
p.setXmiId(id);
p.isDerived = derived;
p.setIsReadOnly(readOnly);
p.isDerivedUnion = derivedUnion;
if ((typeName == null || typeName.length() == 0)
&& (redefinedProperty == null || redefinedProperty.length() == 0))
throw new RepositorylException("no type or redefinedProperty found for property '"
+ name + "' (" + id
+ ")");
if (typeName != null && typeName.length() > 0)
{
//FIXME: flat namespace lookup
org.modeldriven.fuml.repository.Classifier typeClassifier = (org.modeldriven.fuml.repository.Classifier)model.findElementById(typeName);
// Well TypedElement.type is not frigging required. Another ridiculous
// UML problem, like NamedElement.name. I guess we don't throw here,
// just log an error.
if (typeClassifier == null) {
log.error("could not find type '" + typeName + "' for property '"
+ name + "' (" + id + ")");
}
else
p.typedElement.type = typeClassifier.getDelegate();
}
else
{
org.modeldriven.fuml.repository.Property redefinedProp = (org.modeldriven.fuml.repository.Property)model.getElementById(redefinedProperty);
if (redefinedProp == null)
throw new RepositorylException("could not find redefinedProperty '" + redefinedProperty + "' for property '"
+ name + "' (" + id
+ ")");
Property redefined = redefinedProp.getDelegate();
p.typedElement.type = redefined.typedElement.type;
}
return p;
}
public LiteralInteger createLowerValue(Property p, boolean hasLowerValue, String value)
{
LiteralInteger lowerValue = new LiteralInteger();
p.setLowerValue(lowerValue);
if ("1".equals(value)) {
lowerValue.value = 1;
}
else if (value != null && value.length() > 0)
{
lowerValue.value = 1;
}
else if (hasLowerValue) {
// it's defined, but no value attrib, give it the default
// value for LiteralInteger (0)
lowerValue.value = 0;
}
else {
lowerValue.value = 1;
}
return lowerValue;
}
/**
* multiplicity examples
* ---------------------------------------
* 1 - Default if omitted
* * - zero or more
* 1..* - 1 or more
* 0..1 - zero or 1
* 2..5 - At least 2 and up to 5
* 2,5 - 2 or 5
* n - Unknown at compile time
* ---------------------------------------
* @param p
* @param hasUpperValue
* @param value
*/
public LiteralSpecification createUpperValue(Property p, boolean hasUpperValue, String value)
{
LiteralSpecification result = null;
if ("*".equals(value)) {
LiteralUnlimitedNatural upperValue = new LiteralUnlimitedNatural();
UnlimitedNatural unlimitedNatural = new UnlimitedNatural();
upperValue.value = unlimitedNatural;
p.setUpperValue(upperValue);
result = upperValue;
}
else if (value != null && value.length() > 0)
{
int intValue = Integer.parseInt(value);
LiteralInteger upperValue = new LiteralInteger();
upperValue.value = intValue;
p.setUpperValue(upperValue);
result = upperValue;
}
else if (hasUpperValue) {
LiteralInteger upperValue = new LiteralInteger();
upperValue.value = 1;
p.setUpperValue(upperValue);
result = upperValue;
}
else
{
LiteralInteger upperValue = new LiteralInteger();
upperValue.value = 1;
p.setUpperValue(upperValue);
result = upperValue;
}
return result;
}
public ValueSpecification createDefault(Property prop, Object value, String instance, String id,
String xmiType, String typeId) {
ValueSpecification valueSpec = null;
String typeName = xmiType.substring(4);
Classifier type = null;
if (typeId != null && typeId.length() > 0)
{
org.modeldriven.fuml.repository.Classifier typeClassifier = (org.modeldriven.fuml.repository.Classifier)model.getElementById(typeId);
type = typeClassifier.getDelegate();
}
if (LiteralString.class.getSimpleName().equals(typeName))
{
LiteralString literalString = new LiteralString();
if (type != null)
literalString.type = type;
else
literalString.type = model.getClassifierByName("String").getDelegate();
literalString.value = String.valueOf(value);
valueSpec = literalString;
}
else if (LiteralBoolean.class.getSimpleName().equals(typeName))
{
LiteralBoolean literalBoolean = new LiteralBoolean();
if (type != null)
literalBoolean.type = type;
else
literalBoolean.type = model.getClassifierByName("Boolean").getDelegate();
if (value != null) {
literalBoolean.value = Boolean.valueOf(String.valueOf(value)).booleanValue();
}
else
{
literalBoolean.value = false;
}
valueSpec = literalBoolean;
}
else if (LiteralInteger.class.getSimpleName().equals(typeName))
{
LiteralInteger literalInteger = new LiteralInteger();
if (type != null)
literalInteger.type = type;
else
literalInteger.type = model.getClassifierByName("Integer").getDelegate();
if (value != null && String.valueOf(value).length() > 0) {
literalInteger.value = Integer.valueOf(String.valueOf(value)).intValue();
}
else
{
literalInteger.value = 0;
}
valueSpec = literalInteger;
}
else if (LiteralUnlimitedNatural.class.getSimpleName().equals(typeName))
{
LiteralUnlimitedNatural literalUnlimitedNatural = new LiteralUnlimitedNatural();
if (type != null)
literalUnlimitedNatural.type = type;
else
literalUnlimitedNatural.type = model.getClassifierByName("UnlimitedNatural").getDelegate();
if (value instanceof UnlimitedNatural) {
literalUnlimitedNatural.value = (UnlimitedNatural)value;
}
else
{
literalUnlimitedNatural.value = new UnlimitedNatural();
}
valueSpec = literalUnlimitedNatural;
}
else if ("OpaqueExpression".equals(typeName))
{
if (value == null)
throw new RepositorylException("expected default value - cannot create OpaqueExpression default for property '"
+ prop.class_.name + "." + prop.name + "'");
if (value instanceof UnlimitedNatural)
{
LiteralUnlimitedNatural literalUnlimitedNatural = new LiteralUnlimitedNatural();
literalUnlimitedNatural.value = (UnlimitedNatural)value;
valueSpec = literalUnlimitedNatural;
}
else
throw new RepositorylException("expected UnlimitedNatural value from OpaqueExpression default for property '"
+ prop.class_.name + "." + prop.name + "'");
}
else if (InstanceValue.class.getSimpleName().equals(typeName))
{
InstanceValue instanceValue = new InstanceValue();
if (type == null)
throw new RepositorylException("can't derive type for InstanceValue");
instanceValue.type = type;
valueSpec = instanceValue;
if (instance == null || instance.length() == 0)
throw new RepositorylException("required InstanceValue.instance ");
instanceValue.instance = (InstanceSpecification)model.getElementById(instance).getDelegate();
if (instanceValue.instance == null)
log.warn("could not lookup reference for instance by id, '"
+ instance + "'");
}
else
throw new RepositorylException("unknown type, '" + typeName + "'");
prop.defaultValue = valueSpec;
return valueSpec;
}
public EnumerationLiteral createEnumerationLiteral(Enumeration enumeration,
String name, String id) {
EnumerationLiteral literal = new EnumerationLiteral();
literal.name = name;
literal.setXmiId(id);
enumeration.ownedLiteral.add(literal);
return literal;
}
}