001package io.ebean.enhance.common;
002
003import java.util.HashSet;
004import java.util.List;
005import java.util.Set;
006import java.util.StringJoiner;
007import java.util.TreeSet;
008
009/**
010 * Summary of the enhancement.
011 */
012public class SummaryInfo {
013
014  private final List<String> loadedResources;
015  private final Set<String> entities = new HashSet<>();
016  private final Set<String> queryBeans = new HashSet<>();
017  private final Set<String> queryBeanCallers = new HashSet<>();
018  private final Set<String> transactional = new HashSet<>();
019
020  SummaryInfo(List<String> loadedResources) {
021    this.loadedResources = loadedResources;
022  }
023
024  /**
025   * Remove from queryBeanCallers the queryBeans (due to profile location enhancement).
026   */
027  SummaryInfo prepare() {
028    for (String queryBean : queryBeans) {
029      queryBeanCallers.remove(queryBean);
030      queryBeanCallers.remove(queryBean + "$Companion");
031    }
032    return this;
033  }
034
035  /**
036   * Return true if there was nothing enhanced.
037   */
038  public boolean isEmpty() {
039    return entities.isEmpty() && queryBeans.isEmpty() && queryBeanCallers.isEmpty() && transactional.isEmpty();
040  }
041
042  public boolean hasEntities() {
043    return !entities.isEmpty();
044  }
045
046  public boolean hasQueryBeans() {
047    return !queryBeans.isEmpty();
048  }
049
050  public boolean hasTransactional() {
051    return !transactional.isEmpty();
052  }
053
054  public boolean hasQueryCallers() {
055    return !queryBeanCallers.isEmpty();
056  }
057
058
059  public String toString() {
060    return " entities:" + entities + " queryBeans:" + queryBeans + " tqb:" + transactional;
061  }
062
063  void addTransactional(String className) {
064    transactional.add(className);
065  }
066
067  void addEntity(String className) {
068    entities.add(className);
069  }
070
071  void addQueryBean(String className) {
072    queryBeans.add(className);
073  }
074
075  void addQueryBeanCaller(String className) {
076    queryBeanCallers.add(className);
077  }
078
079  private String summary(String prefix, Set<String> beans) {
080    return new SumOut(beans).summary(prefix);
081  }
082
083  /**
084   * Return the manifest resource paths that were loaded.
085   */
086  public List<String> loadedResources() {
087    return loadedResources;
088  }
089
090  /**
091   * Return a summary of the entities enhanced.
092   */
093  public String entities() {
094    return summary("     Entities", entities);
095  }
096
097  /**
098   * Return a summary of the query beans enhanced.
099   */
100  public String queryBeans() {
101    return summary("   QueryBeans", queryBeans);
102  }
103
104  /**
105   * Return a summary of the beans enhanced that call query beans.
106   */
107  public String queryCallers() {
108    return summary("Query Callers", queryBeanCallers);
109  }
110
111  /**
112   * Return a summary of the beans with transactional enhanced.
113   */
114  public String transactional() {
115    return summary("Transactional", transactional);
116  }
117
118  /**
119   * Helper that trims off the common package prefix to shorten the output.
120   */
121  static class SumOut {
122
123    private final Set<String> beans;
124    private final Set<String> trimmedBeans;
125    private String[] commonAsArray;
126    private String commonPrefix;
127
128    SumOut(Set<String> beans) {
129      this.beans = beans;
130      initCommonPrefix();
131      trimmedBeans = trimmedBeans();
132    }
133
134    String sizeOut(int size) {
135      return " (" + size + ")" + ((size < 9) ? " " : "");
136    }
137
138    String summary(String prefix) {
139      return prefix + sizeOut(beans.size()) + " pkgs[" + commonPrefix + "] beans" + trimmedBeans.toString();
140    }
141
142    String commonPackage() {
143      return commonPrefix;
144    }
145
146    String beans() {
147      return trimmedBeans.toString();
148    }
149
150    private void initCommonPrefix() {
151      if (beans.isEmpty()) {
152        commonPrefix = "";
153      } else {
154        for (String bean : beans) {
155          final String beanPrefix = prefix(bean);
156          if (commonPrefix == null) {
157            commonPrefix = beanPrefix;
158            commonAsArray = beanPrefix.split("/");
159          } else {
160            common(beanPrefix);
161          }
162        }
163      }
164    }
165
166    private void common(String beanPrefix) {
167      if (beanPrefix.equals(commonPrefix)) {
168        return;
169      }
170
171      final String[] elements = beanPrefix.split("/");
172      int min = Math.min(commonAsArray.length, elements.length);
173      for (int i = 0; i < min; i++) {
174        if (!elements[i].equals(commonAsArray[i])) {
175          commonFor(i);
176          return;
177        }
178      }
179      if (commonAsArray.length != min) {
180        commonFor(min);
181      }
182    }
183
184    private void setCommonPrefix(String beanPrefix) {
185      commonPrefix = beanPrefix;
186      commonAsArray = beanPrefix.split("/");
187    }
188
189    private void commonFor(int pos) {
190      StringJoiner joiner = new StringJoiner("/");
191      for (int i = 0; i < pos; i++) {
192        joiner.add(commonAsArray[i]);
193      }
194      setCommonPrefix(joiner.toString());
195    }
196
197    String prefix(String bean) {
198      final int pos = bean.lastIndexOf('/');
199      return (pos == -1) ? bean : bean.substring(0, pos);
200    }
201
202    private Set<String> trimmedBeans() {
203      if (beans.isEmpty()) {
204        return beans;
205      }
206      Set<String> temp = new TreeSet<>();
207      int trimLen = commonPrefix.length() + 1;
208      if (trimLen == 1) {
209        trimLen = 0;
210      }
211      for (String bean : beans) {
212        if (bean.length() > trimLen) {
213          bean = bean.substring(trimLen);
214        }
215        temp.add(bean);
216      }
217      return temp;
218    }
219
220  }
221}