Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.felix.sigil.search.index; import java.lang.ref.SoftReference; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.regex.Pattern; import org.apache.bcel.classfile.JavaClass; import org.apache.felix.sigil.common.model.ModelElementFactory; import org.apache.felix.sigil.common.model.eclipse.ISigilBundle; import org.apache.felix.sigil.common.model.osgi.IPackageExport; import org.apache.felix.sigil.common.model.osgi.IRequiredBundle; import org.apache.felix.sigil.common.osgi.VersionRange; import org.apache.felix.sigil.common.repository.IBundleRepository; import org.apache.felix.sigil.search.ISearchResult; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IPackageFragment; import org.osgi.framework.Version; public class Index { private HashMap<String, ClassData> primary = new HashMap<String, ClassData>(); private HashMap<IBundleRepository, HashSet<String>> secondary = new HashMap<IBundleRepository, HashSet<String>>(); private final ReadWriteLock lock = new ReentrantReadWriteLock(); static class ClassData { HashMap<IBundleRepository, Set<ISearchResult>> provided = new HashMap<IBundleRepository, Set<ISearchResult>>(); void add(IBundleRepository rep, ISearchResult export) { Set<ISearchResult> exports = provided.get(rep); if (exports == null) { exports = new HashSet<ISearchResult>(); provided.put(rep, exports); } exports.add(export); } List<ISearchResult> getResults() { LinkedList<ISearchResult> exports = new LinkedList<ISearchResult>(); for (Set<ISearchResult> p : provided.values()) { exports.addAll(p); } return exports; } void remove(IBundleRepository rep) { provided.remove(rep); } boolean isEmpty() { return provided.isEmpty(); } } static class SearchResult implements ISearchResult { private final String className; private final String packageName; private final IBundleRepository rep; private final String bundleSymbolicName; private final Version version; private final boolean exported; private SoftReference<ISigilBundle> bundleReference; private SoftReference<IPackageExport> exportReference; public SearchResult(String className, IBundleRepository rep, ISigilBundle bundle, String packageName, boolean exported) { this.className = className; this.rep = rep; this.exported = exported; this.bundleSymbolicName = bundle.getBundleInfo().getSymbolicName(); this.version = bundle.getVersion(); this.packageName = packageName; } public String getClassName() { return className; } public String getPackageName() { return packageName; } public IPackageExport getExport() { IPackageExport ipe = null; if (exported) { ipe = exportReference == null ? null : exportReference.get(); if (ipe == null) { ipe = getProvider().findExport(packageName); exportReference = new SoftReference<IPackageExport>(ipe); } } return ipe; } public ISigilBundle getProvider() { ISigilBundle b = bundleReference == null ? null : bundleReference.get(); if (b == null) { IRequiredBundle rb = ModelElementFactory.getInstance().newModelElement(IRequiredBundle.class); rb.setSymbolicName(bundleSymbolicName); VersionRange versions = new VersionRange(false, version, version, false); rb.setVersions(versions); b = rep.findProvider(rb, 0); bundleReference = new SoftReference<ISigilBundle>(b); } return b; } } public void addEntry(JavaClass c, IBundleRepository rep, ISigilBundle bundle, boolean exported) { addEntry(c.getClassName(), rep, bundle, c.getPackageName(), exported); } public void addEntry(ICompilationUnit unit, IBundleRepository rep, ISigilBundle bundle, boolean exported) { String name = unit.getElementName(); if (name.endsWith(".java")) { name = name.substring(0, name.length() - 5); } IPackageFragment p = (IPackageFragment) unit.getAncestor(IJavaElement.PACKAGE_FRAGMENT); addEntry(p.getElementName() + "." + name, rep, bundle, p.getElementName(), exported); } private void addEntry(String className, IBundleRepository rep, ISigilBundle bundle, String packageName, boolean exported) { List<String> keys = genKeys(className); lock.writeLock().lock(); try { for (String key : keys) { ClassData data = primary.get(key); if (data == null) { data = new ClassData(); primary.put(key, data); } SearchResult result = new SearchResult(className, rep, bundle, packageName, exported); data.add(rep, result); } HashSet<String> all = secondary.get(rep); if (all == null) { all = new HashSet<String>(); secondary.put(rep, all); } all.addAll(keys); } finally { lock.writeLock().unlock(); } } public List<ISearchResult> findProviders(String className, IProgressMonitor monitor) { lock.readLock().lock(); try { ClassData data = primary.get(className); return data == null ? Collections.<ISearchResult>emptyList() : data.getResults(); } finally { lock.readLock().unlock(); } } public List<ISearchResult> findProviders(Pattern className, IProgressMonitor monitor) { lock.readLock().lock(); try { ClassData data = primary.get(className); return data == null ? Collections.<ISearchResult>emptyList() : data.getResults(); } finally { lock.readLock().unlock(); } } public void delete(IBundleRepository rep) { lock.writeLock().lock(); try { Set<String> keys = secondary.remove(rep); if (keys != null) { for (String key : keys) { ClassData data = primary.get(key); data.remove(rep); if (data.isEmpty()) { primary.remove(key); } } } } finally { lock.writeLock().unlock(); } } private List<String> genKeys(String className) { LinkedList<String> keys = new LinkedList<String>(); keys.add(className); int i = className.lastIndexOf('.'); if (i != -1) { String name = className.substring(i + 1); keys.add(name); } return keys; } }