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

org.dizitart.no2.util.ObjectUtils Maven / Gradle / Ivy

There is a newer version: 4.3.0
Show newest version
/*
 *
 * Copyright 2017-2018 Nitrite author or authors.
 *
 * 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.dizitart.no2.util;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.dizitart.no2.Document;
import org.dizitart.no2.NitriteId;
import org.dizitart.no2.exceptions.IndexingException;
import org.dizitart.no2.exceptions.InvalidIdException;
import org.dizitart.no2.exceptions.NotIdentifiableException;
import org.dizitart.no2.mapper.NitriteMapper;
import org.dizitart.no2.objects.*;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.objenesis.instantiator.ObjectInstantiator;

import java.lang.reflect.Field;
import java.util.*;

import static org.dizitart.no2.Constants.KEY_OBJ_SEPARATOR;
import static org.dizitart.no2.exceptions.ErrorCodes.*;
import static org.dizitart.no2.exceptions.ErrorMessage.*;
import static org.dizitart.no2.objects.filters.ObjectFilters.eq;
import static org.dizitart.no2.util.ReflectionUtils.*;
import static org.dizitart.no2.util.StringUtils.isNullOrEmpty;
import static org.dizitart.no2.util.ValidationUtils.*;

/**
 * A utility class for {@link Object}.
 *
 * @since 1.0
 * @author Anindya Chatterjee.
 */
@UtilityClass
@Slf4j
public class ObjectUtils {
    private static Map constructorCache = new HashMap<>();
    private static Objenesis objenesis = new ObjenesisStd();

    /**
     * Generates the name of an {@link org.dizitart.no2.objects.ObjectRepository}.
     *
     * @param            the type parameter
     * @param type          the type of object stored in the repository
     * @return the name of the object repository.
     */
    public static  String findObjectStoreName(Class type) {
        notNull(type, errorMessage("type can not be null", VE_OBJ_STORE_NULL_TYPE));
        return type.getName();
    }

    /**
     * Generates the name of an {@link org.dizitart.no2.objects.ObjectRepository}
     * with an unique key identifier.
     *
     * @param   the type parameter
     * @param key  the key identifier
     * @param type the type of object stored in the repository
     * @return the name of the object repository.
     */
    public static  String findObjectStoreName(String key, Class type) {
        notNull(key, errorMessage("key can not be null", VE_OBJ_STORE_NULL_KEY));
        notEmpty(key, errorMessage("key can not be empty", VE_OBJ_STORE_EMPTY_KEY));
        notNull(type, errorMessage("type can not be null", VE_OBJ_STORE_NULL_TYPE));
        return type.getName() + KEY_OBJ_SEPARATOR + key;
    }

    /**
     * Extract indices information by scanning for {@link Index} annotated fields.
     *
     * @param            the type parameter
     * @param nitriteMapper the {@link NitriteMapper}
     * @param type          the type of the object stored in the repository
     * @return the set of all {@link Index} annotations found.
     */
    public static  Set extractIndices(NitriteMapper nitriteMapper, Class type) {
        notNull(type, errorMessage("type can not be null", VE_INDEX_ANNOTATION_NULL_TYPE));

        List indicesList;
        if (type.isAnnotationPresent(InheritIndices.class)) {
            indicesList = findAnnotations(Indices.class, type);
        } else {
            indicesList = new ArrayList<>();
            Indices indices = type.getAnnotation(Indices.class);
            if (indices != null) indicesList.add(indices);
        }

        Set indexSet = new LinkedHashSet<>();
        if (indicesList != null) {
            for (Indices indices : indicesList) {
                Index[] indexList = indices.value();
                populateIndex(nitriteMapper, type, Arrays.asList(indexList), indexSet);
            }
        }

        List indexList;
        if (type.isAnnotationPresent(InheritIndices.class)) {
            indexList = findAnnotations(Index.class, type);
        } else {
            indexList = new ArrayList<>();
            Index index = type.getAnnotation(Index.class);
            if (index != null) indexList.add(index);
        }

        if (indexList != null) {
            populateIndex(nitriteMapper, type, indexList, indexSet);
        }
        return indexSet;
    }

    /**
     * Gets the field marked with {@link Id} annotation.
     *
     * @param            the type parameter
     * @param nitriteMapper the nitrite mapper
     * @param type          the type
     * @return the id field
     */
    public static  Field getIdField(NitriteMapper nitriteMapper, Class type) {
        List fields;
        if (type.isAnnotationPresent(InheritIndices.class)) {
            fields = getFieldsUpto(type, Object.class);
        } else {
            fields = Arrays.asList(type.getDeclaredFields());
        }

        boolean alreadyIdFound = false;
        Field idField = null;
        for (Field field : fields) {
            if (field.isAnnotationPresent(Id.class)) {
                validateObjectIndexField(nitriteMapper, field.getType(), field.getName());
                if (alreadyIdFound) {
                    throw new NotIdentifiableException(OBJ_MULTIPLE_ID_FOUND);
                } else {
                    alreadyIdFound = true;
                    idField = field;
                }
            }
        }
        return idField;
    }

    /**
     * Creates unique filter from the object.
     *
     * @param object  the object
     * @param idField the id field
     * @return the equals filter
     */
    public static ObjectFilter createUniqueFilter(Object object, Field idField) {
        idField.setAccessible(true);
        try {
            Object value = idField.get(object);
            if (value == null) {
                throw new InvalidIdException(ID_FILTER_VALUE_CAN_NOT_BE_NULL);
            }
            return eq(idField.getName(), value);
        } catch (IllegalAccessException iae) {
            throw new InvalidIdException(ID_FIELD_IS_NOT_ACCESSIBLE);
        }
    }

    /**
     * Checks whether a collection name is a valid object store name.
     *
     * @param collectionName the collection name
     * @return `true` if it is a valid object store name; `false` otherwise.
     */
    public static boolean isObjectStore(String collectionName) {
        try {
            if (isNullOrEmpty(collectionName)) return false;
            Class clazz = Class.forName(collectionName);
            return clazz != null;
        } catch (ClassNotFoundException e) {
            return isKeyedObjectStore(collectionName);
        }
    }

    /**
     * Checks whether a collection name is a valid keyed object store name.
     *
     * @param collectionName the collection name
     * @return `true` if it is a valid object store name; `false` otherwise.
     */
    public static boolean isKeyedObjectStore(String collectionName) {
        try {
            if (isNullOrEmpty(collectionName)) return false;
            if (!collectionName.contains(KEY_OBJ_SEPARATOR)) return false;

            String[] split = collectionName.split("\\" + KEY_OBJ_SEPARATOR);
            if (split.length != 2) {
                return false;
            }
            String storeName = split[0];
            Class clazz = Class.forName(storeName);
            return clazz != null;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    @SuppressWarnings("unchecked")
    public static  T newInstance(Class type) {
        try {
            String clazz = type.getName();
            ObjectInstantiator instantiator = constructorCache.get(clazz);
            if (instantiator == null) {
                instantiator = objenesis.getInstantiatorOf(type);
                constructorCache.put(clazz, instantiator);
            }

            return (T) instantiator.newInstance();
        } catch (Exception e) {
            log.error("Error while creating instance of " + type.getName(), e);
            return null;
        }
    }

    public static  Document toDocument(T object, NitriteMapper nitriteMapper,
                                          Field idField, boolean update) {
        Document document = nitriteMapper.asDocument(object);
        if (idField != null) {
            if (idField.getType() == NitriteId.class) {
                try {
                    idField.setAccessible(true);
                    if (idField.get(object) == null) {
                        NitriteId id = document.getId();
                        idField.set(object, id);
                        document.put(idField.getName(), id.getIdValue());
                    } else if (!update) {
                        throw new InvalidIdException(AUTO_ID_ALREADY_SET);
                    }
                } catch (IllegalAccessException iae) {
                    throw new InvalidIdException(CANNOT_ACCESS_AUTO_ID);
                }
            }
            Object idValue = document.get(idField.getName());
            if (idValue == null) {
                throw new InvalidIdException(ID_CAN_NOT_BE_NULL);
            }
            if (idValue instanceof String && isNullOrEmpty((String) idValue)) {
                throw new InvalidIdException(ID_VALUE_CAN_NOT_BE_EMPTY_STRING);
            }
        }
        return document;
    }

    private  void populateIndex(NitriteMapper nitriteMapper, Class type,
                                   List indexList, Set indexSet) {
        for (Index index : indexList) {
            String name = index.value();
            Field field = getField(type, name, true);
            if (field != null) {
                validateObjectIndexField(nitriteMapper, field.getType(), field.getName());
                indexSet.add(index);
            } else {
                throw new IndexingException(errorMessage(
                        "field " + name + " does not exists for type " + type.getName(),
                        IE_OBJ_INDEX_INVALID_FIELD));
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy