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  
32      /** The hash code, pre-computed for fast op. */
33      private final int hashCode;
34  
35      /** The set of features. */
36      private final JexlFeatures features;
37  
38      /** The local symbols, if any. */
39      private final Map<String, Integer> symbols;
40  
41      /** The actual source script/expression. */
42      private final String str;
43  
44      /**
45       * Default constructor.
46       *
47       * @param theFeatures the features
48       * @param theSymbols the map of variable name to symbol offset in evaluation frame
49       * @param theStr the script source
50       */
51      Source(final JexlFeatures theFeatures, final Map<String, Integer> theSymbols,  final String theStr) {
52          this.features = theFeatures;
53          this.symbols = theSymbols == null ? Collections.emptyMap() : theSymbols;
54          this.str = theStr;
55          this.hashCode = Objects.hash(features, symbols, str);
56      }
57  
58      @Override
59      public int compareTo(final Source s) {
60          int cmp = str.compareTo(s.str);
61          if (cmp == 0) {
62              cmp = Integer.compare(features.hashCode(), s.features.hashCode());
63              if (cmp == 0) {
64                  cmp = Integer.compare(symbols.hashCode(), s.symbols.hashCode());
65                  if (cmp == 0) {
66                      if (Objects.equals(features, s.features)) {
67                          if (Objects.equals(symbols, s.symbols)) {
68                              return 0;
69                          }
70                         return -1; // Same features, different symbols
71                      }
72                      return +1; // Different features
73                  }
74              }
75          }
76          return cmp;
77      }
78  
79      @Override
80      public boolean equals(final Object obj) {
81          if (this == obj) {
82              return true;
83          }
84          if (obj == null) {
85              return false;
86          }
87          if (getClass() != obj.getClass()) {
88              return false;
89          }
90          final Source other = (Source) obj;
91          if (!Objects.equals(this.features, other.features)) {
92              return false;
93          }
94          if (!Objects.equals(this.symbols, other.symbols)) {
95              return false;
96          }
97          if (!Objects.equals(this.str, other.str)) {
98              return false;
99          }
100         return true;
101     }
102 
103     /**
104      * @return the features associated with the source
105      */
106     public JexlFeatures getFeatures() {
107         return features;
108     }
109 
110     @Override
111     public int hashCode() {
112         return hashCode;
113     }
114 
115     /**
116      * @return the length of the script source
117      */
118     int length() {
119         return str.length();
120     }
121 
122     @Override
123     public String toString() {
124         return str;
125     }
126 
127 }