View Javadoc
1   /*
2    * Copyright (C) 2016 eXo Platform SAS.
3    *
4    * This is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU Lesser General Public License as
6    * published by the Free Software Foundation; either version 2.1 of
7    * the License, or (at your option) any later version.
8    *
9    * This software is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this software; if not, write to the Free
16   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18   */
19  package org.exoplatform.commons.file.services.checker;
20  
21  import org.exoplatform.commons.file.model.FileInfo;
22  import org.exoplatform.commons.file.resource.BinaryProvider;
23  import org.exoplatform.commons.file.services.job.FileStorageCleanJob;
24  import org.exoplatform.commons.file.storage.DataStorage;
25  import org.exoplatform.commons.utils.PropertyManager;
26  import org.exoplatform.commons.utils.SecurityHelper;
27  import org.exoplatform.services.log.ExoLogger;
28  import org.exoplatform.services.log.Log;
29  import org.picocontainer.Startable;
30  import org.exoplatform.management.annotations.Managed;
31  import org.exoplatform.management.annotations.ManagedDescription;
32  import org.exoplatform.management.jmx.annotations.NameTemplate;
33  import org.exoplatform.management.jmx.annotations.Property;
34  
35  import java.io.*;
36  import java.security.PrivilegedAction;
37  import java.security.PrivilegedExceptionAction;
38  import java.text.SimpleDateFormat;
39  import java.util.Date;
40  import java.util.List;
41  
42  /**
43   * File Storage Check Controller allows check file Storage consistency: Created
44   * by The eXo Platform SAS Author : eXoPlatform exo@exoplatform.com
45   */
46  @Managed
47  @NameTemplate(@Property(key = "service", value = "FileStorageCheckController"))
48  @ManagedDescription("File Storage Check consistency")
49  public class FileStorageCheckController implements Startable {
50    protected static Log       LOG                           = ExoLogger.getLogger(FileStorageCheckController.class);
51  
52    public static final String REPORT_CONSISTENT_MESSAGE     = "File Storage data is consistent";
53  
54    public static final String REPORT_NOT_CONSISTENT_MESSAGE = "File Storage data is NOT consistent";
55  
56    private static final int   pageSize                      = 20;
57  
58    private BinaryProvider     binaryProvider;
59  
60    private DataStorage        dataStorage;
61  
62    public FileStorageCheckController(DataStorage dataStorage, BinaryProvider resourceProvider) {
63      this.dataStorage = dataStorage;
64      this.binaryProvider = resourceProvider;
65    }
66  
67    @Managed
68    @ManagedDescription("Check File Storage consistency. ")
69    public String checkFileStorage() {
70      boolean defaultState = FileStorageCleanJob.isEnabled().get();
71      ;
72      try {
73        Report report = new Report();
74        if (FileStorageCleanJob.isEnabled().get()) {
75          FileStorageCleanJob.setEnabled(false);
76        }
77        SecurityHelper.doPrivilegedAction(new PrivilegedAction<Boolean>() {
78          public Boolean run() {
79            try {
80              LOG.info("Start File Storage Check Consistency");
81              boolean isConsistent = true;
82              int offset = 0;
83              boolean hasNext = true;
84              while (hasNext) {
85                List<FileInfo> list = dataStorage.getAllFilesInfo(offset, pageSize);
86  
87                if (list == null || list.isEmpty()) {
88                  break;
89                }
90                if (list.size() < pageSize) {
91                  hasNext = false;
92                }
93                for (FileInfo fileInfo : list) {
94                  String checksum = fileInfo.getChecksum();
95                  if (checksum != null && !checksum.isEmpty()) {
96                    if (!binaryProvider.exists(checksum)) {
97                      isConsistent = false;
98                      report.writeLine("File not exist in file storage File ID : " + fileInfo.getId() + " File name : "
99                          + fileInfo.getName() + " , Path : " + binaryProvider.getFilePath(fileInfo.getChecksum()));
100                   }
101                 } else {
102                   isConsistent = false;
103                   report.writeLine("File metaData with empty checksum File ID : " + fileInfo.getId() + " File name : "
104                       + fileInfo.getName() + " , Path : ");
105                 }
106               }
107               offset += pageSize;
108             }
109             if (isConsistent) {
110               report.writeLine(REPORT_CONSISTENT_MESSAGE);
111               LOG.info("Finish File Storage Check Consistency : " + REPORT_CONSISTENT_MESSAGE);
112             } else {
113               report.writeLine(REPORT_NOT_CONSISTENT_MESSAGE);
114               LOG.info("Finish File Storage Check Consistency : " + REPORT_NOT_CONSISTENT_MESSAGE);
115             }
116           } catch (Exception e) {
117             try {
118               report.writeLine("Processing File Storage Check Consistency Error ");
119               report.writeStackTrace(e);
120             } catch (IOException e1) {
121               LOG.error(e1.getMessage());
122             }
123             LOG.error(e.getMessage());
124           }
125           return true;
126         }
127       });
128     } catch (Exception ex) {
129       LOG.error(ex.getMessage());
130       return "Failed Operation";
131     } finally {
132       FileStorageCleanJob.setEnabled(defaultState);
133     }
134     return "Success Operation";
135   }
136 
137   @Managed
138   @ManagedDescription("Check File Storage consistency. ")
139   public String RepairFileStorage() {
140     try {
141       // TODO Repair file Storage data
142     } catch (Exception ex) {
143       LOG.error(ex.getMessage());
144       return "Failed";
145     }
146     return "Unsupported Operation";
147   }
148 
149   @Override
150   public void start() {
151 
152   }
153 
154   @Override
155   public void stop() {
156 
157   }
158 
159   private class Report {
160     private static final String DELIMITER = "\n";
161 
162     private Writer              writer;
163 
164     private String              reportPath;
165 
166     public Report() throws IOException {
167       String reportPathRoot = PropertyManager.getProperty("java.io.tmpdir");
168       final File reportFile = new File(reportPathRoot,
169                                        "report-filesStorage-" + new SimpleDateFormat("dd-MMM-yy-HH-mm").format(new Date())
170                                            + ".txt");
171 
172       SecurityHelper.doPrivilegedIOExceptionAction(new PrivilegedExceptionAction<Void>() {
173         public Void run() throws IOException {
174           reportPath = reportFile.getAbsolutePath();
175           writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(reportPath)));
176 
177           return null;
178         }
179       });
180 
181     }
182 
183     private void writeLine(String message) throws IOException {
184       writer.write(message);
185       writer.write(DELIMITER);
186       writer.flush();
187     }
188 
189     private void writeStackTrace(Throwable e) throws IOException {
190       writeLine(e.getMessage());
191       writeLine(e.toString());
192       StackTraceElement[] trace = e.getStackTrace();
193       for (int i = 0; i < trace.length; i++) {
194         writeLine("\tat " + trace[i]);
195       }
196 
197       Throwable ourCause = e.getCause();
198       if (ourCause != null) {
199         writeLine("Cause:");
200         writeStackTrace(ourCause);
201       }
202     }
203 
204   }
205 }