• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package ohos;
18 
19 import com.alibaba.fastjson.JSON;
20 import com.alibaba.fastjson.serializer.SerializerFeature;
21 
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.math.BigInteger;
27 import java.security.MessageDigest;
28 import java.security.NoSuchAlgorithmException;
29 import java.text.SimpleDateFormat;
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 /**
34  * scanDuplicate info
35  *
36  * @since 2023/11/27
37  */
38 
39 public class ScanStatDuplicate {
40     private static final String UNPACK_NAME = "unpack";
41     private static final String DUPLICATE_FOLDER_NAME = "duplicate";
42     private static final String EMPTY_STRING = "";
43     private static final String SHA_256 = "SHA-256";
44     private static final String RESULT_MD5 = "md5";
45     private static final String RESULT_SIZE = "size";
46     private static final String RESULT_FILES = "files";
47     private static final String DUPLICATE_DESC = "find the duplicated files";
48     private static final String DUPLICATE_PARAM = "--stat-duplicate";
49     private static final String TASK_TYPE = "taskType";
50     private static final String TASK_DESC = "taskDesc";
51     private static final String PARAM = "param";
52     private static final String START_TIME = "startTime";
53     private static final String STOP_TIME = "stopTime";
54     private static final String RESULT = "result";
55     private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss:SSS";
56     private static final int MD5_BUFFER_SIZE = 1024;
57     private static final long DUPLICATE_TYPE = 1L;
58     private static final int MD5_LENGTH = 16;
59     private static final long SHOW_SIZE = 10L;
60     private static final String HTML_BUTTON_SHOW = "<button id=\"show_%s\" type=\"button\" "
61             + "onclick=\"show_%s()\" style=\"display: block\">more</button>";
62     private static final String HTML_BUTTON_HIDE = "<button id=\"hide_%s\" type=\"button\" "
63             + "onclick=\"hide_%s()\" style=\"display: none\">close</button>";
64     private static final String HTML_TABLE_BOX = "<table class=\"boxTable\">";
65     private static final String HTML_TABLE_END = "</table>";
66     private static final String HTML_TR_TD_LAYOUT = "<tr class=\"layout\"><td class=\"key\">";
67     private static final String HTML_TR_TD_VALUE = "</td><td class=\"value\">";
68     private static final String HTML_TR_TD_END = "</td></tr>";
69     private static final String HTML_TR_TD_RESULT = "<tr class=\"result\"><td class=\"key\">";
70     private static final String HTML_TR_TD = "<tr%s><td%s>";
71     private static final String HTML_TD_END_TD = "</td><td%s>";
72     private static final String HTML_LI_CIRCLE = "<li type=\"circle\">";
73     private static final String HTML_LI_END = "</li>";
74     private static final String HTML_TR_TD_DUPLICATE_KEY = "<tr class=\"duplicateLayout\"><td class=\"duplicateKey\">";
75     private static final String HTML_TD_DUPLICATE_VALUE = "</td><td class=\"duplicateValue\"><ul>";
76     private static final String HTML_UL_TD_TR_END = "</ul></td></tr>";
77     private static final String HTML_UL_HEAD = "<ul>";
78     private static final String CLASS_DUPLICATE_LAYOUT = " class=\"duplicateLayout\"";
79     private static final String CLASS_DUPLICATE_KEY = " class=\"duplicateKey\"";
80     private static final String CLASS_DUPLICATE_VALUE = " class=\"duplicateValue\"";
81     private static final String HTML_LI_HEAD = "<li>";
82     private static final String HTML_LI_DUPLICATE = "<li class=\"duplicate\">";
83     private static final String HTML_TABLE_DUPLICATE = "<table class=\"duplicateTable\">";
84     private static final String HTML_TABLE_LI_END = "</table></li>";
85     private static final String HTML_UL_END = "</ul>";
86     private static final Log LOG = new Log(ScanStatDuplicate.class.toString());
87 
88     private static class ParamModel {
89         private String md5 = EMPTY_STRING;
90         private long size;
91         private List<String> files = new ArrayList<>();
92 
getMd5()93         public String getMd5() {
94             return this.md5;
95         }
setMd5(String md5)96         public void setMd5(String md5) {
97             this.md5 = md5;
98         }
getSize()99         public long getSize() {
100             return this.size;
101         }
setSize(long size)102         public void setSize(long size) {
103             this.size = size;
104         }
getFiles()105         public List<String> getFiles() {
106             return this.files;
107         }
setFiles(List<String> files)108         public void setFiles(List<String> files) {
109             this.files = files;
110         }
111     }
112 
113     private static class DuplicateResult {
114         private long taskType = DUPLICATE_TYPE;
115         private String taskDesc = DUPLICATE_DESC;
116         private String param = DUPLICATE_PARAM;
117         private String startTime = EMPTY_STRING;
118         private String stopTime = EMPTY_STRING;
119         private List<ParamModel> result = new ArrayList<>();
120 
getTaskType()121         public long getTaskType() {
122             return this.taskType;
123         }
setTaskType(long taskType)124         public void setTaskType(long taskType) {
125             this.taskType = taskType;
126         }
getTaskDesc()127         public String getTaskDesc() {
128             return this.taskDesc;
129         }
setTaskDesc(String taskDesc)130         public void setTaskDesc(String taskDesc) {
131             this.taskDesc = taskDesc;
132         }
getParam()133         public String getParam() {
134             return this.param;
135         }
setParam(String param)136         public void setParam(String param) {
137             this.param = param;
138         }
getStartTime()139         public String getStartTime() {
140             return this.startTime;
141         }
setStartTime(String startTime)142         public void setStartTime(String startTime) {
143             this.startTime = startTime;
144         }
getStopTime()145         public String getStopTime() {
146             return this.stopTime;
147         }
setStopTime(String stopTime)148         public void setStopTime(String stopTime) {
149             this.stopTime = stopTime;
150         }
getResult()151         public List<ParamModel> getResult() {
152             return this.result;
153         }
setResult(List<ParamModel> result)154         public void setResult(List<ParamModel> result) {
155             this.result = result;
156         }
157     }
158 
159     /**
160      * scan statDuplicate.
161      *
162      * @param utility utility data
163      * @param jsonList List<String> data
164      * @param fileList List<String> data
165      * @return duplicate html
166      * @throws IOException Throws this exception if getDuplicateResList exception
167      * @throws NoSuchAlgorithmException Throws this exception if getDuplicateResList exception
168      */
statDuplicate(Utility utility, List<String> jsonList, List<String> fileList)169     public String statDuplicate(Utility utility, List<String> jsonList, List<String> fileList)
170             throws IOException, NoSuchAlgorithmException {
171         DuplicateResult duplicateResult = new DuplicateResult();
172         duplicateResult.setStartTime(getCurrentTime());
173         List<ParamModel> resList = getDuplicateResList(fileList);
174         File parentFile = new File(utility.getOutPath());
175         if (!parentFile.exists() && !parentFile.mkdirs()) {
176             LOG.error(ScanErrorEnum.STAT_DUPLICATE_CREATE_FILE_ERROR.toString());
177         }
178         List<ParamModel> filterList = new ArrayList<>();
179         for (ParamModel model : resList) {
180             List<String> files = model.getFiles();
181             if (files.size() > 1) {
182                 filterList.add(model);
183             }
184         }
185         duplicateResult.setResult(filterList);
186         duplicateResult.setStopTime(getCurrentTime());
187         String taskTypeHtml = getHtmlRow(TASK_TYPE, duplicateResult.getTaskType());
188         String taskDescHtml = getHtmlRow(TASK_DESC, duplicateResult.getTaskDesc());
189         String paramHtml = getHtmlRow(PARAM, duplicateResult.getParam());
190         String startTimeHtml = getHtmlRow(START_TIME, duplicateResult.getStartTime());
191         String stopTimeHtml = getHtmlRow(STOP_TIME, duplicateResult.getStopTime());
192         String resultValue = getResultHtml(duplicateResult.getResult());
193         String resultHtml = getHtmlRowResultClass(RESULT, resultValue);
194         String htmlStr = HTML_TABLE_BOX + taskTypeHtml + taskDescHtml + paramHtml
195                 + startTimeHtml + stopTimeHtml + resultHtml + HTML_TABLE_END;
196         String jsonStr = JSON.toJSONString(duplicateResult, new SerializerFeature[] {
197                 SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
198                 SerializerFeature.WriteDateUseDateFormat});
199         jsonList.add(jsonStr);
200         return htmlStr;
201     }
202 
getCurrentTime()203     private static String getCurrentTime() {
204         long currentTimeMillis = System.currentTimeMillis();
205         return new SimpleDateFormat(DATE_FORMAT).format(currentTimeMillis);
206     }
207 
getDuplicateResList(List<String> fileList)208     private List<ParamModel> getDuplicateResList(List<String> fileList) throws IOException, NoSuchAlgorithmException {
209         List<ParamModel> resList = new ArrayList<>();
210         for (String filePath : fileList) {
211             boolean addFlag = true;
212             String md5 = md5HashCode(filePath);
213             for (ParamModel element : resList) {
214                 String eleMd5 = element.getMd5();
215                 if (eleMd5.equals(md5)) {
216                     List<String> eleFiles = element.getFiles();
217                     eleFiles.add(splitPath(filePath, UNPACK_NAME));
218                     element.setFiles(eleFiles);
219                     addFlag = false;
220                 }
221             }
222             if (addFlag) {
223                 ParamModel model = new ParamModel();
224                 long size = FileUtils.getFileSize(filePath);
225                 model.setMd5(md5);
226                 model.setSize(size);
227                 List<String> files = model.getFiles();
228                 files.add(splitPath(filePath, UNPACK_NAME));
229                 resList.add(model);
230             }
231         }
232         return resList;
233     }
234 
getHtmlRow(String key, long valve)235     private static String getHtmlRow(String key, long valve) {
236         return HTML_TR_TD_LAYOUT + key + HTML_TR_TD_VALUE + valve + HTML_TR_TD_END;
237     }
238 
getHtmlRow(String key, String valve)239     private static String getHtmlRow(String key, String valve) {
240         return HTML_TR_TD_LAYOUT + key + HTML_TR_TD_VALUE + valve + HTML_TR_TD_END;
241     }
242 
getHtmlRowResultClass(String key, String valve)243     private static String getHtmlRowResultClass(String key, String valve) {
244         return HTML_TR_TD_RESULT + key + HTML_TR_TD_VALUE + valve + HTML_TR_TD_END;
245     }
246 
getHtmlRowResult(String key, long valve, String trClass, String tdClassKey, String tdClassValue)247     private static String getHtmlRowResult(String key, long valve,
248                                            String trClass, String tdClassKey, String tdClassValue) {
249         return String.format(HTML_TR_TD + key + HTML_TD_END_TD + valve + HTML_TR_TD_END,
250                 trClass, tdClassKey, tdClassValue);
251     }
252 
getHtmlRowResult(String key, String valve, String trClass, String tdClassKey, String tdClassValue)253     private static String getHtmlRowResult(String key, String valve,
254                                            String trClass, String tdClassKey, String tdClassValue) {
255         return String.format(HTML_TR_TD + key + HTML_TD_END_TD + valve + HTML_TR_TD_END,
256                 trClass, tdClassKey, tdClassValue);
257     }
258 
getHtmlRowResult(String key, List<String> valve)259     private static String getHtmlRowResult(String key, List<String> valve) {
260         StringBuilder resValve = new StringBuilder(EMPTY_STRING);
261         for (String ele : valve) {
262             resValve.insert(0, HTML_LI_CIRCLE + ele + HTML_LI_END);
263         }
264         return HTML_TR_TD_DUPLICATE_KEY + key + HTML_TD_DUPLICATE_VALUE + resValve + HTML_UL_TD_TR_END;
265     }
266 
getResultHtml(List<ParamModel> models)267     private static String getResultHtml(List<ParamModel> models) {
268         StringBuilder resultHtml = new StringBuilder(EMPTY_STRING);
269         resultHtml.append(HTML_UL_HEAD);
270         for (int i = 0; i < models.size(); i++) {
271             ParamModel model = models.get(i);
272             String md5Html = getHtmlRowResult(RESULT_MD5, model.getMd5(),
273                     CLASS_DUPLICATE_LAYOUT, CLASS_DUPLICATE_KEY, CLASS_DUPLICATE_VALUE);
274             String sizeHtml = getHtmlRowResult(RESULT_SIZE, model.getSize(),
275                     CLASS_DUPLICATE_LAYOUT, CLASS_DUPLICATE_KEY, CLASS_DUPLICATE_VALUE);
276             String filesHtml = getHtmlRowResult(RESULT_FILES, model.getFiles());
277             String liHtml;
278             if (SHOW_SIZE > i) {
279                 liHtml = HTML_LI_HEAD;
280             } else {
281                 liHtml = HTML_LI_DUPLICATE;
282             }
283             String modelHtml = liHtml + HTML_TABLE_DUPLICATE
284                     + md5Html + sizeHtml + filesHtml + HTML_TABLE_LI_END;
285             resultHtml.append(modelHtml);
286         }
287         resultHtml.append(HTML_UL_END);
288         if (models.size() > SHOW_SIZE) {
289             resultHtml.append(String.format(HTML_BUTTON_SHOW, DUPLICATE_FOLDER_NAME, DUPLICATE_FOLDER_NAME));
290             resultHtml.append(String.format(HTML_BUTTON_HIDE, DUPLICATE_FOLDER_NAME, DUPLICATE_FOLDER_NAME));
291         }
292         return resultHtml.toString();
293     }
294 
md5HashCode(String filePath)295     private String md5HashCode(String filePath) throws IOException, NoSuchAlgorithmException {
296         try (InputStream fis = new FileInputStream(filePath)) {
297             MessageDigest md = MessageDigest.getInstance(SHA_256);
298             byte[] buffer = new byte[MD5_BUFFER_SIZE];
299             int length;
300             while ((length = fis.read(buffer, 0, MD5_BUFFER_SIZE)) != -1) {
301                 md.update(buffer, 0, length);
302             }
303             byte[] md5Bytes = md.digest();
304             BigInteger bigInt = new BigInteger(1, md5Bytes);
305             return bigInt.toString(MD5_LENGTH);
306         } catch (IOException e) {
307             LOG.error(ScanErrorEnum.STAT_DUPLICATE_INPUT_STREAM_ERROR + e.getMessage());
308             throw new IOException(ScanErrorEnum.STAT_DUPLICATE_INPUT_STREAM_ERROR.msg + e.getMessage());
309         } catch (NoSuchAlgorithmException e) {
310             LOG.error(ScanErrorEnum.STAT_DUPLICATE_MESSAGE_DIGEST_ERROR + e.getMessage());
311             throw new NoSuchAlgorithmException(ScanErrorEnum.STAT_DUPLICATE_MESSAGE_DIGEST_ERROR.msg
312                     + e.getMessage());
313         }
314     }
315 
splitPath(String path, String packageName)316     private String splitPath(String path, String packageName) {
317         String[] split = path.split(packageName);
318         if (split.length > 1) {
319             return split[1];
320         } else {
321             return path;
322         }
323     }
324 }
325