SyncedFolderObserverService.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /**
  2. * Nextcloud Android client application
  3. *
  4. * @author Tobias Kaminsky
  5. * @author Andy Scherzinger
  6. * @author Mario Danic
  7. * Copyright (C) 2016 Tobias Kaminsky, Andy Scherzinger
  8. * Copyright (C) 2017 Mario Danic
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. package com.owncloud.android.services.observer;
  24. import android.app.Service;
  25. import android.content.Intent;
  26. import android.os.Binder;
  27. import android.os.IBinder;
  28. import com.owncloud.android.MainApp;
  29. import com.owncloud.android.datamodel.SerializablePair;
  30. import com.owncloud.android.datamodel.SyncedFolder;
  31. import com.owncloud.android.datamodel.SyncedFolderProvider;
  32. import com.owncloud.android.lib.common.utils.Log_OC;
  33. import com.owncloud.android.services.FileAlterationMagicListener;
  34. import org.apache.commons.io.FileUtils;
  35. import org.apache.commons.io.monitor.FileAlterationMonitor;
  36. import org.apache.commons.io.monitor.FileEntry;
  37. import java.io.File;
  38. import java.io.FileFilter;
  39. import java.io.FileInputStream;
  40. import java.io.FileNotFoundException;
  41. import java.io.FileOutputStream;
  42. import java.io.IOException;
  43. import java.io.ObjectInputStream;
  44. import java.io.ObjectOutputStream;
  45. import java.util.HashMap;
  46. import java.util.concurrent.CopyOnWriteArrayList;
  47. public class SyncedFolderObserverService extends Service {
  48. private static final String TAG = "SyncedFolderObserverService";
  49. private SyncedFolderProvider mProvider;
  50. private HashMap<SyncedFolder, FileAlterationMagicObserver> syncedFolderMap = new HashMap<>();
  51. private final IBinder mBinder = new SyncedFolderObserverBinder();
  52. private FileAlterationMonitor monitor;
  53. private FileFilter fileFilter;
  54. private CopyOnWriteArrayList<SerializablePair<SyncedFolder, FileEntry>> pairArrayList = new CopyOnWriteArrayList<>();
  55. private File file;
  56. @Override
  57. public void onCreate() {
  58. mProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver());
  59. }
  60. @Override
  61. public int onStartCommand(Intent intent, int flags, int startId) {
  62. monitor = new FileAlterationMonitor();
  63. fileFilter = new FileFilter() {
  64. @Override
  65. public boolean accept(File pathname) {
  66. return !pathname.getName().startsWith(".") && !pathname.getName().endsWith(".tmp");
  67. }
  68. };
  69. file = new File(MainApp.getAppContext().getExternalFilesDir(null).getAbsolutePath() + File.separator +
  70. "nc_persistence");
  71. boolean readPerstistanceEntries = false;
  72. if (file.exists() ) {
  73. FileInputStream fis = null;
  74. try {
  75. fis = new FileInputStream(file);
  76. ObjectInputStream ois = new ObjectInputStream(fis);
  77. boolean cont = true;
  78. while(cont){
  79. Object obj = ois.readObject();
  80. if(obj != null)
  81. pairArrayList.add((SerializablePair<SyncedFolder, FileEntry>) obj);
  82. else
  83. cont = false;
  84. }
  85. readPerstistanceEntries = true;
  86. } catch (FileNotFoundException e) {
  87. Log_OC.d(TAG, "Failed with FileNotFound while reading persistence file");
  88. } catch (IOException e) {
  89. Log_OC.d(TAG, "Failed with IOException while reading persistence file");
  90. } catch (ClassNotFoundException e) {
  91. Log_OC.d(TAG, "Failed with ClassNotFound while reading persistence file");
  92. } finally {
  93. try {
  94. if (fis != null) {
  95. fis.close();
  96. }
  97. } catch (IOException e) {
  98. Log_OC.d(TAG, "Failed with closing FIS");
  99. }
  100. }
  101. }
  102. Log_OC.d(TAG, "start");
  103. if (pairArrayList.size() == 0) {
  104. for (SyncedFolder syncedFolder : mProvider.getSyncedFolders()) {
  105. if (syncedFolder.isEnabled() && !syncedFolderMap.containsKey(syncedFolder.getLocalPath())) {
  106. Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath());
  107. FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File(
  108. syncedFolder.getLocalPath()), fileFilter);
  109. try {
  110. observer.init();
  111. SerializablePair<SyncedFolder, FileEntry> pair = new SerializablePair<>(syncedFolder,
  112. observer.getRootEntry());
  113. pairArrayList.add(pair);
  114. } catch (Exception e) {
  115. Log_OC.d(TAG, "Failed getting an observer to intialize");
  116. }
  117. observer.addListener(new FileAlterationMagicListener(syncedFolder));
  118. monitor.addObserver(observer);
  119. syncedFolderMap.put(syncedFolder, observer);
  120. }
  121. }
  122. } else {
  123. for(int i = 0; i < pairArrayList.size(); i++) {
  124. SyncedFolder syncFolder = pairArrayList.get(i).getKey();
  125. FileAlterationMagicObserver observer = new FileAlterationMagicObserver(new File(
  126. syncFolder.getLocalPath()), fileFilter);
  127. observer.setRootEntry(pairArrayList.get(i).getValue());
  128. observer.addListener(new FileAlterationMagicListener(syncFolder));
  129. monitor.addObserver(observer);
  130. syncedFolderMap.put(syncFolder, observer);
  131. }
  132. }
  133. writePersistenceEntries(readPerstistanceEntries, file);
  134. try {
  135. monitor.start();
  136. } catch (Exception e) {
  137. Log_OC.d(TAG, "Something went very wrong at onStartCommand");
  138. }
  139. return Service.START_NOT_STICKY;
  140. }
  141. private void writePersistenceEntries(boolean readPerstistanceEntries, File file) {
  142. FileOutputStream fos = null;
  143. try {
  144. if (pairArrayList.size() > 0 && !readPerstistanceEntries) {
  145. File newFile = new File(file.getAbsolutePath());
  146. if (!newFile.exists()) {
  147. newFile.createNewFile();
  148. }
  149. fos = new FileOutputStream (new File(file.getAbsolutePath()), false);
  150. ObjectOutputStream os = new ObjectOutputStream(fos);
  151. for (int i = 0; i < pairArrayList.size(); i++) {
  152. os.writeObject(pairArrayList.get(i));
  153. }
  154. os.close();
  155. } else if (file.exists() && pairArrayList.size() == 0) {
  156. FileUtils.deleteQuietly(file);
  157. }
  158. if (fos != null) {
  159. fos.close();
  160. }
  161. } catch (FileNotFoundException e) {
  162. Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via FileNotFound");
  163. } catch (IOException e) {
  164. Log_OC.d(TAG, "Failed writing to nc_sync_persistance file via IOException");
  165. }
  166. }
  167. @Override
  168. public void onDestroy() {
  169. for (SyncedFolder syncedFolder : syncedFolderMap.keySet()) {
  170. FileAlterationMagicObserver obs = syncedFolderMap.get(syncedFolder);
  171. for (int i = 0; i < pairArrayList.size(); i++) {
  172. SyncedFolder pairSyncedFolder = pairArrayList.get(i).getKey();
  173. if (pairSyncedFolder.equals(syncedFolder)) {
  174. SerializablePair<SyncedFolder, FileEntry> newPairEntry = new SerializablePair<>(syncedFolder,
  175. obs.getRootEntry());
  176. pairArrayList.set(i, newPairEntry);
  177. break;
  178. }
  179. }
  180. monitor.removeObserver(obs);
  181. syncedFolderMap.remove(obs);
  182. try {
  183. obs.destroy();
  184. } catch (Exception e) {
  185. Log_OC.d(TAG, "Something went very wrong at onDestroy");
  186. }
  187. }
  188. writePersistenceEntries(false, file);
  189. }
  190. /**
  191. * Restart oberver if it is enabled
  192. * If syncedFolder exists already, use it, otherwise create new observer
  193. *
  194. * @param syncedFolder
  195. */
  196. public void restartObserver(SyncedFolder syncedFolder) {
  197. FileAlterationMagicObserver fileAlterationObserver;
  198. if (syncedFolderMap.containsKey(syncedFolder)) {
  199. Log_OC.d(TAG, "stop observer: " + syncedFolder.getLocalPath());
  200. fileAlterationObserver = syncedFolderMap.get(syncedFolder);
  201. monitor.removeObserver(fileAlterationObserver);
  202. try {
  203. fileAlterationObserver.destroy();
  204. } catch (Exception e) {
  205. Log_OC.d(TAG, "Something went very wrong at onDestroy");
  206. }
  207. // remove it from the paired array list
  208. for (int i = 0; i < pairArrayList.size(); i++) {
  209. if (syncedFolder.equals(pairArrayList.get(i).getKey())) {
  210. pairArrayList.remove(i);
  211. break;
  212. }
  213. }
  214. syncedFolderMap.remove(syncedFolder);
  215. }
  216. if (syncedFolder.isEnabled()) {
  217. Log_OC.d(TAG, "start observer: " + syncedFolder.getLocalPath());
  218. if (syncedFolderMap.containsKey(syncedFolder)) {
  219. fileAlterationObserver = syncedFolderMap.get(syncedFolder);
  220. if (fileAlterationObserver.getListeners() == null) {
  221. fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder));
  222. }
  223. monitor.addObserver(fileAlterationObserver);
  224. } else {
  225. fileAlterationObserver = new FileAlterationMagicObserver(new File(syncedFolder.getLocalPath()),
  226. fileFilter);
  227. try {
  228. fileAlterationObserver.init();
  229. SerializablePair<SyncedFolder, FileEntry> pair = new SerializablePair<>(syncedFolder,
  230. fileAlterationObserver.getRootEntry());
  231. pairArrayList.add(pair);
  232. } catch (Exception e) {
  233. Log_OC.d(TAG, "Failed getting an observer to intialize");
  234. }
  235. fileAlterationObserver.addListener(new FileAlterationMagicListener(syncedFolder));
  236. monitor.addObserver(fileAlterationObserver);
  237. try {
  238. syncedFolderMap.put(syncedFolder, fileAlterationObserver);
  239. } catch (Exception e) {
  240. Log_OC.d(TAG, "Something went very wrong on RestartObserver");
  241. }
  242. }
  243. }
  244. writePersistenceEntries(false, file);
  245. }
  246. @Override
  247. public IBinder onBind(Intent arg0) {
  248. return mBinder;
  249. }
  250. public class SyncedFolderObserverBinder extends Binder {
  251. public SyncedFolderObserverService getService() {
  252. return SyncedFolderObserverService.this;
  253. }
  254. }
  255. }