/**
* Copyright © 2006-2016 Web Cohesion (info@webcohesion.com)
*
* 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 com.webcohesion.enunciate.modules.jaxb.api.impl;
import com.webcohesion.enunciate.api.ApiRegistrationContext;
import com.webcohesion.enunciate.api.datatype.*;
import com.webcohesion.enunciate.api.datatype.Value;
import com.webcohesion.enunciate.facets.FacetFilter;
import com.webcohesion.enunciate.javac.decorations.type.DecoratedTypeMirror;
import com.webcohesion.enunciate.modules.jaxb.model.*;
import com.webcohesion.enunciate.modules.jaxb.model.types.XmlClassType;
import com.webcohesion.enunciate.modules.jaxb.model.types.XmlType;
import com.webcohesion.enunciate.modules.jaxb.model.types.XmlTypeFactory;
import com.webcohesion.enunciate.util.BeanValidationUtils;
import java.util.*;
/**
* @author Ryan Heaton
*/
public class ComplexDataTypeImpl extends DataTypeImpl {
final ComplexTypeDefinition typeDefinition;
public ComplexDataTypeImpl(ComplexTypeDefinition typeDefinition, ApiRegistrationContext registrationContext) {
super(typeDefinition, registrationContext);
this.typeDefinition = typeDefinition;
}
@Override
public BaseType getBaseType() {
return BaseType.object;
}
@Override
public List<? extends Value> getValues() {
return null;
}
@Override
public List<? extends Property> getProperties() {
ArrayList<Property> properties = new ArrayList<Property>();
FacetFilter facetFilter = this.typeDefinition.getContext().getContext().getConfiguration().getFacetFilter();
List<Property> attributeProperties = new ArrayList<Property>();
for (Attribute attribute : this.typeDefinition.getAttributes()) {
if (!facetFilter.accept(attribute)) {
continue;
}
attributeProperties.add(new PropertyImpl(attribute, registrationContext));
}
if (this.typeDefinition.getPropertyOrder() == null) {
//if the property order isn't explicit, sort the attributes by name, then add them to the list.
Collections.sort(attributeProperties, new Comparator<Property>() {
@Override
public int compare(Property o1, Property o2) {
return o1.getName().compareTo(o2.getName());
}
});
}
properties.addAll(attributeProperties);
if (this.typeDefinition.getValue() != null) {
properties.add(new PropertyImpl(this.typeDefinition.getValue(), registrationContext));
}
else {
List<Property> elementProperties = new ArrayList<Property>();
for (Element element : this.typeDefinition.getElements()) {
if (!facetFilter.accept(element)) {
continue;
}
boolean wrapped = element.isWrapped();
String wrapperName = wrapped ? element.getWrapperName() : null;
String wrapperNamespace = wrapped ? element.getWrapperNamespace() : null;
for (Element choice : element.getChoices()) {
elementProperties.add(wrapped ? new WrappedPropertyImpl(choice, wrapperName, wrapperNamespace, registrationContext) : new PropertyImpl(choice, registrationContext));
}
}
if (this.typeDefinition.getPropertyOrder() == null) {
//if the property order isn't explicit, sort the elements by name, then add them to the list.
Collections.sort(elementProperties, new Comparator<Property>() {
@Override
public int compare(Property o1, Property o2) {
return o1.getName().compareTo(o2.getName());
}
});
}
properties.addAll(elementProperties);
}
return properties;
}
public List<? extends Property> getRequiredProperties() {
ArrayList<Property> requiredProperties = new ArrayList<Property>();
for (Property property : getProperties()) {
if (property.isRequired()) {
requiredProperties.add(property);
}
}
return requiredProperties;
}
@Override
public List<DataTypeReference> getSupertypes() {
ArrayList<DataTypeReference> supertypes = null;
XmlType supertype = this.typeDefinition.getBaseType();
while (supertype != null) {
if (supertypes == null) {
supertypes = new ArrayList<DataTypeReference>();
}
supertypes.add(new DataTypeReferenceImpl(supertype, false, registrationContext));
supertype = supertype instanceof XmlClassType ?
((XmlClassType) supertype).getTypeDefinition() instanceof ComplexTypeDefinition ?
((XmlClassType) supertype).getTypeDefinition().getBaseType()
: null
: null;
}
return supertypes;
}
@Override
public List<DataTypeReference> getSubtypes() {
ArrayList<DataTypeReference> subtypes = new ArrayList<DataTypeReference>();
for (SchemaInfo schemaInfo : this.typeDefinition.getContext().getSchemas().values()) {
for (TypeDefinition td : schemaInfo.getTypeDefinitions()) {
if (td instanceof ComplexTypeDefinition && !td.getQualifiedName().contentEquals(this.typeDefinition.getQualifiedName()) && ((DecoratedTypeMirror)td.asType()).isInstanceOf(this.typeDefinition)) {
subtypes.add(new DataTypeReferenceImpl(XmlTypeFactory.getXmlType(td.asType(), this.typeDefinition.getContext()), false, registrationContext));
}
}
}
return subtypes.isEmpty() ? null : subtypes;
}
@Override
public Example getExample() {
return this.typeDefinition.getContext().isDisableExamples() ? null : new ComplexTypeExampleImpl(this.typeDefinition);
}
@Override
public Map<String, String> getPropertyMetadata() {
Map<String, String> propertyMetadata = new LinkedHashMap<String, String>();
propertyMetadata.put("type", "type");
propertyMetadata.put("namespaceInfo", "namespace");
propertyMetadata.put("minMaxOccurs", "min/max occurs");
//if any elements have a default value, show that, too.
boolean showDefaultValue = false;
boolean showWrapper = false;
boolean showConstraints = false;
for (Element element : this.typeDefinition.getElements()) {
for (Element choice : element.getChoices()) {
if (BeanValidationUtils.hasConstraints(choice, choice.isRequired())) {
showConstraints = true;
}
if (choice.getDefaultValue() != null) {
showDefaultValue = true;
}
}
if (element.isWrapped()) {
showWrapper = true;
}
}
if (showDefaultValue) {
propertyMetadata.put("defaultValue", "default");
}
if (showConstraints) {
propertyMetadata.put("constraints", "constraints");
}
if (showWrapper) {
propertyMetadata.put("wrapper", "wrapped by");
}
return propertyMetadata;
}
}