View Javadoc
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  package org.apache.maven.model.profile.activation;
20  
21  import javax.inject.Named;
22  import javax.inject.Singleton;
23  
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.List;
27  import java.util.regex.Pattern;
28  
29  import org.apache.maven.model.Activation;
30  import org.apache.maven.model.Profile;
31  import org.apache.maven.model.building.ModelProblem.Severity;
32  import org.apache.maven.model.building.ModelProblem.Version;
33  import org.apache.maven.model.building.ModelProblemCollector;
34  import org.apache.maven.model.building.ModelProblemCollectorRequest;
35  import org.apache.maven.model.profile.ProfileActivationContext;
36  
37  /**
38   * Determines profile activation based on the version of the current Java runtime.
39   *
40   * @author Benjamin Bentmann
41   * @see Activation#getJdk()
42   */
43  @Named("jdk-version")
44  @Singleton
45  public class JdkVersionProfileActivator implements ProfileActivator {
46  
47      private static final Pattern FILTER_1 = Pattern.compile("[^\\d._-]");
48      private static final Pattern FILTER_2 = Pattern.compile("[._-]");
49      private static final Pattern FILTER_3 = Pattern.compile("\\."); // used for split now
50  
51      @Override
52      public boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
53          Activation activation = profile.getActivation();
54  
55          if (activation == null) {
56              return false;
57          }
58  
59          String jdk = activation.getJdk();
60  
61          if (jdk == null) {
62              return false;
63          }
64  
65          String version = context.getSystemProperties().get("java.version");
66  
67          if (version == null || version.length() <= 0) {
68              problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
69                      .setMessage("Failed to determine Java version for profile " + profile.getId())
70                      .setLocation(activation.getLocation("jdk")));
71              return false;
72          }
73          return isJavaVersionCompatible(jdk, version);
74      }
75  
76      public static boolean isJavaVersionCompatible(String requiredJdkRange, String currentJavaVersion) {
77          if (requiredJdkRange.startsWith("!")) {
78              return !currentJavaVersion.startsWith(requiredJdkRange.substring(1));
79          } else if (isRange(requiredJdkRange)) {
80              return isInRange(currentJavaVersion, getRange(requiredJdkRange));
81          } else {
82              return currentJavaVersion.startsWith(requiredJdkRange);
83          }
84      }
85  
86      @Override
87      public boolean presentInConfig(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
88          Activation activation = profile.getActivation();
89  
90          if (activation == null) {
91              return false;
92          }
93  
94          String jdk = activation.getJdk();
95  
96          return jdk != null;
97      }
98  
99      private static boolean isInRange(String value, List<RangeValue> range) {
100         int leftRelation = getRelationOrder(value, range.get(0), true);
101 
102         if (leftRelation == 0) {
103             return true;
104         }
105 
106         if (leftRelation < 0) {
107             return false;
108         }
109 
110         return getRelationOrder(value, range.get(1), false) <= 0;
111     }
112 
113     private static int getRelationOrder(String value, RangeValue rangeValue, boolean isLeft) {
114         if (rangeValue.value.length() <= 0) {
115             return isLeft ? 1 : -1;
116         }
117 
118         value = FILTER_1.matcher(value).replaceAll("");
119 
120         List<String> valueTokens = new ArrayList<>(Arrays.asList(FILTER_2.split(value)));
121         List<String> rangeValueTokens = new ArrayList<>(Arrays.asList(FILTER_3.split(rangeValue.value)));
122 
123         addZeroTokens(valueTokens, 3);
124         addZeroTokens(rangeValueTokens, 3);
125 
126         for (int i = 0; i < 3; i++) {
127             int x = Integer.parseInt(valueTokens.get(i));
128             int y = Integer.parseInt(rangeValueTokens.get(i));
129             if (x < y) {
130                 return -1;
131             } else if (x > y) {
132                 return 1;
133             }
134         }
135         if (!rangeValue.closed) {
136             return isLeft ? -1 : 1;
137         }
138         return 0;
139     }
140 
141     private static void addZeroTokens(List<String> tokens, int max) {
142         while (tokens.size() < max) {
143             tokens.add("0");
144         }
145     }
146 
147     private static boolean isRange(String value) {
148         return value.startsWith("[") || value.startsWith("(");
149     }
150 
151     private static List<RangeValue> getRange(String range) {
152         List<RangeValue> ranges = new ArrayList<>();
153 
154         for (String token : range.split(",")) {
155             if (token.startsWith("[")) {
156                 ranges.add(new RangeValue(token.replace("[", ""), true));
157             } else if (token.startsWith("(")) {
158                 ranges.add(new RangeValue(token.replace("(", ""), false));
159             } else if (token.endsWith("]")) {
160                 ranges.add(new RangeValue(token.replace("]", ""), true));
161             } else if (token.endsWith(")")) {
162                 ranges.add(new RangeValue(token.replace(")", ""), false));
163             } else if (token.length() <= 0) {
164                 ranges.add(new RangeValue("", false));
165             }
166         }
167         if (ranges.size() < 2) {
168             ranges.add(new RangeValue("99999999", false));
169         }
170         return ranges;
171     }
172 
173     private static class RangeValue {
174         private String value;
175 
176         private boolean closed;
177 
178         RangeValue(String value, boolean closed) {
179             this.value = value.trim();
180             this.closed = closed;
181         }
182 
183         @Override
184         public String toString() {
185             return value;
186         }
187     }
188 }