Java tutorial
/* * Copyright 2014 Carsten Rambow, elomagic. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.elomagic.carafile.client; import java.io.IOException; import java.io.InputStreamReader; import java.net.URI; import java.nio.charset.Charset; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.nio.file.attribute.BasicFileAttributes; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.prefs.Preferences; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.fluent.Request; import org.apache.http.entity.ContentType; import org.apache.log4j.Logger; import de.elomagic.carafile.share.CloudFileData; import de.elomagic.carafile.share.FileChangesList; import de.elomagic.carafile.share.JsonUtil; import de.elomagic.carafile.share.MetaData; /** * */ public class CaraCloud { private static final Logger LOG = Logger.getLogger(CaraCloud.class); private CaraFileClient client; private Path basePath; private WatchService watcher; private long lastMillis; /** * Set the client for core service communictations. * * @param client The {@link CaraFileClient} * @return Returns itself */ public CaraCloud setClient(final CaraFileClient client) { this.client = client; return this; } /** * Set the to be sychronized folder * * @param basePath The path * @return Returns itself */ public CaraCloud setBasePath(final Path basePath) { this.basePath = basePath; return this; } /** * Starts synchronization of the given base path with the registry. * <p/> * This method will block till call method {@link CaraCloud#stop() } * * @throws IOException Thrown when an I/O error occurs * @throws InterruptedException Thrown when method stop was called or application will terminate * @throws GeneralSecurityException */ public void start() throws IOException, InterruptedException, GeneralSecurityException { if (client == null) { throw new IllegalStateException("Attribute \"client\" must be set."); } if (basePath == null) { throw new IllegalStateException("Attribute \"basePath\" must be set."); } if (!Files.exists(basePath)) { throw new IllegalStateException("Path \"" + basePath + "\" must exists."); } if (!Files.isDirectory(basePath)) { throw new IllegalStateException("Path \"" + basePath + "\" must be a directory/folder."); } watcher = FileSystems.getDefault().newWatchService(); registerDefaultWatch(basePath); while (!Thread.interrupted()) { WatchKey key = watcher.take(); for (WatchEvent<?> event : key.pollEvents()) { if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { Path path = basePath.resolve(event.context().toString()); createFile(path); } else if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) { } else if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) { Path path = basePath.resolve(event.context().toString()); deleteFile(path); } else { LOG.error("Unsupported kind: " + event.kind() + ", path: " + event.context()); } } key.reset(); } } /** * Stops watching the base path on any kind of changes. * * @throws IOException Thrown when an I/O error occurs */ public void stop() throws IOException { if (watcher == null) { return; } watcher.close(); } public Set<CloudFileData> list(final Path remotePath) throws IOException { LOG.debug("List remote folder \"" + remotePath + "\" file at " + client.getRegistryURI()); URI uri = CaraFileUtils.buildURI(client.getRegistryURI(), "cloud", "list", remotePath.toString()); HttpResponse response = client.executeRequest(Request.Get(uri)).returnResponse(); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new IOException("HTTP responce code " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()); } Charset charset = ContentType.getOrDefault(response.getEntity()).getCharset(); Set<CloudFileData> set = JsonUtil.read(new InputStreamReader(response.getEntity().getContent(), charset), Set.class); LOG.debug("Folder contains " + set.size() + " item(s)"); return set; } private void createFile(final Path path) throws IOException, GeneralSecurityException { LOG.debug("Creating file \"" + path + "\" file at " + client.getRegistryURI()); URI uri; if (Files.isDirectory(path)) { registerDefaultWatch(path); uri = CaraFileUtils.buildURI(client.getRegistryURI(), "cloud", "create", getSubPath(path)); } else { MetaData md = client.uploadFile(path, path.getFileName().toString()); uri = CaraFileUtils.buildURI(client.getRegistryURI(), "cloud", "create", getSubPath(path), md.getId()); } HttpResponse response = client.executeRequest(Request.Post(uri)).returnResponse(); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new IOException(); } } private void deleteFile(final Path path) throws IOException { LOG.debug("Deleting file \"" + path + "\" file at " + client.getRegistryURI()); URI uri = CaraFileUtils.buildURI(client.getRegistryURI(), "cloud", "delete", getSubPath(path)); HttpResponse response = client.executeRequest(Request.Delete(uri)).returnResponse(); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new IOException(); } MetaData md = client.getMetaDataFromResponse(response); client.deleteFile(md.getId(), true); } private void syncFolder() { } private FileChangesList getRemoteChangeList(long lastMillis) throws IOException { URI uri = CaraFileUtils.buildURI(client.getRegistryURI(), "cloud", "changes", Long.toString(lastMillis)); HttpResponse response = client.executeRequest(Request.Get(uri)).returnResponse(); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new IOException("HTTP responce code " + response.getStatusLine().getStatusCode() + " " + response.getStatusLine().getReasonPhrase()); } Charset charset = ContentType.getOrDefault(response.getEntity()).getCharset(); FileChangesList changeList = JsonUtil .read(new InputStreamReader(response.getEntity().getContent(), charset), FileChangesList.class); LOG.debug("Folder contains " + changeList.getChangeList() + " item(s)"); return changeList; } private List<Path> checkLocalFolder(final Path basePath) throws IOException { Preferences preferences = Preferences.systemNodeForPackage(getClass()); final long lastScanMillis = preferences.getLong("lastScan", 0); final List<Path> changedPathList = getLocalChangeList(basePath, lastScanMillis); for (Path path : basePath) { // xxx } return changedPathList; } private List<Path> getLocalChangeList(final Path basePath, final long lastScanMillis) throws IOException { if (Files.notExists(basePath)) { return Collections.EMPTY_LIST; } final List<Path> changedPathList = new ArrayList(); Files.walkFileTree(basePath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { if (attrs.lastModifiedTime().toMillis() > lastScanMillis) { changedPathList.add(dir); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (attrs.lastModifiedTime().toMillis() > lastScanMillis) { changedPathList.add(file); } return FileVisitResult.CONTINUE; } }); return changedPathList; } private void registerDefaultWatch(final Path path) throws IOException { path.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE); } String getSubPath(final Path path) { Path p = path.subpath(basePath.getNameCount(), path.getNameCount()); return p.toString().replace("\\", "/"); } }