All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mysema.rdfbean.object.MappedClass Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010 Mysema Ltd.
 * All rights reserved.
 *
 */
package com.mysema.rdfbean.object;

import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

import com.mysema.commons.lang.Assert;
import com.mysema.rdfbean.annotations.Mixin;
import com.mysema.rdfbean.model.RDF;
import com.mysema.rdfbean.model.UID;

/**
 * @author sasa
 * 
 */
public final class MappedClass {

    private static final Comparator mappedPathComparator = new Comparator() {
        @Override
        public int compare(MappedPath o1, MappedPath o2) {
            return o1.getOrder() - o2.getOrder();
        }
    };

    private final Class clazz;

    @Nullable
    private MappedConstructor constructor;

    private final Set> dynamicProperties = new LinkedHashSet>();

    private final Set> mixinProperties = new LinkedHashSet>();

    @Nullable
    private MappedProperty idProperty;

    private final Set mappedPredicates = new HashSet();

    private final Set invMappedPredicates = new HashSet();

    private Map properties = new LinkedHashMap();

    private final List mappedSuperClasses;

    @Nullable
    private final UID uid;

    @Nullable
    private final UID context;

    MappedClass(Class clazz, @Nullable UID uid, @Nullable UID context, List mappedSuperClasses) {
        this.clazz = Assert.notNull(clazz, "clazz");
        this.uid = uid;
        this.context = context;
        this.mappedSuperClasses = mappedSuperClasses;
        mappedPredicates.add(RDF.type);
    }

    void addDynamicProperty(MappedProperty property) {
        // FIXME How to handle mapped keys from superclass?
        dynamicProperties.add(property);
    }

    @SuppressWarnings("unchecked")
    void addMappedPath(MappedPath path) {
        if (path.getPredicatePath().size() > 0) {
            if (!path.get(0).inv()) {
                mappedPredicates.add(path.get(0).getUID());
            } else {
                invMappedPredicates.add(path.get(0).getUID());
            }
        } else if (path.getMappedProperty().isAnnotationPresent(Mixin.class)) {
            mixinProperties.add(path.getMappedProperty());
        }

        MappedProperty property = path.getMappedProperty();
        MappedPath existingPath = properties.get(property.getName());

        if (path.getMappedProperty().isIdReference()) {
            if (idProperty != null) {
                throw new IllegalArgumentException("Duplicate ID property: " +
                        idProperty + " and " + path.getMappedProperty());
            }
            idProperty = path.getMappedProperty();
            properties.put(path.getName(), path);
        }

        else if (existingPath != null) {
            MappedProperty existingProperty = existingPath.getMappedProperty();
            if (property instanceof FieldProperty) {
                if (existingProperty instanceof FieldProperty) {
                    throw new IllegalArgumentException("Cannot merge field properties: " +
                            path + " into " + existingPath);
                } else {
                    // Field property overrides method and constructor
                    // properties
                    properties.put(path.getName(), path);
                    path.merge(existingPath);
                }
            } else {
                existingPath.merge(path);
            }
        }

        else {
            properties.put(path.getName(), path);
        }
    }

    void close() {
        MappedPath[] paths = properties.values().toArray(new MappedPath[properties.size()]);
        // Sort properties into bind order
        Arrays.sort(paths, mappedPathComparator);
        // Rebuild properties map using bind ordering
        properties = new LinkedHashMap();
        for (MappedPath path : paths) {
            properties.put(path.getName(), path);
        }
        // Close properties map from further changes
        properties = Collections.unmodifiableMap(properties);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        } else if (obj instanceof MappedClass) {
            return clazz.equals(((MappedClass) obj).clazz);
        } else {
            return false;
        }
    }

    @Nullable
    public  T getAnnotation(Class atype) {
        return clazz.getAnnotation(atype);
    }

    public String getClassNs() {
        return uid != null ? uid.ns() : "";
    }

    @Nullable
    public MappedConstructor getConstructor() {
        return constructor;
    }

    public Collection> getDynamicProperties() {
        return dynamicProperties;
    }

    public Collection> getMixinProperties() {
        return mixinProperties;
    }

    @Nullable
    public MappedProperty getIdProperty() {
        return idProperty;
    }

    public Class getJavaClass() {
        return clazz;
    }

    public boolean hasProperty(String name) {
        return properties.containsKey(name);
    }

    public MappedPath getMappedPath(String name) {
        MappedPath path = properties.get(name);
        if (path != null) {
            return path;
        } else {
            throw new IllegalArgumentException("No such property: " + name + " in " + clazz);
        }
    }

    public List getMappedSuperClasses() {
        return mappedSuperClasses;
    }

    public Collection getProperties() {
        return properties.values();
    }

    @Nullable
    public UID getUID() {
        return uid;
    }

    @Nullable
    public UID getContext() {
        return context;
    }

    @Override
    public int hashCode() {
        return clazz.hashCode();
    }

    public boolean isEnum() {
        return clazz.isEnum();
    }

    public Collection getMappedPredicates() {
        return mappedPredicates;
    }

    public Collection getInvMappedPredicates() {
        return invMappedPredicates;
    }

    public boolean isMappedPredicate(UID predicate) {
        return mappedPredicates.contains(predicate);
    }

    Type resolveTypeVariable(String typeVariableName, MappedClass declaringClass) {
        int i = 0;
        for (TypeVariable typeParameter : declaringClass.clazz.getTypeParameters()) {
            if (typeParameter.getName().equals(typeVariableName)) {
                break;
            } else {
                i++;
            }
        }
        int j = 0;
        boolean found = false;
        for (MappedClass superClass : getMappedSuperClasses()) {
            if (declaringClass.equals(superClass)) {
                found = true;
                break;
            } else {
                j++;
            }
        }
        if (!found) {
            throw new SessionException("Super class declaration for " + declaringClass + " not found from " + this);
        }

        Type type = (j == 0 ? clazz.getGenericSuperclass() : clazz.getGenericInterfaces()[j - 1]);
        if (type instanceof ParameterizedType) {
            return ((ParameterizedType) type).getActualTypeArguments()[i];
        } else {
            throw new SessionException("Generic parameters not supplied from " + this + " to " + declaringClass);
        }
    }

    void setMappedConstructor(@Nullable MappedConstructor constructor) {
        if (constructor == null && !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) {
            throw new IllegalArgumentException("Default or mapped constructor required for " + clazz);
        } else {
            this.constructor = constructor;
        }
    }

    @Override
    public String toString() {
        return clazz.toString();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy