Java tutorial
/* * Copyright (c) 2009 Andrejs Jermakovics. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Andrejs Jermakovics - initial implementation */ package it.unibz.instasearch.indexing; import it.unibz.instasearch.InstaSearchPlugin; import it.unibz.instasearch.prefs.PreferenceConstants; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.LinkedList; import java.util.List; import java.util.TreeSet; import org.apache.lucene.index.IndexWriter; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IStorage; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.IJarEntryResource; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaModel; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility; import org.eclipse.ui.IEditorInput; /** * Workspace indexer which also indexes JAR source attachments */ @SuppressWarnings("restriction") public class WorkspaceIndexerJDT extends WorkspaceIndexer { /** * @throws Exception * @throws IOException */ public WorkspaceIndexerJDT() throws Exception { super(); if (JavaCore.getJavaCore() == null) // check that we have JDT. throws exception if we don't have JavaCore throw new RuntimeException("JDT not detected"); } @Override protected void indexContainers(IndexWriter indexWriter, IWorkspaceRoot workspaceRoot, IProgressMonitor monitor) throws Exception { super.indexContainers(indexWriter, workspaceRoot, monitor); boolean indexArchives = InstaSearchPlugin.getBoolPref(PreferenceConstants.P_INDEX_ARCHIVES); if (!indexArchives) return; try { IJavaModel javaModel = JavaCore.create(workspaceRoot); List<IPackageFragmentRoot> jars = getJars(javaModel); monitor.beginTask("Indexing JAR Source Attachements (" + jars.size() + ")", jars.size()); for (IPackageFragmentRoot jar : jars) { monitor.worked(1); indexClassFiles(indexWriter, jar, monitor); indexNonJavaResources(indexWriter, jar, monitor); if (monitor.isCanceled()) break; } } catch (Exception e) { InstaSearchPlugin.log(e); } if (monitor.isCanceled()) { // if user canceled, disable jar indexing in preferences. next time don't index InstaSearchPlugin.setBoolPref(PreferenceConstants.P_INDEX_ARCHIVES, false); } monitor.done(); } /** * Index non .class files * * @param indexWriter * @param jar * @param monitor * @throws CoreException * @throws IOException */ private void indexNonJavaResources(IndexWriter indexWriter, IPackageFragmentRoot jar, IProgressMonitor monitor) throws Exception { Object[] resources = jar.getNonJavaResources(); if (resources == null || resources.length == 0) return; IJarEntryResource[] jarEntries = new IJarEntryResource[resources.length]; System.arraycopy(resources, 0, jarEntries, 0, resources.length); indexNonJavaResources(indexWriter, jar, jarEntries, monitor); } /** * @param indexWriter * @param jar * @param resources * @param monitor * @throws IOException * @throws CoreException */ private void indexNonJavaResources(IndexWriter indexWriter, IPackageFragmentRoot jar, IJarEntryResource[] resources, IProgressMonitor monitor) throws Exception { String jarName = getJarName(jar); String projectPath = getProjectPath(jar); for (IJarEntryResource resource : resources) { if (monitor.isCanceled()) return; if (resource.isFile()) { if (isIndexable(resource)) indexStorageWithRetry(indexWriter, resource, projectPath, IResource.NULL_STAMP, jarName); } else { indexNonJavaResources(indexWriter, jar, resource.getChildren(), monitor); } } } /** * @param jarRes * @return */ private boolean isIndexable(IJarEntryResource jarRes) { String ext = jarRes.getFullPath().getFileExtension(); return isIndexableExtension(ext); } /** * @param jar * @return */ private String getProjectPath(IPackageFragmentRoot jar) { return jar.getJavaProject().getElementName() + "/" + getJarName(jar); } /** * @param jar * @return */ private String getJarName(IPackageFragmentRoot jar) { return jar.getElementName(); } private void indexClassFiles(IndexWriter indexWriter, IPackageFragmentRoot jar, IProgressMonitor monitor) throws Exception { String jarName = getJarName(jar); String projectPath = getProjectPath(jar); for (IJavaElement pkgRootChild : jar.getChildren()) { IPackageFragment pkg = (IPackageFragment) pkgRootChild; monitor.setTaskName( "Indexing JAR Source Attachements: " + jar.getElementName() + " - " + pkg.getElementName()); for (IClassFile classFile : pkg.getClassFiles()) { if (classFile.getElementName().contains("$")) continue; // not type root ClassFileSourceStorage classFileSourceStorage = new ClassFileSourceStorage(classFile); if (classFileSourceStorage.hasSource()) indexStorageWithRetry(indexWriter, classFileSourceStorage, projectPath, IResource.NULL_STAMP, jarName); if (monitor.isCanceled()) return; } } } private List<IPackageFragmentRoot> getJars(IJavaModel javaModel) throws JavaModelException { IJavaProject[] projects = javaModel.getJavaProjects(); TreeSet<String> jarNames = new TreeSet<String>(); LinkedList<IPackageFragmentRoot> jars = new LinkedList<IPackageFragmentRoot>(); for (IJavaProject javaProj : projects) { IPackageFragmentRoot[] roots = javaProj.getPackageFragmentRoots(); for (IPackageFragmentRoot root : roots) { if (root.isArchive() && root.getSourceAttachmentPath() != null) { String name = root.getElementName(); if (!jarNames.contains(name)) { jarNames.add(name); jars.add(root); } } } } return jars; } @Override public IEditorInput getEditorInput(SearchResultDoc doc) throws Exception { if (!doc.isInJar()) return super.getEditorInput(doc); if ("class".equals(doc.getFileExtension())) { IClassFile classFile = getClassFile(doc); if (classFile == null) return null; return EditorUtility.getEditorInput(classFile); } IStorage storage = getNonJavaResource(doc); if (storage == null) return null; return EditorUtility.getEditorInput(storage); } @Override public IStorage getStorage(SearchResultDoc doc) throws Exception { if (!doc.isInJar()) return super.getStorage(doc); // return file if ("class".equals(doc.getFileExtension())) { IClassFile classFile = getClassFile(doc); if (classFile == null) return null; ClassFileSourceStorage storage = new ClassFileSourceStorage(classFile); return storage; } return getNonJavaResource(doc); } /** * @param doc * @return * @throws JavaModelException */ private IStorage getNonJavaResource(SearchResultDoc doc) throws JavaModelException { IWorkspaceRoot workspaceRoot = InstaSearchPlugin.getWorkspaceRoot(); IJavaModel javaModel = JavaCore.create(workspaceRoot); String javaProjectName = doc.getProject().segment(0); IJavaProject javaProj = javaModel.getJavaProject(javaProjectName); if (!javaProj.isOpen()) javaProj.open(new NullProgressMonitor()); javaModel.refreshExternalArchives(new IJavaElement[] { javaProj }, new NullProgressMonitor()); String jarName = doc.getJarName(); IPackageFragmentRoot[] roots = javaProj.getPackageFragmentRoots(); IPackageFragmentRoot jar = null; for (IPackageFragmentRoot root : roots) { if (root.isArchive() && root.getSourceAttachmentPath() != null) { String name = root.getElementName(); if (name.equals(jarName)) { jar = root; break; } } } if (jar == null) return null; String filePath = doc.getFilePath(); IPath path = new Path(filePath); IJarEntryResource res = null; for (String segment : path.segments()) { if (res == null) res = findJarEntry(jar, segment); else res = findJarEntry(res.getChildren(), segment); } return res; } /** * @param jar * @param filePath * @return * @throws JavaModelException */ private IJarEntryResource findJarEntry(IPackageFragmentRoot jar, String filePath) throws JavaModelException { Object[] resources = jar.getNonJavaResources(); if (resources == null || resources.length == 0) return null; IJarEntryResource[] jarEntries = new IJarEntryResource[resources.length]; System.arraycopy(resources, 0, jarEntries, 0, resources.length); return findJarEntry(jarEntries, filePath); } /** * @param jarEntries * @param filePath * @return */ private IJarEntryResource findJarEntry(IJarEntryResource[] jarEntries, String filePath) { for (IJarEntryResource entry : jarEntries) { if (filePath.equals(entry.getName())) return entry; } return null; } /** * @param doc * @return * @throws JavaModelException */ private IClassFile getClassFile(SearchResultDoc doc) throws Exception { IWorkspaceRoot workspaceRoot = InstaSearchPlugin.getWorkspaceRoot(); IJavaModel javaModel = JavaCore.create(workspaceRoot); String javaProjectName = doc.getProject().segment(0); IJavaProject proj = javaModel.getJavaProject(javaProjectName); if (proj == null) throw new Exception("Project " + javaProjectName + " not found"); if (!proj.isOpen()) proj.open(new NullProgressMonitor()); javaModel.refreshExternalArchives(new IJavaElement[] { proj }, new NullProgressMonitor()); IPath filePath = new Path(doc.getFilePath()); String fileName = filePath.lastSegment(); IPath jarPath = filePath.removeLastSegments(2); // remove pkg and filename IPackageFragmentRoot jar = null; IResource jarFile = workspaceRoot.findMember(jarPath); if (jarFile != null) jar = proj.getPackageFragmentRoot(jarFile); else jar = proj.getPackageFragmentRoot(jarPath.toString()); // external archive if (jar == null) throw new Exception("Jar " + jarPath + " not found in project " + doc.getProjectName()); IPath pkgPath = filePath.removeLastSegments(1); // remove filename String pkgName = pkgPath.lastSegment(); IPackageFragment pkg = jar.getPackageFragment(pkgName); if (pkg == null) throw new Exception("Package " + pkgName + " not found in " + doc.getProjectName()); IClassFile classFile = pkg.getClassFile(fileName); return classFile; } /** * Stores the attached source of a .class file */ private class ClassFileSourceStorage implements IStorage { private IClassFile classFile; private String source; /** * @param classFileWithSource * @throws JavaModelException * */ public ClassFileSourceStorage(IClassFile classFileWithSource) throws JavaModelException { this.classFile = classFileWithSource; this.source = classFile.getSource(); } public InputStream getContents() throws CoreException { if (!hasSource()) return null; return new ByteArrayInputStream(source.getBytes()); } public boolean hasSource() { return source != null; } /** * <jar path>/<package name>/<file name> */ public IPath getFullPath() { IPackageFragment pkg = (IPackageFragment) classFile.getParent(); IPackageFragmentRoot jar = (IPackageFragmentRoot) pkg.getParent(); String pkgName = pkg.getElementName(); IPath jarPath = jar.getPath(); IPath filePath = jarPath.append(pkgName).append(getName()); return filePath; } public String getName() { return classFile.getElementName(); // ClassName.class } public boolean isReadOnly() { return true; } @SuppressWarnings("rawtypes") public Object getAdapter(Class adapter) { return classFile.getAdapter(adapter); } } }