View Javadoc
1   /**
2    * This file Copyright (c) 2020 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.about.app.licenses;
35  
36  import info.magnolia.i18nsystem.SimpleTranslator;
37  import info.magnolia.init.MagnoliaConfigurationProperties;
38  
39  import java.io.File;
40  import java.io.FileNotFoundException;
41  import java.util.ArrayList;
42  import java.util.Comparator;
43  import java.util.List;
44  import java.util.NoSuchElementException;
45  import java.util.Scanner;
46  import java.util.regex.Matcher;
47  import java.util.regex.Pattern;
48  import java.util.stream.Stream;
49  
50  import org.apache.commons.lang3.StringUtils;
51  
52  import com.vaadin.data.provider.AbstractDataProvider;
53  import com.vaadin.data.provider.Query;
54  import com.vaadin.data.provider.QuerySortOrder;
55  import com.vaadin.shared.data.sort.SortDirection;
56  import com.vaadin.ui.Notification;
57  
58  import lombok.extern.slf4j.Slf4j;
59  
60  
61  /**
62   * Licenses data provider.
63   */
64  @Slf4j
65  public class LicensesDataProvider extends AbstractDataProvider<LicensesInfoBean, String> {
66      private static final String NOTICE = "/NOTICE.txt";
67      private final String NOTICE_FILE_PATH;
68      private List<LicensesInfoBean> licensesInfoBeans = null;
69      private final LicensesInfoBeantml#LicensesInfoBean">LicensesInfoBean licensesInfoBeanFilter = new LicensesInfoBean();
70      private final SimpleTranslator i18n;
71  
72      public LicensesDataProvider(MagnoliaConfigurationProperties magnoliaConfigurationProperties, SimpleTranslator i18n) {
73          this.i18n = i18n;
74          this.NOTICE_FILE_PATH = magnoliaConfigurationProperties.getProperty("magnolia.app.rootdir") + NOTICE;
75      }
76  
77      @Override
78      public boolean isInMemory() {
79          return true;
80      }
81  
82      @Override
83      public int size(Query<LicensesInfoBean, String> query) {
84          return (int) fetch(query).count();
85      }
86  
87      @Override
88      public Stream<LicensesInfoBean> fetch(Query<LicensesInfoBean, String> query) {
89          if (licensesInfoBeans == null) {
90              try {
91                  licensesInfoBeans = loadNoticeFile(NOTICE_FILE_PATH);
92              } catch (FileNotFoundException e) {
93                  Notification.show(i18n.translate("about.app.licenses.licenseinfo.noticeFileMissingWarning"), Notification.Type.ERROR_MESSAGE);
94                  log.error("NOTICE.txt not found!", e);
95                  // Preventing NPE occurrence
96                  licensesInfoBeans = new ArrayList<>();
97                  return licensesInfoBeans.stream();
98              }
99          }
100 
101         Stream<LicensesInfoBean> stream = licensesInfoBeans.stream().distinct()
102                 .filter(item -> StringUtils.containsIgnoreCase(item.parseLicenseName(), licensesInfoBeanFilter.parseLicenseName()))
103                 .filter(item -> StringUtils.containsIgnoreCase(item.parseDeveloperName(), licensesInfoBeanFilter.parseDeveloperName()))
104                 .filter(item -> StringUtils.containsIgnoreCase(item.parseLibraryName(), licensesInfoBeanFilter.parseLibraryName()));
105 
106         if (query.getSortOrders() != null && !query.getSortOrders().isEmpty()) {
107             QuerySortOrder querySortList = query.getSortOrders().get(0);
108             stream = stream.sorted((infoBean1, infoBean2) -> {
109                 if (querySortList.getDirection() == SortDirection.DESCENDING) {
110                     return sortItems(querySortList, infoBean1, infoBean2);
111                 } else {
112                     return sortItems(querySortList, infoBean2, infoBean1);
113                 }
114             });
115         } else {
116             stream = stream.sorted(Comparator.comparing(LicensesInfoBean::parseLibraryName, String.CASE_INSENSITIVE_ORDER));
117         }
118         stream = stream.skip(query.getOffset()).limit(query.getLimit());
119         return stream;
120     }
121 
122     private int sortItems(QuerySortOrder querySortList, LicensesInfoBean/../info/magnolia/about/app/licenses/LicensesInfoBean.html#LicensesInfoBean">LicensesInfoBean infoBean1, LicensesInfoBean infoBean2) {
123         switch (querySortList.getSorted()) {
124         case LicensesSystemDataGrid.LICENSE:
125             return infoBean1.parseLicenseName().compareToIgnoreCase(infoBean2.parseLicenseName());
126         case LicensesSystemDataGrid.DEVELOPER:
127             return infoBean1.parseDeveloperName().compareToIgnoreCase(infoBean2.parseDeveloperName());
128         }
129         return infoBean1.parseLibraryName().compareToIgnoreCase(infoBean2.parseLibraryName());
130     }
131 
132     public LicensesInfoBean getLicensesInfoBeanFilter() {
133         return licensesInfoBeanFilter;
134     }
135 
136     private ArrayList<LicensesInfoBean> loadNoticeFile(String filePath) throws FileNotFoundException {
137         ArrayList<LicensesInfoBean> noticeLicensesArray = new ArrayList<>();
138         File noticeFile = new File(filePath);
139         Scanner fileReader = new Scanner(noticeFile);
140 
141         String line = "";
142         // Skip first three lines of NOTICE.txt file
143         for (int i = 0; i < 3; i++) {
144             if (fileReader.hasNextLine()) {
145                 line = fileReader.nextLine();
146             }
147         }
148 
149         Pattern developerInfoPattern = Pattern.compile("This.*'(.*)'(.*)$");
150         Pattern libraryNamePattern = Pattern.compile("-\\s((.(?!\\(http|\\(www))+)");
151         Pattern licenseNamePattern = Pattern.compile("License:\\s((.(?!\\(http|\\(www))+)");
152         Pattern urlPattern = Pattern.compile("[(]((http|www).+)[)]");
153 
154         String developerName = "";
155         while (fileReader.hasNextLine()) {
156             boolean parseHandler = false;
157             String libName = "";
158             ArrayList<String> licenseList = new ArrayList<>();
159 
160             if (line.length() == 0) {
161                 if (fileReader.hasNextLine()) {
162                     line = fileReader.nextLine();
163                 }
164             }
165 
166             Matcher developerMatch = developerInfoPattern.matcher(line);
167             if (developerMatch.find()) {
168                 parseHandler = true;
169                 String developerHTML = developerMatch.group(2).replace("(", "").replace(")", "");
170                 developerName = toHTMLHref(developerHTML, developerMatch.group(1));
171                 line = getNewLine(fileReader);
172             }
173 
174             Matcher libraryMatch = libraryNamePattern.matcher(line);
175             if (libraryMatch.find()) {
176                 parseHandler = true;
177                 libName = checkForURL(line, urlPattern, libraryMatch.group(1));
178                 line = getNewLine(fileReader);
179             }
180 
181             Matcher licenseMatch = licenseNamePattern.matcher(line);
182             for (; licenseMatch.find(); licenseMatch = licenseNamePattern.matcher(line)) {
183                 parseHandler = true;
184                 String licenseText = checkForURL(line, urlPattern, licenseMatch.group(1));
185                 licenseList.add(licenseText);
186                 try {
187                     line = fileReader.nextLine();
188                 } catch (NoSuchElementException e) {
189                     break;
190                 }
191             }
192 
193             /* Parsed info analysis */
194             if (licenseList.size() == 0 && !libName.equals("")) {
195                 // Library's license wasn't provided
196                 licenseList.add("");
197                 noticeLicensesArray.add(new LicensesInfoBean(libName, developerName, licenseList));
198             } else if (licenseList.size() == 0) {
199                 // Only Developer name or nothing was parsed, continue with next line
200             } else {
201                 noticeLicensesArray.add(new LicensesInfoBean(libName, developerName, licenseList));
202             }
203 
204             // Cycle prevention
205             if (!parseHandler) {
206                 try {
207                     line = fileReader.nextLine();
208                 } catch (NoSuchElementException e) {
209                     break;
210                 }
211             }
212         }
213         fileReader.close();
214         return noticeLicensesArray;
215     }
216 
217     private String checkForURL(String line, Pattern urlPattern, String licenseText) {
218         Matcher urlMatch = urlPattern.matcher(line);
219         if (urlMatch.find()) {
220             licenseText = toHTMLHref(urlMatch.group(1), licenseText);
221         }
222         return licenseText;
223     }
224 
225 
226     private String getNewLine(Scanner fileReader) {
227         String line = "";
228         if (fileReader.hasNextLine()) {
229             line = fileReader.nextLine();
230         }
231         return line;
232     }
233 
234     private String toHTMLHref(String link, String title) {
235         if (link.length() > 0) {
236             // Fix HTML renderer issue with links missing http
237             link = StringUtils.prependIfMissingIgnoreCase(link.trim(), "http://", "http://", "https://");
238             return "<a class=\"license-info-link\" href=\"" + link + "\" target=\"_blank\">" +
239                     title.replaceAll("\\s+$", "") +
240                     "</a><span class=\"icon icon-external-webpage\"></span>";
241         }
242         return title;
243     }
244 }