View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jexl3.internal;
18  
19  import java.util.Collections;
20  import java.util.Map;
21  import java.util.Objects;
22  
23  import org.apache.commons.jexl3.JexlFeatures;
24  
25  /**
26   * Maintains the set of allowed features associated with a script/expression source.
27   * <p>This is meant for caching scripts using their 'source' as key but still distinguishing
28   * scripts with different features and prevent false sharing.
29   */
30  public final class Source implements Comparable<Source> {
31      /** The hash code, pre-computed for fast op. */
32      private final int hashCode;
33      /** The set of features. */
34      private final JexlFeatures features;
35      /** The local symbols, if any. */
36      private final Map<String, Integer> symbols;
37      /** The actual source script/expression. */
38      private final String str;
39  
40      /**
41       * Default constructor.
42       * @param theFeatures the features
43       * @param theSymbols the map of variable name to symbol offset in evaluation frame
44       * @param theStr the script source
45       */
46      Source(final JexlFeatures theFeatures, final Map<String, Integer> theSymbols,  final String theStr) {
47          this.features = theFeatures;
48          this.symbols = theSymbols == null ? Collections.emptyMap() : theSymbols;
49          this.str = theStr;
50          this.hashCode = Objects.hash(features, symbols, str);
51      }
52  
53      @Override
54      public int compareTo(final Source s) {
55          int cmp = str.compareTo(s.str);
56          if (cmp == 0) {
57              cmp = Integer.compare(features.hashCode(), s.features.hashCode());
58              if (cmp == 0) {
59                  cmp = Integer.compare(symbols.hashCode(), s.symbols.hashCode());
60                  if (cmp == 0) {
61                      if (Objects.equals(features, s.features)) {
62                          if (Objects.equals(symbols, s.symbols)) {
63                              return 0;
64                          }
65                         return -1; // Same features, different symbols
66                      }
67                      return +1; // Different features
68                  }
69              }
70          }
71          return cmp;
72      }
73  
74      @Override
75      public boolean equals(final Object obj) {
76          if (this == obj) {
77              return true;
78          }
79          if (obj == null) {
80              return false;
81          }
82          if (getClass() != obj.getClass()) {
83              return false;
84          }
85          final Source other = (Source) obj;
86          if (!Objects.equals(this.features, other.features)) {
87              return false;
88          }
89          if (!Objects.equals(this.symbols, other.symbols)) {
90              return false;
91          }
92          if (!Objects.equals(this.str, other.str)) {
93              return false;
94          }
95          return true;
96      }
97  
98      /**
99       * @return the features associated with the source
100      */
101     public JexlFeatures getFeatures() {
102         return features;
103     }
104 
105     @Override
106     public int hashCode() {
107         return hashCode;
108     }
109 
110     /**
111      * @return the length of the script source
112      */
113     int length() {
114         return str.length();
115     }
116 
117     @Override
118     public String toString() {
119         return str;
120     }
121 
122 }