blob: d8192243229f74f57d9adc79d6d4ba74d6b94cff [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2017 xored software, Inc.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.core.search.indexing.core;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.dltk.compiler.CharOperation;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IDLTKLanguageToolkit;
import org.eclipse.dltk.core.IExternalSourceModule;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModelElementVisitor;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.environment.EnvironmentManager;
import org.eclipse.dltk.core.environment.EnvironmentPathUtils;
import org.eclipse.dltk.core.environment.IEnvironment;
import org.eclipse.dltk.core.environment.IFileHandle;
import org.eclipse.dltk.core.search.index.Index;
import org.eclipse.dltk.core.search.indexing.IIndexConstants;
import org.eclipse.dltk.core.search.indexing.IProjectIndexer;
import org.eclipse.dltk.core.search.indexing.ReadWriteMonitor;
import org.eclipse.dltk.internal.core.BuiltinSourceModule;
public class ArchiveProjectFragmentRequest extends IndexRequest {
protected final IProjectFragment fragment;
protected final IDLTKLanguageToolkit toolkit;
public ArchiveProjectFragmentRequest(IProjectIndexer indexer,
IProjectFragment fragment, IDLTKLanguageToolkit toolkit) {
super(indexer);
this.fragment = fragment;
this.toolkit = toolkit;
}
@Override
protected String getName() {
return fragment.getElementName();
}
@Override
protected void run() throws CoreException, IOException {
IEnvironment environment = EnvironmentManager
.getEnvironment(fragment.getScriptProject());
if (environment == null || !environment.connect()) {
return;
}
final Set<ISourceModule> modules = getExternalSourceModules();
final Index index = getIndexer().getProjectFragmentIndex(fragment);
if (index == null) {
return;
}
final IFileHandle archive = EnvironmentPathUtils
.getFile(fragment.getPath());
if (archive == null) {
return;
}
final String signature = archive.lastModified() + "#"
+ archive.length();
final IPath containerPath = fragment.getPath();
final List<Object> changes = checkChanges(index, modules, containerPath,
signature);
if (DEBUG) {
log("changes.size=" + changes.size()); //$NON-NLS-1$
}
if (changes.isEmpty()) {
return;
}
final ReadWriteMonitor imon = index.monitor;
imon.enterWrite();
try {
index.separator = Index.JAR_SEPARATOR;
index.addIndexEntry(IIndexConstants.STAMP, CharOperation.NO_CHAR,
SIGNATURE_PREFIX + signature);
for (Iterator<Object> i = changes.iterator(); !isCancelled
&& i.hasNext();) {
final Object change = i.next();
if (change instanceof String) {
index.remove((String) change);
} else if (change instanceof ISourceModule) {
ISourceModule module = (ISourceModule) change;
getIndexer().indexSourceModule(index, toolkit, module,
containerPath);
}
}
} catch (Throwable e) {
e.printStackTrace();
} finally {
try {
index.save();
} catch (IOException e) {
DLTKCore.error("error saving index", e); //$NON-NLS-1$
} finally {
imon.exitWrite();
}
}
}
// TODO (alex) use content cache for it probably
private static final String SIGNATURE_PREFIX = "###.LIBRARY.###.SIGNATURE.###";
protected List<Object> checkChanges(Index index,
Collection<ISourceModule> modules, IPath containerPath,
String signature) throws ModelException, IOException {
final String[] documents = queryDocumentNames(index);
if (documents != null && documents.length != 0) {
final List<Object> changes = new ArrayList<>();
final Map<String, ISourceModule> m = collectSourceModulePaths(
modules, containerPath);
if (DEBUG) {
log("documents.length=" + documents.length); //$NON-NLS-1$
log("modules.size=" + modules.size()); //$NON-NLS-1$
log("map.size=" + m.size()); //$NON-NLS-1$
}
boolean signatureOK = false;
final List<ISourceModule> updates = new ArrayList<>();
for (int i = 0; i < documents.length; ++i) {
final String document = documents[i];
if (document.startsWith(SIGNATURE_PREFIX)) {
signatureOK = document.substring(SIGNATURE_PREFIX.length())
.equals(signature);
if (!signatureOK) {
changes.add(document);
}
} else {
final ISourceModule module = m.remove(document);
if (module == null) {
changes.add(document);
} else {
updates.add(module);
}
}
}
if (!signatureOK) {
changes.addAll(updates);
}
if (!m.isEmpty()) {
changes.addAll(m.values());
}
return changes;
} else {
return new ArrayList<>(modules);
}
}
static class ExternalModuleVisitor implements IModelElementVisitor {
final Set<ISourceModule> modules = new HashSet<>();
@Override
public boolean visit(IModelElement element) {
if (element.getElementType() == IModelElement.SOURCE_MODULE) {
if (element instanceof IExternalSourceModule
|| element instanceof BuiltinSourceModule
|| ((ISourceModule) element).isBinary()) {
modules.add((ISourceModule) element);
}
return false;
}
return true;
}
}
private Set<ISourceModule> getExternalSourceModules()
throws ModelException {
final ExternalModuleVisitor visitor = new ExternalModuleVisitor();
fragment.accept(visitor);
return visitor.modules;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((fragment == null) ? 0 : fragment.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
ArchiveProjectFragmentRequest other = (ArchiveProjectFragmentRequest) obj;
if (fragment == null) {
if (other.fragment != null)
return false;
} else if (!fragment.equals(other.fragment))
return false;
return true;
}
}