APIJSON (11: AbstractVerifier source code reading (2))

APIJSON (11: AbstractVerifier source code reading (2))

2021SC@SDUSC

element definition

At the beginning of the class, of course, there are still a lot of element definitions——

// 共享 STRUCTURE_MAP 则不能 remove 等做任何变更,否则在并发情况下可能会出错,加锁效率又低,所以这里改为忽略对应的 key
public static final Map<String, Entry<String, Object>> ROLE_MAP;

public static final List<String> OPERATION_KEY_LIST;

// <TableName, <METHOD, allowRoles>>
// <User, <GET, [OWNER, ADMIN]>>
@NotNull
public static final Map<String, Map<RequestMethod, String[]>> SYSTEM_ACCESS_MAP;
@NotNull
public static final Map<String, Map<RequestMethod, String[]>> ACCESS_MAP;

// <method tag, <version, Request>>
// <PUT Comment, <1, { "method":"PUT", "tag":"Comment", "structure":{ "MUST":"id"... }... }>>
@NotNull
public static final Map<String, SortedMap<Integer, JSONObject>> REQUEST_MAP;

// 正则匹配的别名快捷方式,例如用 "PHONE" 代替 "^((13[0-9])|(15[^4,\\D])|(18[0-2,5-9])|(17[0-9]))\\d{8}$"
@NotNull
public static final Map<String, Pattern> COMPILE_MAP;

map

Here a lot of @NotNull annotations are used to declare that it cannot be empty, and the map interface

Map is an interface in java, and Map.Entry is an internal interface of Map.

Map provides some common methods, such as keySet(), entrySet() and other methods.

The return value of the keySet() method is a collection of key values ​​in the Map; the return value of entrySet() also returns a Set collection, and the type of this collection is Map.Entry.

Map.Entry is an internal interface declared by Map, which is generic and defined as Entry<K,V>. It represents an entity (a key-value pair) in the Map. There are getKey() and getValue methods in the interface.

Next is a static block

static {
   ROLE_MAP = new LinkedHashMap<>();
   ROLE_MAP.put(UNKNOWN, new Entry<String, Object>());
   ROLE_MAP.put(LOGIN, new Entry<String, Object>("userId>", 0));
   ROLE_MAP.put(CONTACT, new Entry<String, Object>("userId{}", "contactIdList"));
   ROLE_MAP.put(CIRCLE, new Entry<String, Object>("userId-()", "verifyCircle()")); // "userId{}", "circleIdList"));  // 还是 {"userId":"currentUserId", "userId{}": "contactIdList", "@combine": "userId,userId{}" } ? 
   ROLE_MAP.put(OWNER, new Entry<String, Object>("userId", "userId"));
   ROLE_MAP.put(ADMIN, new Entry<String, Object>("userId-()", "verifyAdmin()"));
   
   OPERATION_KEY_LIST = new ArrayList<>();
   OPERATION_KEY_LIST.add(TYPE.name());
   OPERATION_KEY_LIST.add(VERIFY.name());
   OPERATION_KEY_LIST.add(INSERT.name());
   OPERATION_KEY_LIST.add(UPDATE.name());
   OPERATION_KEY_LIST.add(REPLACE.name());
   OPERATION_KEY_LIST.add(EXIST.name());
   OPERATION_KEY_LIST.add(UNIQUE.name());
   OPERATION_KEY_LIST.add(REMOVE.name());
   OPERATION_KEY_LIST.add(MUST.name());
   OPERATION_KEY_LIST.add(REFUSE.name());


   SYSTEM_ACCESS_MAP = new HashMap<String, Map<RequestMethod, String[]>>();

   SYSTEM_ACCESS_MAP.put(Access.class.getSimpleName(), getAccessMap(Access.class.getAnnotation(MethodAccess.class)));
   SYSTEM_ACCESS_MAP.put(Function.class.getSimpleName(), getAccessMap(Function.class.getAnnotation(MethodAccess.class)));
   SYSTEM_ACCESS_MAP.put(Request.class.getSimpleName(), getAccessMap(Request.class.getAnnotation(MethodAccess.class)));
   SYSTEM_ACCESS_MAP.put(Response.class.getSimpleName(), getAccessMap(Response.class.getAnnotation(MethodAccess.class)));

   if (Log.DEBUG) {
      SYSTEM_ACCESS_MAP.put(Table.class.getSimpleName(), getAccessMap(Table.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(Column.class.getSimpleName(), getAccessMap(Column.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(PgAttribute.class.getSimpleName(), getAccessMap(PgAttribute.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(PgClass.class.getSimpleName(), getAccessMap(PgClass.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(SysTable.class.getSimpleName(), getAccessMap(SysTable.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(SysColumn.class.getSimpleName(), getAccessMap(SysColumn.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(ExtendedProperty.class.getSimpleName(), getAccessMap(ExtendedProperty.class.getAnnotation(MethodAccess.class)));

      SYSTEM_ACCESS_MAP.put(Document.class.getSimpleName(), getAccessMap(Document.class.getAnnotation(MethodAccess.class)));
      SYSTEM_ACCESS_MAP.put(TestRecord.class.getSimpleName(), getAccessMap(TestRecord.class.getAnnotation(MethodAccess.class)));
   }

   ACCESS_MAP = new HashMap<>(SYSTEM_ACCESS_MAP);

   REQUEST_MAP = new HashMap<>(ACCESS_MAP.size()*6);  // 单个与批量增删改

   COMPILE_MAP = new HashMap<String, Pattern>();
}

static{}

concept explanation

1. The characteristics of class loading
In the life cycle of the JVM, each class will only be loaded once.

The principle of class loading: lazy loading, load as little as possible, because the space of the virtual machine is limited.

2. Timing of class loading
1) When creating an object for the first time, the class needs to be loaded.

2) Classes are loaded when static methods are called, and classes are loaded when static properties are accessed.

3) When loading a subclass, the parent class must be loaded first.

4) Creating an object reference does not load the class.

  1. When a child class calls a static method of the parent class

(1) When the subclass does not override the static method of the parent class, only the parent class is loaded, and the subclass is not loaded

(2) When the subclass has a static method that overrides the parent class, both the parent class and the subclass are loaded

6) To access static constants, if the compiler can calculate the value of the constant, the class will not be loaded, for example: public static final int a =123; otherwise the class will be loaded, for example: public static final int a = math.PI.

Static block (static{})
(1) The static keyword also has a more critical role, which is used to form a static code block (static{} (ie static block)) to optimize program performance.

(2) The static block can be placed anywhere in the class, and there can be multiple static blocks in the class.

(3) Executed when the class is first loaded and will only be executed once (this is the reason for optimizing performance!!!), each static block will be executed in the order of the static block, generally used to initialize static variables and call static method.
Otherwise, whenever the method is called, these member objects will be generated, resulting in a waste of space.

LinkedHashMap

ROLE_MAP = new LinkedHashMap<>();

First, you can see that a LinkedHashMap object is created

In essence, LinkedHashMap = HashMap + doubly linked list, that is to say, the combination of HashMap and doubly linked list is LinkedHashMap. It can also be understood that LinkedHashMap adds two links (before pointer and after pointer) between any two nodes of HashMap without making any changes to HashMap, so that these nodes form a doubly linked list. In LinkedHashMapMap, all put entries are stored in the HashMap, but since it additionally defines an empty doubly linked list with head as the head node, it will be inserted into the doubly linked list for each put entry of the tail.
Write picture description here

The put method that is widely used is the method of adding key-value pairs to LinkedHashMap. For details, please refer to the following articles:

Map overview (1): A thorough understanding of HashMap

Map overview (2): A thorough understanding of LinkedHashMap

List

public static final List<String> OPERATION_KEY_LIST;

List is an interface that inherits from Collection's interface. It represents an ordered queue.

The elements in the List can be repeated and are in order (the order here refers to the storage in the order in which they are placed. If 1, 2, and 3 are stored in the List in order, then the order traversed from the List is also 1, 2, 3).

void add(int index, E element)

Insert an element at the specified position, and all subsequent elements will be moved back one element.

img

method of realization

getAccessMap

public static HashMap<RequestMethod, String[]> getAccessMap(MethodAccess access)

Note that the value passed in by getAccessMap is the MethodAccess class

public @interface MethodAccess

This is the definition of the MethodAccess class, and found that @interface looks strange

The difference between @interface and interface in java

What is java Annotation
Java has provided Annotation (annotation, annotation) since 1.5, which is used to decorate application elements (classes, methods, attributes, parameters, local variables, packages, metadata), and the compiler compares them with metadata They are stored together in the class file, and access to its modified elements is handled through Java reflection during runtime. Annotation is only used to decorate elements and cannot affect the execution of code. Its information can only be accessed and processed through its supporting framework or tools.

the difference

①, interface: declares that this is a java interface

②, @interface: It is used to modify Annotation, please note that it is not an interface. This keyword declaration implies a message: it inherits the java.lang.annotation.Annotation interface instead of declaring an interface.

Among them, the permissions of the request method are mainly defined, and only certain roles are allowed to access the database through the corresponding method.

For example, the get method, the default allowed roles are UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN;

String[] GET() default {UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

It can be found that the permissions of these methods are from low to high, POST, PUT, DELETE methods only allow OWNER, or ADMIN to use by default

String[] GET() default {UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

String[] HEAD() default {UNKNOWN, LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

String[] GETS() default {LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

String[] HEADS() default {LOGIN, CONTACT, CIRCLE, OWNER, ADMIN};

String[] POST() default {OWNER, ADMIN};

String[] PUT() default {OWNER, ADMIN};

String[] DELETE() default {OWNER, ADMIN};

Go back to our getAcessMap method, which is used to obtain these permission Maps.

if (access == null) {
   return null;
}

HashMap<RequestMethod, String[]> map = new HashMap<>();
map.put(GET, access.GET());
map.put(HEAD, access.HEAD());
map.put(GETS, access.GETS());
map.put(HEADS, access.HEADS());
map.put(POST, access.POST());
map.put(PUT, access.PUT());
map.put(DELETE, access.DELETE());
return map;

put(GET, access.GET());
map.put(HEAD, access.HEAD());
map.put(GETS, access.GETS());
map.put(HEADS, access.HEADS());
map.put(POST, access.POST());
map.put(PUT, access.PUT());
map.put(DELETE, access.DELETE());
return map;


它首先进行判断access是否为空,不是的话,就会创建一个HashMap对这些权限进行依次存储,并返回这个HashMap。

Guess you like

Origin blog.csdn.net/qq_50861917/article/details/121878897