blob: 24944fb37653b073b574cb9c58332e91abb2d6e1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2021 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* SAP AG - initial API and implementation
* IBM Corporation - validation of indices
*******************************************************************************/
package org.eclipse.mat.parser.internal;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.collect.HashMapIntObject;
import org.eclipse.mat.collect.IteratorInt;
import org.eclipse.mat.parser.IIndexBuilder;
import org.eclipse.mat.parser.internal.oql.OQLQueryImpl;
import org.eclipse.mat.parser.internal.util.ParserRegistry;
import org.eclipse.mat.parser.internal.util.ParserRegistry.Parser;
import org.eclipse.mat.parser.model.ClassImpl;
import org.eclipse.mat.parser.model.XGCRootInfo;
import org.eclipse.mat.parser.model.XSnapshotInfo;
import org.eclipse.mat.snapshot.IOQLQuery;
import org.eclipse.mat.snapshot.ISnapshot;
import org.eclipse.mat.snapshot.SnapshotFactory;
import org.eclipse.mat.snapshot.SnapshotFormat;
import org.eclipse.mat.snapshot.model.GCRootInfo;
import org.eclipse.mat.util.IProgressListener;
import org.eclipse.mat.util.IProgressListener.Severity;
import org.eclipse.mat.util.MessageUtil;
public class SnapshotFactoryImpl implements SnapshotFactory.Implementation
{
private static class SnapshotEntry
{
private int usageCount;
private WeakReference<ISnapshot> snapshot;
public SnapshotEntry(int usageCount, ISnapshot snapshot)
{
this.usageCount = usageCount;
this.snapshot = new WeakReference<ISnapshot>(snapshot);
}
}
private Map<File, SnapshotEntry> snapshotCache = new HashMap<File, SnapshotEntry>();
public ISnapshot openSnapshot(File file, Map<String, String> args, IProgressListener listener) throws SnapshotException
{
ISnapshot answer = null;
// lookup in cache
SnapshotEntry entry = snapshotCache.get(file);
if (entry != null)
{
answer = entry.snapshot.get();
if (answer != null)
{
entry.usageCount++;
return answer;
}
}
String name = file.getName();
/*
* Perhaps there are extensions with dots, e.g. .phd.gz or .hprof.gz,
* so this code ensures the whole extension is removed.
*/
IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
IContentType javaheapdump = contentTypeManager.getContentType("org.eclipse.mat.JavaHeapDump"); //$NON-NLS-1$
List<IContentType>listtypes = new ArrayList<IContentType>();
if (javaheapdump != null)
{
String n1 = name;
IContentType types[];
try (FileInputStream fis = new FileInputStream(file))
{
types = contentTypeManager.findContentTypesFor(fis, file.getPath());
if (types.length == 0)
{
try (FileInputStream fis2 = new FileInputStream(file))
{
types = contentTypeManager.findContentTypesFor(fis2, null);
}
}
}
catch (IOException e)
{
// Ignore, try using file name alone
types = contentTypeManager.findContentTypesFor(file.getPath());
}
for (IContentType tp : types)
{
if (tp.isKindOf(javaheapdump))
{
// See if this content description is based on the file contents
IContentDescription cd1, cd2;
try (FileInputStream fis = new FileInputStream(file))
{
// Succeeds if based on context
cd1 = tp.getDescriptionFor(fis, IContentDescription.ALL);
}
catch (IOException e)
{
cd1 = null;
}
try (InputStream sr = new ByteArrayInputStream(new byte[10]))
{
// Succeeds if generic type without content checking
cd2 = tp.getDescriptionFor(sr, IContentDescription.ALL);
}
catch (IOException e)
{
cd2 = null;
}
if (cd1 != null && cd2 == null)
listtypes.add(tp);
for (String ext: tp.getFileSpecs(IContentType.FILE_EXTENSION_SPEC))
{
// Does extension itself contains a dot, and matches this file ?
if (ext.indexOf('.') >= 0 && name.endsWith("." + ext)) //$NON-NLS-1$
{
// It has a dot, so remove
n1 = name.substring(0, name.length() - ext.length());
}
}
}
}
name = n1;
}
int p = name.lastIndexOf('.');
name = p >= 0 ? name.substring(0, p + 1) : name + ".";//$NON-NLS-1$
String prefix = new File(file.getParentFile(), name).getAbsolutePath();
String snapshot_identifier = args.get("snapshot_identifier"); //$NON-NLS-1$
if (snapshot_identifier != null)
{
prefix += snapshot_identifier + "."; //$NON-NLS-1$
}
try
{
File indexFile = new File(prefix + "index");//$NON-NLS-1$
if (indexFile.exists())
{
// check if hprof file is newer than index file
if (file.lastModified() <= indexFile.lastModified())
{
answer = SnapshotImpl.readFromFile(file, prefix, listener);
}
else
{
String message = MessageUtil.format(Messages.SnapshotFactoryImpl_ReparsingHeapDumpAsIndexOutOfDate,
file.getPath(), new Date(file.lastModified()),
indexFile.getPath(), new Date(indexFile.lastModified()));
listener.sendUserMessage(Severity.INFO, message, null);
listener.subTask(Messages.SnapshotFactoryImpl_ReparsingHeapDumpWithOutOfDateIndex);
}
}
}
catch (IOException ignore_and_reparse)
{
String text = ignore_and_reparse.getMessage() != null ? ignore_and_reparse.getMessage()
: ignore_and_reparse.getClass().getName();
String message = MessageUtil.format(Messages.SnapshotFactoryImpl_Error_ReparsingHeapDump, text);
listener.sendUserMessage(Severity.WARNING, message, ignore_and_reparse);
listener.subTask(message);
}
if (answer == null)
{
deleteIndexFiles(file, prefix, listener);
answer = parse(file, prefix, args, listtypes, listener);
}
entry = new SnapshotEntry(1, answer);
snapshotCache.put(file, entry);
return answer;
}
public synchronized void dispose(ISnapshot snapshot)
{
for (Iterator<SnapshotEntry> iter = snapshotCache.values().iterator(); iter.hasNext();)
{
SnapshotEntry entry = iter.next();
ISnapshot s = entry.snapshot.get();
if (s == null)
{
iter.remove();
}
else if (s == snapshot)
{
entry.usageCount--;
if (entry.usageCount == 0)
{
snapshot.dispose();
iter.remove();
}
return;
}
}
// just in case the snapshot is not stored anymore
if (snapshot != null)
snapshot.dispose();
}
public IOQLQuery createQuery(String queryString) throws SnapshotException
{
return new OQLQueryImpl(queryString);
}
public List<SnapshotFormat> getSupportedFormats()
{
List<SnapshotFormat> answer = new ArrayList<SnapshotFormat>();
for (Parser parser : ParserPlugin.getDefault().getParserRegistry().delegates())
answer.add(parser.getSnapshotFormat());
return answer;
}
// //////////////////////////////////////////////////////////////
// Internal implementations
// //////////////////////////////////////////////////////////////
private final ISnapshot parse(File file, String prefix, Map<String, String> args, List<IContentType>listtypes, IProgressListener listener) throws SnapshotException
{
ParserRegistry registry = ParserPlugin.getDefault().getParserRegistry();
List<ParserRegistry.Parser> parsers = registry.matchParser(file.getName());
if (parsers.isEmpty())
parsers.addAll(registry.delegates()); // try all...
else
{
// Add some extra parsers by content type
for (IContentType type : listtypes)
{
// Parsers don't match for equality
List<ParserRegistry.Parser> parsers2 = registry.matchParser(type);
for (ParserRegistry.Parser p2 : parsers2)
{
boolean found = false;
for (ParserRegistry.Parser p3 : parsers)
{
if (p3.getId().equals(p2.getId()))
{
found = true;
break;
}
}
if (!found)
parsers.add(p2);
}
}
}
List<IOException> errors = new ArrayList<IOException>();
for (Parser parser : parsers)
{
IIndexBuilder indexBuilder = parser.create(IIndexBuilder.class, ParserRegistry.INDEX_BUILDER);
if (indexBuilder == null)
continue;
try
{
indexBuilder.init(file, prefix);
XSnapshotInfo snapshotInfo = new XSnapshotInfo();
snapshotInfo.setPath(file.getAbsolutePath());
snapshotInfo.setPrefix(prefix);
snapshotInfo.setProperty("$heapFormat", parser.getId());//$NON-NLS-1$
if (Boolean.parseBoolean(args.get("keep_unreachable_objects")))//$NON-NLS-1$
{
snapshotInfo.setProperty("keep_unreachable_objects", GCRootInfo.Type.UNREACHABLE);//$NON-NLS-1$
}
if (args.containsKey("discard_ratio")) //$NON-NLS-1$
{
snapshotInfo.setProperty("discard_ratio", Integer.parseInt(args.get("discard_ratio"))); //$NON-NLS-1$//$NON-NLS-2$
if (args.containsKey("discard_pattern")) //$NON-NLS-1$
snapshotInfo.setProperty("discard_pattern", args.get("discard_pattern")); //$NON-NLS-1$ //$NON-NLS-2$
if (args.containsKey("discard_offset")) //$NON-NLS-1$
snapshotInfo.setProperty("discard_offset", Integer.parseInt(args.get("discard_offset"))); //$NON-NLS-1$ //$NON-NLS-2$
if (args.containsKey("discard_seed")) //$NON-NLS-1$
snapshotInfo.setProperty("discard_seed", Integer.parseInt(args.get("discard_seed"))); //$NON-NLS-1$ //$NON-NLS-2$
}
String snapshot_identifier = args.get("snapshot_identifier"); //$NON-NLS-1$
if (snapshot_identifier != null)
{
snapshotInfo.setProperty("$runtimeId", snapshot_identifier);//$NON-NLS-1$
}
PreliminaryIndexImpl idx = new PreliminaryIndexImpl(snapshotInfo);
indexBuilder.fill(idx, listener);
if (ParserPlugin.getDefault().isDebugging())
{
validateIndices(idx, listener);
}
SnapshotImplBuilder builder = new SnapshotImplBuilder(idx.getSnapshotInfo());
int[] purgedMapping = GarbageCleaner.clean(idx, builder, args, listener);
indexBuilder.clean(purgedMapping, listener);
SnapshotImpl snapshot = builder.create(parser, listener);
boolean done = false;
try
{
snapshot.calculateDominatorTree(listener);
done = true;
}
finally
{
if (!done)
{
// Error in dominator tree, so close the index files
snapshot.dispose();
}
}
return snapshot;
}
catch (IOException ioe)
{
errors.add(ioe);
indexBuilder.cancel();
}
catch (Exception e)
{
indexBuilder.cancel();
throw SnapshotException.rethrow(e);
}
}
if (errors.size() > 1)
{
MultiStatus status = new MultiStatus(ParserPlugin.PLUGIN_ID, 0,
MessageUtil.format(Messages.SnapshotFactoryImpl_ErrorOpeningHeapDump, file.getName()), null);
for (IOException error : errors)
status.add(new Status(IStatus.ERROR, ParserPlugin.PLUGIN_ID, 0, error.getLocalizedMessage(), error));
// Create a CoreException so that all the errors will be logged
CoreException ce = new CoreException(status);
throw new SnapshotException(MessageUtil.format(Messages.SnapshotFactoryImpl_Error_OpeningHeapDump, file
.getName()), ce);
}
else if (errors.size() == 1)
{
throw new SnapshotException(MessageUtil.format(Messages.SnapshotFactoryImpl_Error_OpeningHeapDump, file
.getName()), errors.get(0));
}
else
{
throw new SnapshotException(MessageUtil.format(Messages.SnapshotFactoryImpl_Error_NoParserRegistered, file
.getName()));
}
}
/**
* Check that indices look valid
*
* @param listener
*/
private void validateIndices(PreliminaryIndexImpl pidx, IProgressListener listener)
{
final int maxIndex = pidx.identifiers.size();
listener.beginTask(Messages.SnapshotFactoryImpl_ValidatingIndices, maxIndex / 1000 + 1);
long prevAddress = -1;
int nObjs = 0;
int nObjsFromClass = 0;
int nCls = 0;
// Look at each object
for (int i = 0; i < maxIndex; ++i)
{
if (i % 1000 == 0)
{
if (listener.isCanceled()) { throw new IProgressListener.OperationCanceledException(); }
listener.worked(1);
}
// Check addresses are in ascending order
long addr = pidx.identifiers.get(i);
if (prevAddress == addr)
{
String desc = objDesc(pidx, i);
int j = pidx.identifiers.reverse(addr);
String desc2 = objDesc(pidx, j);
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_IndexAddressHasSameAddressAsPrevious, i, desc, format(addr),
desc2), null);
}
if (prevAddress > addr)
{
String desc = objDesc(pidx, i);
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_IndexAddressIsSmallerThanPrevious, i, desc, format(addr),
format(prevAddress)), null);
}
prevAddress = addr;
int j = pidx.identifiers.reverse(addr);
if (i != j)
{
String desc1 = objDesc(pidx, i);
String desc2 = objDesc(pidx, j);
listener.sendUserMessage(Severity.ERROR,
MessageUtil.format(Messages.SnapshotFactoryImpl_IndexAddressFoundAtOtherID, i,
format(addr), j, desc1, desc2), null);
}
// Check the type of each object
int clsId = pidx.object2classId.get(i);
if (clsId < 0)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_ClassIDNotFound, i, format(addr), clsId), null);
}
else
{
ClassImpl ci = pidx.classesById.get(clsId);
if (ci == null)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_ClassImplNotFound, i, format(addr), clsId), null);
}
}
// Check the outbounds of each object
int outs[] = pidx.outbound.get(i);
if (outs == null)
{
String desc = objDesc(pidx, i);
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_NoOutbounds, i, format(addr), desc), null);
}
else
{
if (outs.length == 0)
{
String desc = objDesc(pidx, i);
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_EmptyOutbounds, i, format(addr), desc), null);
}
else
{
for (int k = 0; k < outs.length; ++k)
{
if (outs[k] < 0 || outs[k] >= maxIndex)
{
String desc = objDesc(pidx, i);
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_InvalidOutbound, i, format(addr), desc, k, outs[k]), null);
}
}
if (outs[0] != clsId) {
long address = outs[0] >= 0 && outs[0] < maxIndex ? pidx.identifiers.get(outs[0]) : -1;
String desc = objDesc(pidx, i);
long clsAddress = clsId >= 0 && outs[0] < maxIndex ? pidx.identifiers.get(clsId) : -1;
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_InvalidFirstOutbound, i, format(addr), desc, outs[0], format(address), clsId, format(clsAddress)), null);
}
}
}
// Check the object itself, and do special checks for plain objects or class objects
ClassImpl ci = pidx.classesById.get(i);
if (ci == null)
{
++nObjs;
// Ordinary object
long size = pidx.array2size.getSize(i);
if (size < 0)
{
ci = pidx.classesById.get(clsId);
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_IndexAddressNegativeArraySize, i, format(addr), size, ci
.getTechnicalName()), null);
}
}
else
{
++nCls;
long addr2 = ci.getObjectAddress();
if (addr != addr2)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_ClassIndexAddressNotEqualClassObjectAddress, i,
format(addr), format(addr2), ci.getTechnicalName()), null);
}
int id = ci.getObjectId();
if (i != id)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_ClassIndexNotEqualClassObjectID, i, format(addr), id, ci
.getTechnicalName()), null);
}
int clsId2 = ci.getClassId();
if (clsId != clsId2)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_ClassIndexAddressTypeIDNotEqualClassImplClassId, i,
format(addr), clsId, clsId2, ci.getTechnicalName()), null);
}
long ldrAddr = ci.getClassLoaderAddress();
int ldr = ci.getClassLoaderId();
if (ldr < 0)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_ClassIndexAddressNoLoaderID, i, format(addr), clsId, ldr,
format(ldrAddr), ci.getTechnicalName()), null);
}
nObjsFromClass += ci.getNumberOfObjects();
}
}
if (nObjsFromClass != nObjs + nCls)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_ObjectsFoundButClassesHadObjectsAndClassesInTotal, nObjs, nCls,
nObjsFromClass), null);
}
listener.subTask(Messages.SnapshotFactoryImpl_ValidatingGCRoots);
// Check some GC information
for (IteratorInt it = pidx.gcRoots.keys(); it.hasNext();)
{
int idx = it.next();
if (idx < 0 || idx >= maxIndex)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_GCRootIDOutOfRange, idx, maxIndex), null);
}
else
{
for (ListIterator<XGCRootInfo> it2 = pidx.gcRoots.get(idx).listIterator(); it2.hasNext();)
{
XGCRootInfo ifo = it2.next();
int objid = ifo.getObjectId();
if (objid != idx)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_GCRootIDDoesNotMatchIndex, objid, idx), null);
}
long objaddr = ifo.getObjectAddress();
int j = pidx.identifiers.reverse(objaddr);
if (j != idx)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_GCRootIDDoesNotMatchAddress, objid, Long.toHexString(objaddr)), null);
}
int ctxidx = ifo.getContextId();
long ctxaddr = ifo.getContextAddress();
if (ctxaddr != 0)
{
if (ctxidx < 0 || ctxidx >= maxIndex)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_GCRootIDOutOfRange, ctxidx, maxIndex), null);
}
int k = pidx.identifiers.reverse(ctxaddr);
if (k != ctxidx)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_GCRootContextIDDoesNotMatchAddress, objid, ctxidx, Long.toHexString(ctxaddr)), null);
}
}
}
}
}
for (int thrd : pidx.thread2objects2roots.getAllKeys())
{
if (thrd < 0 || thrd >= maxIndex)
{
listener.sendUserMessage(Severity.ERROR,
MessageUtil.format(Messages.SnapshotFactoryImpl_GCThreadIDOutOfRange, thrd, maxIndex), null);
}
else
{
HashMapIntObject<List<XGCRootInfo>> l = pidx.thread2objects2roots.get(thrd);
for (int idx : l.getAllKeys())
{
if (idx < 0 || idx >= maxIndex)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil
.format(Messages.SnapshotFactoryImpl_GCThreadRootIDOutOfRange, thrd, idx,
maxIndex), null);
}
else
{
for (XGCRootInfo ifo : l.get(idx))
{
int objid = ifo.getObjectId();
if (objid != idx)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_GCThreadRootIDDoesNotMatchIndex,
thrd, objid, idx), null);
}
long objaddr = ifo.getObjectAddress();
int j = pidx.identifiers.reverse(objaddr);
if (j != idx)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_GCRootIDDoesNotMatchAddress, objid, Long.toHexString(objaddr)), null);
}
int ctxidx = ifo.getContextId();
long ctxaddr = ifo.getContextAddress();
if (ctxaddr != 0)
{
if (ctxidx < 0 || ctxidx >= maxIndex)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_GCRootIDOutOfRange, ctxidx, maxIndex), null);
}
int k = pidx.identifiers.reverse(ctxaddr);
if (k != ctxidx)
{
listener.sendUserMessage(Severity.ERROR, MessageUtil.format(
Messages.SnapshotFactoryImpl_GCRootContextIDDoesNotMatchAddress, objid, ctxidx, Long.toHexString(ctxaddr)), null);
}
}
}
}
}
}
}
listener.done();
}
/**
* Convert an address to a 0x hex number
*
* @param address
* @return A string representing the address
*/
private static String format(long address)
{
return "0x" + Long.toHexString(address); //$NON-NLS-1$
}
/**
* Describe the class of the object at the given index
*
* @param newObjId
* @return a class description
*/
private String objDesc(PreliminaryIndexImpl pidx, int newObjId)
{
String clsInfo;
if (newObjId >= 0)
{
ClassImpl classInfo = pidx.classesById.get(newObjId);
if (classInfo != null)
{
clsInfo = MessageUtil.format(Messages.SnapshotFactoryImpl_ObjDescClass, classInfo.getName());
}
else
{
int clsId = pidx.object2classId.get(newObjId);
if (clsId >= 0 && clsId < pidx.identifiers.size())
{
long clsAddr = pidx.identifiers.get(clsId);
classInfo = pidx.classesById.get(clsId);
// If objectToClass has not yet been filled in for objects
// then this could be null
if (classInfo != null)
{
clsInfo = MessageUtil.format(Messages.SnapshotFactoryImpl_ObjDescObjType, classInfo.getName(),
format(clsAddr));
}
else
{
clsInfo = MessageUtil
.format(Messages.SnapshotFactoryImpl_ObjDescObjTypeAddress, format(clsAddr));
}
}
else
{
clsInfo = ""; //$NON-NLS-1$
}
}
}
else
{
clsInfo = ""; //$NON-NLS-1$
}
return clsInfo;
}
private void deleteIndexFiles(File file, final String prefix, IProgressListener listener)
{
File prefixFile = new File(prefix);
File directory = prefixFile.getParentFile();
if (directory == null)
directory = new File("."); //$NON-NLS-1$
final String fragment = prefixFile.getName();
final Pattern indexPattern = Pattern.compile("([A-Za-z0-9]+\\.)?index$"); //$NON-NLS-1$
final Pattern threadPattern = Pattern.compile("threads$"); //$NON-NLS-1$
final Pattern logPattern = Pattern.compile("inbound\\.index.*\\.log$"); //$NON-NLS-1$
File[] files = directory.listFiles(new FileFilter()
{
public boolean accept(File f)
{
if (f.isDirectory())
return false;
String name = f.getName();
return name.startsWith(fragment)
&& (indexPattern.matcher(name.substring(fragment.length())).matches()
|| threadPattern.matcher(name.substring(fragment.length())).matches()
|| logPattern.matcher(name.substring(fragment.length())).matches());
}
});
if (files != null)
{
for (File f : files)
{
boolean deleted = f.delete();
if (!deleted)
{
listener.sendUserMessage(Severity.WARNING,
MessageUtil.format(Messages.SnapshotFactoryImpl_UnableToDeleteIndexFile, f.toString()), null);
}
}
}
}
}