/*******************************************************************************
* Copyright 2012 Pearson Education
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.semantictools.uml.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.semantictools.frame.api.TypeManager;
import org.semantictools.frame.model.Encapsulation;
import org.semantictools.frame.model.Field;
import org.semantictools.frame.model.Frame;
import org.semantictools.frame.model.InverseProperty;
import org.semantictools.frame.model.RdfType;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntProperty;
import com.hp.hpl.jena.ontology.OntResource;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
public class UmlManager {
private TypeManager typeManager;
private Map<String, UmlClass> uri2Class = new HashMap<String, UmlClass>();
public UmlManager(TypeManager typeManager) {
this.typeManager = typeManager;
init();
}
public void add(UmlClass umlClass) {
uri2Class.put(umlClass.getURI(), umlClass);
}
public TypeManager getTypeManager() {
return typeManager;
}
public UmlClass getUmlClassByURI(String uri) {
return uri2Class.get(uri);
}
public Collection<UmlClass> listUmlClasses() {
return uri2Class.values();
}
private void init() {
buildClasses();
buildAssociations();
sortAssociations();
}
private void sortAssociations() {
for (UmlClass umlClass : uri2Class.values()) {
Comparator<UmlAssociation> comparator = new UmlAssociationComparator(umlClass);
sort(umlClass.getChildren(), comparator);
}
}
private void sort(List<UmlAssociation> list, Comparator<UmlAssociation> comparator) {
if (list.isEmpty()) return;
Collections.sort(list, comparator);
}
private void buildClasses() {
List<Frame> list = new ArrayList<Frame>(typeManager.listFrames());
for (Frame frame : list ) {
buildClass(frame);
}
for (Frame frame : list) {
buildPropertyClasses(frame);
}
for (Frame frame : typeManager.listListTypes()) {
buildClass(frame);
}
}
private void buildPropertyClasses(Frame frame) {
for (Field field : frame.getDeclaredFields()) {
OntResource type = field.getType();
if (type.canAs(OntProperty.class)) {
String uri = type.getURI();
UmlClass umlClass = addPropertyClass(type, true);
}
}
}
private UmlClass addPropertyClass(OntResource type, boolean addSuperProperties) {
String uri = type.getURI();
UmlClass umlClass = uri2Class.get(uri);
if (umlClass == null) {
Frame propertyFrame = typeManager.getFrameByUri(uri);
if (propertyFrame == null) {
if (!type.canAs(OntClass.class)) {
type.addProperty(RDF.type, OWL.Class);
}
propertyFrame = new Frame(typeManager, type.asClass());
typeManager.add(propertyFrame);
}
umlClass = new UmlClass(propertyFrame, this);
uri2Class.put(uri, umlClass);
addSubProperties(umlClass, type.asProperty());
}
if (addSuperProperties) {
addSuperProperties(umlClass, type.asProperty());
}
return umlClass;
}
private void addSuperProperties(UmlClass umlClass, OntProperty property) {
List<? extends OntProperty> list = property.listSuperProperties(true).toList();
for (OntProperty superProperty : list) {
if (superProperty.getURI().equals(property.getURI())) {
continue;
}
UmlClass superClass = addPropertyClass(superProperty, true);
umlClass.addSupertype(superClass);
superClass.addSubtype(umlClass);
}
}
private void addSubProperties(UmlClass umlClass, OntProperty type) {
List<? extends OntProperty> list = type.listSubProperties(true).toList();
for (OntProperty p : list) {
if (p.getURI().equals(type.getURI())) {
continue;
}
UmlClass subProperty = addPropertyClass(p, false);
umlClass.addSubtype(subProperty);
subProperty.addSupertype(umlClass);
}
}
private void buildClass(Frame frame) {
String uri = frame.getUri();
UmlClass umlClass = new UmlClass(frame, this);
uri2Class.put(uri, umlClass);
for (Field field : frame.getDeclaredFields()) {
RdfType fieldType = field.getRdfType();
if (fieldType.canAsDatatype()) {
umlClass.add(field);
}
}
}
private void buildAssociations() {
for (Frame frame : typeManager.listFrames() ) {
buildAssociations(frame);
}
}
private void buildAssociations(Frame frame) {
UmlClass umlClass = getUmlClassByURI(frame.getUri());
addChildren(umlClass, frame);
}
private void addChildren(UmlClass umlClass, Frame frame) {
List<UmlAssociation> parentList = new ArrayList<UmlAssociation>();
for (Field field : frame.getDeclaredFields()) {
RdfType fieldType = field.getRdfType();
Field inverseField = field.getInverseField();
UmlClass otherClass = null;
if (fieldType.canAsFrame()) {
otherClass = getUmlClassByURI(fieldType.getUri());
} else if (fieldType.canAsListType()) {
otherClass = getUmlClassByURI(fieldType.asListType().getElementType().getUri());
}
if (otherClass != null) {
InverseProperty inverse = field.getInverseProperty();
Encapsulation inverseEncapsulation = inverseField==null ? inverse.getEncapsulation() :
inverseField.getEncapsulation();
Encapsulation encapsulation = field.getEncapsulation();
if (encapsulation == Encapsulation.NONE && inverseEncapsulation != Encapsulation.NONE) {
//
// The other class is the parent
UmlAssociationEnd end0 = new UmlAssociationEnd(umlClass);
end0.setMultiplicity(inverse.getMultiplicity());
defineEnd(end0, inverseField, encapsulation);
UmlAssociationEnd end1 = new UmlAssociationEnd(otherClass);
defineEnd(end1, field, inverseEncapsulation);
UmlAssociation assoc = new UmlAssociation(end0, end1);
otherClass.addChild(assoc);
parentList.add(assoc);
} else {
UmlAssociationEnd end0 = new UmlAssociationEnd(umlClass);
UmlAssociationEnd end1 = new UmlAssociationEnd(otherClass);
defineEnd(end0, inverseField, encapsulation);
defineEnd(end1, field, inverseEncapsulation);
UmlAssociation assoc = new UmlAssociation(end0, end1);
umlClass.addChild(assoc);
parentList.add(assoc);
}
} else {
// TODO: handle other conditions
}
}
addParentList(umlClass, parentList);
}
private void addParentList(UmlClass umlClass, List<UmlAssociation> parentList) {
for (UmlAssociation assoc : parentList) {
addParentAssociation(umlClass, assoc);
}
}
private void addParentAssociation(UmlClass umlClass, UmlAssociation assoc) {
List<UmlAssociation> childList = umlClass.getChildren();
for (UmlAssociation child : childList) {
if (child.equals(assoc)) return;
}
umlClass.addParent(assoc);
}
private void defineEnd(UmlAssociationEnd end, Field field, Encapsulation encapsulation) {
end.setEncapsulation(encapsulation);
if (field == null) return;
end.setField(field);
end.setLocalName(field.getLocalName());
end.setMultiplicity(field.getMultiplicity());
}
static class UmlAssociationComparator implements Comparator<UmlAssociation> {
private UmlClass umlClass;
public UmlAssociationComparator(UmlClass umlClass) {
this.umlClass = umlClass;
}
@Override
public int compare(UmlAssociation a, UmlAssociation b) {
String aName = a.getOtherEnd(umlClass).getParticipant().getLocalName();
String bName = b.getOtherEnd(umlClass).getParticipant().getLocalName();
return aName.compareTo(bName);
}
}
}