/* * Copyright 2015 JBoss, by Red Hat, Inc * * 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 org.uberfire.ext.metadata.io; import java.util.concurrent.atomic.AtomicBoolean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.uberfire.commons.async.DescriptiveRunnable; import org.uberfire.commons.async.SimpleAsyncExecutorService; import org.uberfire.ext.metadata.engine.Indexer; import org.uberfire.ext.metadata.engine.MetaIndexEngine; import org.uberfire.ext.metadata.engine.Observer; import org.uberfire.ext.metadata.model.KCluster; import org.uberfire.ext.metadata.model.KObject; import org.uberfire.io.IOService; import org.uberfire.java.nio.IOException; import org.uberfire.java.nio.base.FileSystemId; import org.uberfire.java.nio.file.FileSystem; import org.uberfire.java.nio.file.FileVisitResult; import org.uberfire.java.nio.file.Path; import org.uberfire.java.nio.file.SimpleFileVisitor; import org.uberfire.java.nio.file.attribute.BasicFileAttributes; import org.uberfire.java.nio.file.attribute.FileAttribute; import org.uberfire.java.nio.file.attribute.FileAttributeView; import static org.uberfire.commons.validation.PortablePreconditions.checkNotNull; import static org.uberfire.java.nio.file.Files.walkFileTree; /** * */ public final class BatchIndex { private static final Logger LOG = LoggerFactory.getLogger(BatchIndex.class); private final MetaIndexEngine indexEngine; private final IOService ioService; private final Class<? extends FileAttributeView>[] views; private final AtomicBoolean indexDisposed = new AtomicBoolean(false); private final Observer observer; public BatchIndex(final MetaIndexEngine indexEngine, final IOService ioService, final Observer observer, final Class<? extends FileAttributeView>... views) { this.indexEngine = checkNotNull("indexEngine", indexEngine); this.ioService = checkNotNull("ioService", ioService); this.observer = checkNotNull("observer", observer); this.views = views; } public void runAsync(final FileSystem fs) { if (fs != null && fs.getRootDirectories().iterator().hasNext()) { SimpleAsyncExecutorService.getDefaultInstance().execute(new DescriptiveRunnable() { @Override public String getDescription() { return "FS BatchIndex [" + ((FileSystemId) fs).id() + "]"; } @Override public void run() { final AtomicBoolean indexFinished = new AtomicBoolean(false); indexEngine.beforeDispose(new Runnable() { @Override public void run() { indexDisposed.set(true); if (!indexFinished.get()) { indexEngine.delete(KObjectUtil.toKCluster(fs)); } } }); try { for (final Path root : fs.getRootDirectories()) { BatchIndex.this.run(root); } indexFinished.set(true); } catch (Exception ex) { if (!indexDisposed.get()) { logError("FileSystem Index fails. [@" + fs.toString() + "]", ex); } } } }); } } public void runAsync(final Path root) { SimpleAsyncExecutorService.getDefaultInstance().execute(new DescriptiveRunnable() { @Override public String getDescription() { return "Path BatchIndex [" + root.toString() + "]"; } @Override public void run() { BatchIndex.this.run(root); } }); } public void run(final Path root) { run(root, null); } public void run(final Path root, final Runnable callback) { try { if (root == null) { return; } logInformation("Starting indexing of " + root.toUri() + " ..."); final KCluster cluster = KObjectUtil.toKCluster(root.getFileSystem()); walkFileTree(checkNotNull("root", root), new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { if (indexDisposed.get()) { return FileVisitResult.TERMINATE; } try { checkNotNull("file", file); checkNotNull("attrs", attrs); if (!file.getFileName().toString().startsWith(".")) { LOG.debug("Indexing " + file.toUri()); //Default indexing for (final Class<? extends FileAttributeView> view : views) { ioService.getFileAttributeView(file, view); } final FileAttribute<?>[] allAttrs = ioService.convert(ioService.readAttributes(file)); if (!indexDisposed.get()) { indexEngine.index(KObjectUtil.toKObject(file, allAttrs)); } else { return FileVisitResult.TERMINATE; } //Additional indexing for (Indexer indexer : IndexersFactory.getIndexers()) { if (file.getFileSystem().isOpen()) { if (indexer.supportsPath(file)) { final KObject kObject = indexer.toKObject(file); if (kObject != null) { if (!indexDisposed.get()) { indexEngine.index(kObject); } else { return FileVisitResult.TERMINATE; } } } } } } } catch (final Exception ex) { if (indexDisposed.get()) { logWarning("Batch index couldn't finish. [@" + root.toUri().toString() + "]"); return FileVisitResult.TERMINATE; } else { logError("Index fails. [@" + file.toString() + "]", ex); } } if (indexDisposed.get()) { return FileVisitResult.TERMINATE; } return FileVisitResult.CONTINUE; } }); if (!indexDisposed.get()) { logInformation("Completed indexing of " + root.toUri()); indexEngine.commit(cluster); if (callback != null) { callback.run(); } } else { logWarning("Batch index couldn't finish. [@" + root.toUri().toString() + "]"); } } catch (final IllegalStateException ex) { if (indexDisposed.get()) { logWarning("Batch index couldn't finish. [@" + root.toUri().toString() + "]"); } else { logError("Index fails - Index has an invalid state. [@" + root.toUri().toString() + "]", ex); } } catch (final Exception ex) { if (indexDisposed.get()) { logWarning("Batch index couldn't finish. [@" + root.toUri().toString() + "]"); } else { logError("Index fails. [@" + root.toUri().toString() + "]", ex); } } } private void logInformation(final String message) { observer.information(message); LOG.info(message); } private void logWarning(final String message) { observer.warning(message); LOG.warn(message); } private void logError(final String message, final Throwable throwable) { observer.error(message); LOG.error(message, throwable); } public void dispose() { indexEngine.dispose(); } }