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

io.jsondb.CollectionMetaData Maven / Gradle / Ivy

There is a newer version: 1.0.115-j11
Show newest version
/*
 * Copyright (c) 2016 Farooq Khan
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package io.jsondb;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.reflections.Reflections;

import io.jsondb.annotation.Document;
import io.jsondb.annotation.Id;
import io.jsondb.annotation.Secret;

/**
 * @version 1.0 25-Sep-2016
 */
public class CollectionMetaData {
  private String collectionName;
  private String schemaVersion;
  private String actualSchemaVersion;
  private Comparator schemaComparator;
  private Class clazz;

  private String idAnnotatedFieldName;
  private Method idAnnotatedFieldGetterMethod;
  private Method idAnnotatedFieldSetterMethod;

  private final ReentrantReadWriteLock collectionLock;

  private List secretAnnotatedFieldNames = new ArrayList();
  private Map getterMethodMap = new TreeMap();
  private Map setterMethodMap = new TreeMap();

  private boolean hasSecret;
  private boolean readonly;

  public CollectionMetaData(String collectionName, Class clazz, String schemaVersion, Comparator schemaComparator) {
    super();
    this.collectionName = collectionName;
    this.schemaVersion = schemaVersion;
    this.schemaComparator = schemaComparator;
    this.clazz = clazz;

    this.collectionLock = new ReentrantReadWriteLock();

    //Populate the class metadata
    Field[]  fs = clazz.getDeclaredFields();
    Method[] ms = clazz.getDeclaredMethods();
    for (Field f : fs) {
      String fieldName = f.getName();

      Annotation[] annotations = f.getDeclaredAnnotations();
      for (Annotation a : annotations) {
        if (a.annotationType().equals(Id.class)) {
          //We expect only one @Id annotated field and only one corresponding getter for it
          //This logic will capture the last @Id annotated field if there are more than one.
          this.idAnnotatedFieldName = fieldName;
        }
        if (a.annotationType().equals(Secret.class)) {
          this.secretAnnotatedFieldNames.add(fieldName);
          this.hasSecret = true;
        }
      }

      String getterMethodName = formGetterMethodName(f);
      String setterMethodName = formSetterMethodName(f);
      for (Method m : ms) {
        if (m.getName().equals(getterMethodName)) {
          this.getterMethodMap.put(fieldName, m);
        }
        if (m.getName().equals(setterMethodName)) {
          this.setterMethodMap.put(fieldName, m);
        }
      }
    }
    this.idAnnotatedFieldGetterMethod = getterMethodMap.get(idAnnotatedFieldName);
    this.idAnnotatedFieldSetterMethod = setterMethodMap.get(idAnnotatedFieldName);
  }

  protected ReentrantReadWriteLock getCollectionLock() {
    return collectionLock;
  }

  public String getCollectionName() {
    return collectionName;
  }

  public String getSchemaVersion() {
    return schemaVersion;
  }
  public String getActualSchemaVersion() {
    return actualSchemaVersion;
  }
  public void setActualSchemaVersion(String actualSchemaVersion) {
    this.actualSchemaVersion = actualSchemaVersion;
    int compareResult = schemaComparator.compare(schemaVersion, actualSchemaVersion);
    if (compareResult != 0) {
      readonly = true;
    } else {
      readonly = false;
    }
  }

  @SuppressWarnings("rawtypes")
  public Class getClazz() {
    return clazz;
  }
  public String getIdAnnotatedFieldName() {
    return idAnnotatedFieldName;
  }

  public Method getIdAnnotatedFieldGetterMethod() {
    return idAnnotatedFieldGetterMethod;
  }

  public Method getIdAnnotatedFieldSetterMethod() {
    return idAnnotatedFieldSetterMethod;
  }

  public List getSecretAnnotatedFieldNames() {
    return secretAnnotatedFieldNames;
  }

  public boolean isSecretField(String fieldName) {
    return secretAnnotatedFieldNames.contains(fieldName);
  }

  public Method getGetterMethodForFieldName(String fieldName) {
    return getterMethodMap.get(fieldName);
  }

  public Method getSetterMethodForFieldName(String fieldName) {
    return setterMethodMap.get(fieldName);
  }

  public boolean hasSecret() {
    return hasSecret;
  }

  public boolean isReadOnly() {
    return readonly;
  }

  private String formGetterMethodName(Field field) {
    String fieldName = field.getName();
    if (field.getType().equals(boolean.class)) {
      return "is" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
    } else {
      return "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
    }
  }

  private String formSetterMethodName(Field field) {
    String fieldName = field.getName();
    return "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
  }

  @SuppressWarnings("unused")
  private String formFieldName(String methodName) {
    if(methodName.startsWith("get") || methodName.startsWith("set")) {
      String fName = methodName.substring(3);
      return Character.toLowerCase(fName.charAt(0)) + fName.substring(1);
    } else if (methodName.startsWith("is")) {
      String fName = methodName.substring(2);
      return Character.toLowerCase(fName.charAt(0)) + fName.substring(1);
    }
    //Method has not be named according to Java Bean Specifications. No way to figure out.
    return null;
  }

  /**
   * A utility builder method to scan through the specified package and find all classes/POJOs
   * that are annotated with the @Document annotation.
   *
   * @param dbConfig the object that holds all the baseScanPackage and other settings.
   * @return A Map of collection classes/POJOs
   */
  public static Map builder(JsonDBConfig dbConfig) {
    Map collectionMetaData = new LinkedHashMap();
    Reflections reflections = new Reflections(dbConfig.getBaseScanPackage());
    Set> docClasses = reflections.getTypesAnnotatedWith(Document.class);
    for(Class c : docClasses) {
      Document d = c.getAnnotation(Document.class);
      String collectionName = d.collection();
      String version = d.schemaVersion();
      CollectionMetaData cmd = new CollectionMetaData(collectionName, c, version, dbConfig.getSchemaComparator());
      collectionMetaData.put(collectionName, cmd);
    }
    return collectionMetaData;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy