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.eclipse.aether.internal.impl;
20  
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.eclipse.aether.ConfigurationProperties;
27  import org.eclipse.aether.RepositorySystemSession;
28  import org.eclipse.aether.util.ConfigUtils;
29  
30  /**
31   * Helps to sort pluggable components by their priority.
32   */
33  final class PrioritizedComponents<T> {
34  
35      private static final String FACTORY_SUFFIX = "Factory";
36  
37      private final Map<?, ?> configProps;
38  
39      private final boolean useInsertionOrder;
40  
41      private final List<PrioritizedComponent<T>> components;
42  
43      private int firstDisabled;
44  
45      PrioritizedComponents(RepositorySystemSession session) {
46          this(session.getConfigProperties());
47      }
48  
49      PrioritizedComponents(Map<?, ?> configurationProperties) {
50          configProps = configurationProperties;
51          useInsertionOrder = ConfigUtils.getBoolean(
52                  configProps,
53                  ConfigurationProperties.DEFAULT_IMPLICIT_PRIORITIES,
54                  ConfigurationProperties.IMPLICIT_PRIORITIES);
55          components = new ArrayList<>();
56          firstDisabled = 0;
57      }
58  
59      public void add(T component, float priority) {
60          Class<?> type = getImplClass(component);
61          int index = components.size();
62          priority = useInsertionOrder ? -index : ConfigUtils.getFloat(configProps, priority, getConfigKeys(type));
63          PrioritizedComponent<T> pc = new PrioritizedComponent<>(component, type, priority, index);
64  
65          if (!useInsertionOrder) {
66              index = Collections.binarySearch(components, pc);
67              if (index < 0) {
68                  index = -index - 1;
69              } else {
70                  index++;
71              }
72          }
73          components.add(index, pc);
74  
75          if (index <= firstDisabled && !pc.isDisabled()) {
76              firstDisabled++;
77          }
78      }
79  
80      private static Class<?> getImplClass(Object component) {
81          Class<?> type = component.getClass();
82          // detect and ignore CGLIB-based proxy classes employed by Guice for AOP (cf. BytecodeGen.newEnhancer)
83          int idx = type.getName().indexOf("$$");
84          if (idx >= 0) {
85              Class<?> base = type.getSuperclass();
86              if (base != null && idx == base.getName().length() && type.getName().startsWith(base.getName())) {
87                  type = base;
88              }
89          }
90          return type;
91      }
92  
93      static String[] getConfigKeys(Class<?> type) {
94          List<String> keys = new ArrayList<>();
95          keys.add(ConfigurationProperties.PREFIX_PRIORITY + type.getName());
96          String sn = type.getSimpleName();
97          keys.add(ConfigurationProperties.PREFIX_PRIORITY + sn);
98          if (sn.endsWith(FACTORY_SUFFIX)) {
99              keys.add(ConfigurationProperties.PREFIX_PRIORITY + sn.substring(0, sn.length() - FACTORY_SUFFIX.length()));
100         }
101         return keys.toArray(new String[0]);
102     }
103 
104     public boolean isEmpty() {
105         return components.isEmpty();
106     }
107 
108     public List<PrioritizedComponent<T>> getAll() {
109         return components;
110     }
111 
112     public List<PrioritizedComponent<T>> getEnabled() {
113         return components.subList(0, firstDisabled);
114     }
115 
116     public void list(StringBuilder buffer) {
117         int i = 0;
118         for (PrioritizedComponent<?> component : components) {
119             if (i++ > 0) {
120                 buffer.append(", ");
121             }
122             buffer.append(component.getType().getSimpleName());
123             if (component.isDisabled()) {
124                 buffer.append(" (disabled)");
125             }
126         }
127     }
128 
129     @Override
130     public String toString() {
131         return components.toString();
132     }
133 }