Package org.osmorc.manifest.impl

Source Code of org.osmorc.manifest.impl.LibraryManifestHolderImpl

/*
* Copyright (c) 2007-2009, Osmorc Development Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list
*       of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this
*       list of conditions and the following disclaimer in the documentation and/or other
*       materials provided with the distribution.
*     * Neither the name of 'Osmorc Development Team' nor the names of its contributors may be
*       used to endorse or promote products derived from this software without specific
*       prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.osmorc.manifest.impl;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osmorc.manifest.BundleManifest;
import org.osmorc.manifest.ManifestHolder;
import org.osmorc.manifest.ManifestHolderDisposedException;
import org.jetbrains.lang.manifest.psi.ManifestFile;

import java.util.*;

/**
* Author: Robert F. Beeger (robert@beeger.net)
*/
public class LibraryManifestHolderImpl extends AbstractManifestHolderImpl {

  private BundleManifest myBundleManifest;
  private final Library myLibrary;
  private final Project myProject;
  private final String myPath;

  private LibraryManifestHolderImpl(Library library, Project project, String rootPath) {
    myLibrary = library;
    myProject = project;
    myPath = rootPath;
  }

  @Nullable
  public BundleManifest getBundleManifest() throws ManifestHolderDisposedException {
    // FIX for EA-23586
    if (isDisposed()) {
      throw new ManifestHolderDisposedException();
    }

    if (myBundleManifest == null) {

      VirtualFile[] classRoots = myLibrary.getFiles(OrderRootType.CLASSES);
      for (VirtualFile classRoot : classRoots) {
        if (classRoot.getUrl().equals(myPath)) {
          VirtualFile classDir;
          if (classRoot.isDirectory()) {
            classDir = classRoot;
          }
          else {
            classDir = JarFileSystem.getInstance().getJarRootForLocalFile(classRoot);
          }

          if (classDir != null) {
            final VirtualFile manifestFile = classDir.findFileByRelativePath("META-INF/MANIFEST.MF");
            if (manifestFile != null) {
              PsiFile psiFile = new ReadAction<PsiFile>() {
                @Override
                protected void run(Result<PsiFile> psiFileResult) throws Throwable {
                  psiFileResult.setResult(PsiManager.getInstance(myProject).findFile(manifestFile));
                }
              }.execute().getResultObject();
              myBundleManifest = new BundleManifestImpl((ManifestFile)psiFile);
            }
          }
          break; // we're done here.
        }
      }
    }
    return myBundleManifest;
  }

  public boolean isDisposed() {
    return isLibraryDisposed(myLibrary) || myProject.isDisposed();
  }


  private static boolean isLibraryDisposed(Library library) {
    return library instanceof LibraryEx && ((LibraryEx)library).isDisposed();
  }

  /**
   * Creats manifest holders of the given library and project
   *
   * @param library the library
   * @param project the prorject
   * @return the manifest holders
   */
  @NotNull
  protected static synchronized Collection<ManifestHolder> createForLibrary(@NotNull Library library, @NotNull Project project) {
    cleanupHolderCache();
    List<ManifestHolder> result = new ArrayList<ManifestHolder>();
    if (isLibraryDisposed(library) || project.isDisposed()) {
      return result;
    }
    VirtualFile[] classRoots = library.getFiles(OrderRootType.CLASSES);
    for (VirtualFile classRoot : classRoots) {
      String jarFileUrl = classRoot.getUrl();
      ManifestHolder cachedHolder = myHolderCache.get(jarFileUrl);
      if (cachedHolder != null) {
        result.add(cachedHolder);
        continue;
      }
      VirtualFile classDir;
      if (classRoot.isDirectory()) {
        classDir = classRoot;
      }
      else {
        classDir = JarFileSystem.getInstance().getJarRootForLocalFile(classRoot);
      }

      if (classDir != null) {
        final VirtualFile manifestFile = classDir.findFileByRelativePath("META-INF/MANIFEST.MF");
        if (manifestFile != null) {
          // potential bundle
          final LibraryManifestHolderImpl newHolder = new LibraryManifestHolderImpl(library, project, jarFileUrl);

          // kill reference to the project when it is being disposed. (project leak fix by Alexey Kudravtsev)
          Disposer.register(project, new Disposable() {
            @Override
            public void dispose() {
              synchronized (LibraryManifestHolderImpl.class) {  // make sure there is no concurrent access to the holder cache.
                for (Iterator<LibraryManifestHolderImpl> iterator = myHolderCache.values().iterator(); iterator.hasNext(); ) {
                  LibraryManifestHolderImpl holder = iterator.next();
                  if (holder == newHolder) {
                    iterator.remove();
                    break;
                  }
                }
              }
            }
          });

          myHolderCache.put(jarFileUrl, newHolder);
          result.add(newHolder);
        }
      }
    }
    return result;
  }


  /**
   * Removes disposed holders from the holder cache.
   */
  private static void cleanupHolderCache() {
    for (Iterator<Map.Entry<String, LibraryManifestHolderImpl>> iterator = myHolderCache.entrySet().iterator(); iterator.hasNext(); ) {
      Map.Entry<String, LibraryManifestHolderImpl> entry = iterator.next();
      if (entry.getValue().isDisposed()) {
        iterator.remove();
      }
    }
  }

  /**
   * Cache for generated manifest holders. This is to make sure we don't create two manifest holders for the same jar file.
   */
  private static final Map<String, LibraryManifestHolderImpl> myHolderCache = new HashMap<String, LibraryManifestHolderImpl>();

  @Override
  public Object getBoundObject() throws ManifestHolderDisposedException {
    if (isDisposed()) {
      throw new ManifestHolderDisposedException();
    }
    return myLibrary;
  }
}
TOP

Related Classes of org.osmorc.manifest.impl.LibraryManifestHolderImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.