1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 /*
20  * Licensed to the Apache Software Foundation (ASF) under one
21  * or more contributor license agreements. See the NOTICE file
22  * distributed with this work for additional information
23  * regarding copyright ownership. The ASF licenses this file
24  * to you under the Apache License, Version 2.0 (the
25  * "License"); you may not use this file except in compliance
26  * with the License. You may obtain a copy of the License at
27  *
28  *   http://www.apache.org/licenses/LICENSE-2.0
29  *
30  * Unless required by applicable law or agreed to in writing,
31  * software distributed under the License is distributed on an
32  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
33  * KIND, either express or implied. See the License for the
34  * specific language governing permissions and limitations
35  * under the License.
36  */
37 
38 package org.apache.thrift.meta_data;
39 
40 import org.apache.thrift.TBase;
41 
42 import java.util.Hashtable;
43 
44 
45 /**
46  * This class is used to store meta data about thrift fields. Every field in a
47  * a struct should have a corresponding instance of this class describing it.
48  *
49  * The meta data is registered by ALL Thrift struct classes via a static {...}
50  * initializer block in the generated Thrift code.
51  *
52  * Since different threads could be initializing different Thrift classes, calls
53  * to the public static methods of this class could be racy.
54  *
55  * All methods of this class should be made thread safe.
56  */
57 public class FieldMetaData  {
58   public final String fieldName;
59   public final byte requirementType;
60   public final FieldValueMetaData valueMetaData;
61   private static final Hashtable structMap;
62 
63   static {
64     structMap = new Hashtable();
65   }
66 
FieldMetaData(String name, byte req, FieldValueMetaData vMetaData)67   public FieldMetaData(String name, byte req, FieldValueMetaData vMetaData){
68     this.fieldName = name;
69     this.requirementType = req;
70     this.valueMetaData = vMetaData;
71   }
72 
addStructMetaDataMap(Class sClass, Hashtable map)73   public static void addStructMetaDataMap(Class sClass, Hashtable map){
74     synchronized (structMap) {
75       structMap.put(sClass, map);
76     }
77   }
78 
79   /**
80    * Returns a map with metadata (i.e. instances of FieldMetaData) that
81    * describe the fields of the given class.
82    *
83    * @param sClass The TBase class for which the metadata map is requested. It is not
84    *               guaranteed that sClass will have been statically initialized before
85    *               this method is called. A racy call to
86    *               {@link FieldMetaData#addStructMetaDataMap(Class, Hashtable)} from a different
87    *               thread during static initialization of the Thrift class is possible.
88    */
getStructMetaDataMap(Class sClass)89   public static Hashtable getStructMetaDataMap(Class sClass) {
90     // Note: Do not use synchronized on this method declaration - it leads to a deadlock.
91     // Similarly, do not trigger sClass.newInstance() while holding a lock on structMap,
92     // it will lead to the same deadlock.
93     // See: https://issues.apache.org/jira/browse/THRIFT-5430 for details.
94     boolean isThriftStructStaticallyInitialized = false;
95     synchronized (structMap) {
96       isThriftStructStaticallyInitialized = structMap.containsKey(sClass);
97     }
98 
99     if (!isThriftStructStaticallyInitialized){ // Load class if it hasn't been loaded
100       try{
101         sClass.newInstance();
102       } catch (InstantiationException e){
103         throw new RuntimeException("InstantiationException for TBase class: " + sClass.getName() + ", message: " + e.getMessage());
104       } catch (IllegalAccessException e){
105         throw new RuntimeException("IllegalAccessException for TBase class: " + sClass.getName() + ", message: " + e.getMessage());
106       }
107     }
108     synchronized (structMap) {
109       return (Hashtable) structMap.get(sClass);
110     }
111   }
112 }
113