blob: fa660cd458e1265987369d7a9f60017d043ba6fa [file] [log] [blame]
/*
* 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.netbeans.modules.maven.classpath;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.java.platform.JavaPlatformManager;
import org.netbeans.modules.maven.NbMavenProjectImpl;
import org.netbeans.modules.maven.api.Constants;
import org.netbeans.modules.maven.api.FileUtilities;
import org.netbeans.modules.maven.api.PluginPropertyUtils;
import org.netbeans.modules.maven.indexer.api.NBVersionInfo;
import org.netbeans.modules.maven.indexer.api.RepositoryInfo;
import org.netbeans.modules.maven.indexer.api.RepositoryPreferences;
import org.netbeans.modules.maven.indexer.api.RepositoryQueries;
import org.netbeans.modules.maven.indexer.api.RepositoryUtil;
import org.netbeans.spi.java.classpath.ClassPathImplementation;
import org.netbeans.spi.java.classpath.PathResourceImplementation;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.openide.filesystems.FileAttributeEvent;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileRenameEvent;
import org.openide.filesystems.FileUtil;
import org.openide.util.RequestProcessor;
/**
* NO listening on changes here, let the BootClassPath deal with it..
* @author Milos Kleint
*/
@org.netbeans.api.annotations.common.SuppressWarnings("DMI_COLLECTION_OF_URLS")
public final class EndorsedClassPathImpl implements ClassPathImplementation, FileChangeListener {
private static final Logger LOG = Logger.getLogger(EndorsedClassPathImpl.class.getName());
static final RequestProcessor RP = new RequestProcessor(EndorsedClassPathImpl.class);
private List<? extends PathResourceImplementation> resourcesCache;
private boolean includeJDKCache;
private boolean includeFXCache;
private final PropertyChangeSupport support = new PropertyChangeSupport(this);
private final NbMavenProjectImpl project;
private BootClassPathImpl bcp;
private String[] current;
private final File endorsed;
private final Map<File,File/*|null*/> endorsed2Repo = new HashMap<File,File>();
@SuppressWarnings("LeakingThisInConstructor")
EndorsedClassPathImpl(NbMavenProjectImpl project) {
this.project = project;
endorsed = new File(project.getPOMFile().getParentFile(), "target/endorsed"); // NOI18N
FileUtil.addFileChangeListener(this, endorsed);
}
public @Override List<? extends PathResourceImplementation> getResources() {
boolean[] arr = { false };
return getResources(arr, arr);
}
final List<? extends PathResourceImplementation> getResources(boolean[] includeJDK, boolean[] includeFx) {
assert bcp != null;
synchronized (bcp.LOCK) {
if (this.resourcesCache == null) {
ArrayList<PathResourceImplementation> result = new ArrayList<PathResourceImplementation> ();
String[] boot = getBootClasspath();
includeJDKCache = true;
includeFXCache = false;
if (boot != null) {
for (String b : boot) {
if ("netbeans.ignore.jdk.bootclasspath".equals(b)) { // NOI18N
includeJDK[0] = false;
includeFXCache = false;
includeJDKCache = false;
}
}
StripPlatformResult res = stripDefaultJavaPlatform(boot);
includeFx[0] = res.hasFx;
includeFXCache = res.hasFx;
for (URL u : res.urls) {
if (u != null) {
result.add (ClassPathSupport.createResource(u));
}
}
}
File[] jars = endorsed.listFiles();
if (jars != null) {
for (final File jar : jars) {
if (jar.isFile()) {
if (endorsed2Repo.containsKey(jar)) {
File toScan = endorsed2Repo.get(jar);
if (toScan != null) {
URL url = FileUtil.urlForArchiveOrDir(toScan);
if (url != null) {
result.add(ClassPathSupport.createResource(url));
}
}
} else {
// #197510: blocking, must do this asynch
LOG.log(Level.FINE, "looking up {0}", jar);
RP.post(new Runnable() {
public @Override void run() {
synchronized (bcp.LOCK) {
if (endorsed2Repo.containsKey(jar)) {
// Another task beat us to it.
return;
}
}
if (!jar.isFile()) {
return;
}
File toScan = null;
REPO: for (RepositoryInfo repo : RepositoryPreferences.getInstance().getRepositoryInfos()) {
LOG.log(Level.FINE, "checking {0}", repo);
for (NBVersionInfo analogue : RepositoryQueries.findBySHA1Result(jar, Collections.singletonList(repo)).getResults()) {
toScan = RepositoryUtil.createArtifact(analogue).getFile();
LOG.log(Level.FINE, "found {0}", toScan);
break REPO;
}
}
if (toScan == null) {
try {
toScan = FileUtil.normalizeFile(new File(System.getProperty("java.io.tmpdir"), RepositoryUtil.calculateSHA1Checksum(jar) + ".jar"));
if (!toScan.isFile()) {
FileUtils.copyFile(jar, toScan);
}
} catch (IOException x) {
LOG.log(Level.INFO, "copying " + jar + " to " + toScan, x);
}
}
LOG.log(Level.FINE, "mapping {0} -> {1}", new Object[] {jar, toScan});
synchronized (bcp.LOCK) {
endorsed2Repo.put(jar, toScan);
resourcesCache = null;
}
support.firePropertyChange(PROP_RESOURCES, null, null);
}
});
}
}
}
}
current = boot;
resourcesCache = Collections.unmodifiableList (result);
} else {
includeJDK[0] = includeJDKCache;
includeFx[0] = includeFXCache;
}
return this.resourcesCache;
}
}
public @Override void addPropertyChangeListener(PropertyChangeListener listener) {
this.support.addPropertyChangeListener (listener);
}
public @Override void removePropertyChangeListener(PropertyChangeListener listener) {
this.support.removePropertyChangeListener (listener);
}
private String[] getBootClasspath() {
String carg = PluginPropertyUtils.getPluginProperty(project, Constants.GROUP_APACHE_PLUGINS, Constants.PLUGIN_COMPILER, "compilerArgument", "compile", null);
if (carg != null) {
//TODO
}
Properties cargs = PluginPropertyUtils.getPluginPropertyParameter(project, Constants.GROUP_APACHE_PLUGINS, Constants.PLUGIN_COMPILER, "compilerArguments", "compile");
if (cargs != null) {
String carg2 = cargs.getProperty("bootclasspath");
if (carg2 != null) {
return StringUtils.split(carg2, File.pathSeparator);
}
}
return null;
}
/**
* Resets the cache and firesPropertyChange
*/
boolean resetCache () {
String[] newones = getBootClasspath();
boolean fire = false;
assert bcp != null;
synchronized (bcp.LOCK) {
if (!Arrays.equals(newones, current)) {
resourcesCache = null;
fire = true;
}
}
if (fire) {
support.firePropertyChange(PROP_RESOURCES, null, null);
}
return fire;
}
void setBCP(BootClassPathImpl aThis) {
bcp = aThis;
}
private class StripPlatformResult {
List<URL> urls;
boolean hasFx = false;
}
private StripPlatformResult stripDefaultJavaPlatform(String[] boot) {
StripPlatformResult res = new StripPlatformResult();
List<URL> toRet = new ArrayList<URL>();
res.urls = toRet;
Set<URL> defs = getDefJavaPlatBCP();
OUTER: for (String s : boot) {
File f = FileUtilities.convertStringToFile(s);
URL entry = FileUtil.urlForArchiveOrDir(f);
if (entry != null && !defs.contains(entry)) {
if (entry.getPath().endsWith("/jfxrt.jar!/")) {
//we need to iterate the defs and check again as jdk8 and jdk7 have these at different places
for (URL d : defs) {
if (d.getPath().endsWith("/jfxrt.jar!/")) {
res.hasFx = true;
continue OUTER;
}
}
}
toRet.add(entry);
}
}
return res;
}
private final Set<URL> djpbcp = new HashSet<URL>();
private Set<URL> getDefJavaPlatBCP() {
synchronized (djpbcp) {
if (djpbcp.isEmpty()) {
JavaPlatformManager mngr = JavaPlatformManager.getDefault();
JavaPlatform jp = mngr.getDefaultPlatform();
ClassPath cp = jp.getBootstrapLibraries();
for (ClassPath.Entry ent : cp.entries()) {
djpbcp.add(ent.getURL());
}
}
return Collections.unmodifiableSet(djpbcp);
}
}
private void fileChange() {
assert bcp != null;
synchronized (bcp.LOCK) {
resourcesCache = null;
}
support.firePropertyChange(PROP_RESOURCES, null, null);
}
public @Override void fileFolderCreated(FileEvent fe) {
fileChange();
}
public @Override void fileDataCreated(FileEvent fe) {
fileChange();
}
public @Override void fileChanged(FileEvent fe) {
fileChange();
}
public @Override void fileDeleted(FileEvent fe) {
fileChange();
}
public @Override void fileRenamed(FileRenameEvent fe) {
fileChange();
}
public @Override void fileAttributeChanged(FileAttributeEvent fe) {}
}