org.swordess.ldap.odm.metadata.entity.EntityMetaData.java Source code

Java tutorial

Introduction

Here is the source code for org.swordess.ldap.odm.metadata.entity.EntityMetaData.java

Source

/*
 * Swordess-ldap, an Object-Directory Mapping tool. 
 * 
 * Copyright (c) 2013, 2013 Liu Xingyu.
 * 
 * Swordess-ldap is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 * 
 * Swordess-ldap is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with Swordess-ldap. If not, see <http://www.gnu.org/licenses/>.
 */
package org.swordess.ldap.odm.metadata.entity;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.swordess.ldap.odm.annotation.Attribute;
import org.swordess.ldap.odm.annotation.Entry;
import org.swordess.ldap.odm.annotation.Id;
import org.swordess.ldap.odm.annotation.Transient;
import org.swordess.ldap.odm.metadata.MetaDataException;
import org.swordess.ldap.util.LogUtils;

public class EntityMetaData implements Iterable<EntityPropertyMetaData> {

    private static final Log LOG = LogFactory.getLog(EntityMetaData.class);

    private static Map<Class<?>, EntityMetaData> metaDataMap = new HashMap<Class<?>, EntityMetaData>();

    private final Class<?> managedClass;

    /**
     * LDAP branch the managed class should be saved to.
     */
    private String context;

    /**
     * Values of objectclass which will be saved to LDAP server.
     */
    private String[] objectClasses;

    private EntityPropertyMetaData idProperty;

    private Map<String, EntityPropertyMetaData> ldapPropNameToMetaData = new HashMap<String, EntityPropertyMetaData>();
    private Map<String, EntityPropertyMetaData> javaBeanPropNameToMetaData = new HashMap<String, EntityPropertyMetaData>();

    // cache all defined attribute names in order not to create the same array
    private String[] allDefinedAttrNames;

    private EntityMetaData(Class<?> clazz) {
        this.managedClass = clazz;

        LogUtils.debug(LOG, "Extracting metadata from " + clazz);

        Entry entry = clazz.getAnnotation(Entry.class);
        if (null == entry) {
            throw new MetaDataException(
                    String.format("Class %s must have a class level %s annotation", clazz, Entry.class));
        }

        context = entry.context();
        objectClasses = entry.objectClasses();

        Set<String> allDefinedAttrNameSet = new HashSet<String>();
        for (Method m : clazz.getDeclaredMethods()) {
            m.setAccessible(true);

            // static methods and transient methods are not managed
            if (Modifier.isStatic(m.getModifiers()) || m.isAnnotationPresent(Transient.class)) {
                continue;
            }

            // methods without @Id or @Attribute are not managed
            if (!m.isAnnotationPresent(Id.class) && !m.isAnnotationPresent(Attribute.class)) {
                continue;
            }

            EntityPropertyMetaData currentPropertyMetaData = new EntityPropertyMetaData(m);
            if (currentPropertyMetaData.isId()) {
                if (null != idProperty) {
                    throw new MetaDataException(String.format(
                            "You must have only one method with the %s annotation in class %s", Id.class, clazz));
                }
                idProperty = currentPropertyMetaData;
            }
            ldapPropNameToMetaData.put(currentPropertyMetaData.getLdapPropName(), currentPropertyMetaData);
            javaBeanPropNameToMetaData.put(currentPropertyMetaData.getJavaBeanPropName(), currentPropertyMetaData);
            allDefinedAttrNameSet.add(currentPropertyMetaData.getLdapPropName());
        }
        allDefinedAttrNames = allDefinedAttrNameSet.toArray(new String[0]);

        if (null == idProperty) {
            throw new MetaDataException(String.format(
                    "All Entry classes must define a property with the %s annotation, error in class %s", Id.class,
                    clazz));
        }

        LogUtils.debug(LOG, String.format("Extracted metadata from %s as %s", clazz, this));
    }

    @Override
    public Iterator<EntityPropertyMetaData> iterator() {
        return ldapPropNameToMetaData.values().iterator();
    }

    public Class<?> getManagedClass() {
        return managedClass;
    }

    public String context() {
        return context;
    }

    public String[] objectClasses() {
        return objectClasses;
    }

    public EntityPropertyMetaData getIdProperty() {
        return idProperty;
    }

    public EntityPropertyMetaData getProperty(String ldapPropName) {
        return ldapPropNameToMetaData.get(ldapPropName);
    }

    public EntityPropertyMetaData getPropertyByJavaBeanPropName(String javaBeanPropName) {
        return javaBeanPropNameToMetaData.get(javaBeanPropName);
    }

    @Override
    public String toString() {
        StringBuilder propertiesInfo = new StringBuilder();
        for (EntityPropertyMetaData propertyMetaData : this) {
            propertiesInfo.append("\n");
            propertiesInfo.append(propertyMetaData);
        }
        propertiesInfo.append("\n");
        return String.format("objectClasses=%s | idProperty=%s | properties=[%s]", Arrays.toString(objectClasses),
                idProperty.getLdapPropName(), propertiesInfo);
    }

    public static EntityMetaData get(Class<?> clazz) {
        EntityMetaData metaData = metaDataMap.get(clazz);
        if (null == metaData) {
            metaData = new EntityMetaData(clazz);
            metaDataMap.put(clazz, metaData);
        }
        return metaData;
    }

    public static String[] getDefinedAttrNames(Class<?> clazz) {
        return get(clazz).allDefinedAttrNames;
    }

}