com.cloudera.nav.sdk.model.MetadataModelFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.cloudera.nav.sdk.model.MetadataModelFactory.java

Source

/*
 * Copyright (c) 2015 Cloudera, Inc.
 *
 * 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.cloudera.nav.sdk.model;

import com.cloudera.nav.sdk.model.annotations.MClass;
import com.cloudera.nav.sdk.model.annotations.MProperty;
import com.cloudera.nav.sdk.model.custom.CustomProperty;
import com.cloudera.nav.sdk.model.custom.MetaClass;
import com.cloudera.nav.sdk.model.custom.MetaClassPackage;
import com.cloudera.nav.sdk.model.custom.Namespace;
import com.cloudera.nav.sdk.model.entities.Entity;
import com.cloudera.nav.sdk.model.entities.TagChangeSet;
import com.cloudera.nav.sdk.model.entities.UDPChangeSet;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

/**
 * Factory for generating MetadataModel instances from Entity sub-types
 * annotated with @MClass
 */
public class MetadataModelFactory {

    /**
     * Create a MetadataModel from entity subclasses and a given namespace.
     * For now we're assuming the given namespace is used for both the
     * package of the meta-classes and the custom properties
     *
     * @param classes
     * @param namespace
     */
    public MetadataModel newModel(Collection<? extends Class<? extends Entity>> classes, String namespace) {
        MetadataModel model = new MetadataModel();
        MetaClassPackage pkg = MetaClassPackage.newPackage(namespace);
        model.setPackages(Sets.newHashSet(pkg));
        Namespace ns = Namespace.newNamespace(namespace);
        model.setNamespaces(Sets.newHashSet(ns));

        Set<MetaClass> metaClasses = Sets.newHashSet();
        Map<String, CustomProperty> mPropertyMap = Maps.newHashMap();
        Map<String, Set<String>> mappings = Maps.newHashMap();
        MetaClass mClass;
        for (Class<? extends Entity> aClass : classes) {
            MClass ann = aClass.getAnnotation(MClass.class);
            mClass = MetaClass.newClass(pkg.getName(), ann.model());
            metaClasses.add(mClass);

            // get all @MProperty's (including inherited ones)
            Map<Field, Method> properties = MClassUtil.getAnnotatedProperties(aClass, MProperty.class);

            Class<?> valueType;
            Set<String> classMappings = Sets.newHashSet();
            for (Map.Entry<Field, Method> entry : properties.entrySet()) {
                valueType = entry.getKey().getType();
                MProperty pAnn = entry.getKey().getAnnotation(MProperty.class);
                if (valueType != UDPChangeSet.class && valueType != TagChangeSet.class && pAnn.register()) {
                    String pName = StringUtils.isEmpty(pAnn.attribute()) ? entry.getKey().getName()
                            : pAnn.attribute();
                    boolean multiValued = Collection.class.isAssignableFrom(valueType);
                    if (checkExitingProperties(pName, pAnn, multiValued, mPropertyMap)) {
                        mPropertyMap.put(pName, CustomProperty.newProperty(ns.getName(), pName, pAnn.fieldType(),
                                multiValued, pAnn.values()));
                        classMappings.add(ns.getName() + "." + pName);
                    }
                }
            }
            mappings.put(pkg.getName() + "." + mClass.getName(), classMappings);
        }
        model.setClasses(metaClasses);
        model.setProperties(Sets.newHashSet(mPropertyMap.values()));
        model.setMappings(mappings);
        return model;
    }

    private boolean checkExitingProperties(String pName, MProperty ann, boolean multiValued,
            Map<String, CustomProperty> mProps) {
        CustomProperty existing = mProps.get(pName);
        if (existing != null) {
            Preconditions.checkArgument(ann.register());
            Preconditions.checkArgument(ann.fieldType() == existing.getPropertyType(),
                    String.format("Expecting %s to be of type %s, got %s instead", pName,
                            existing.getPropertyType(), ann.fieldType()));
            // TODO validate type constraints
            Preconditions.checkArgument(multiValued == existing.isMultiValued(),
                    String.format("Expecting %s to%sbe multi-valued", pName, multiValued ? " " : " not "));
        }
        return existing == null;
    }
}