blob: 31b8dc22756bd19b627cffc359d33b5d435d5c2d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2007 Boeing.
* 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:
* Boeing - initial API and implementation
*******************************************************************************/
package org.eclipse.osee.ote.classserver;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilePermission;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Level;
import org.eclipse.osee.framework.logging.OseeLog;
public class PathResourceFinder extends ResourceFinder {
private final HashSet<JarFile> jars = new HashSet<>(128);
private final HashSet<String> dirs = new HashSet<>(128);
private final HashMap<String, JarFile[]> map = new HashMap<>(128);
private final boolean trees;
private final ClassServerPermissions perm;
private static final int NUMBER_OF_FILE_READ_ATTEMPTS = 20;
public PathResourceFinder(String[] dirsToAdd, boolean trees) {
this.trees = trees;
perm = new ClassServerPermissions();
if (dirsToAdd != null) {
addPaths(dirsToAdd);
}
}
@Override
public byte[] find(String path) throws IOException {
int i = path.indexOf('/');
if (i > 0) {
JarFile[] jfs = map.get(path.substring(0, i));
if (jfs != null) {
String jpath = path.substring(i + 1);
for (i = 0; i < jfs.length; i++) {
JarEntry je = jfs[i].getJarEntry(jpath);
if (je != null) {
return getBytes(jfs[i].getInputStream(je), je.getSize());
}
}
}
}
synchronized (jars) {
Iterator<JarFile> it = jars.iterator();
while (it.hasNext()) {
JarFile jar = it.next();
JarEntry je = jar.getJarEntry(path);
if (je != null) {
return getBytes(jar.getInputStream(je), je.getSize());
}
}
}
boolean exists = false;
File f = null;
synchronized (dirs) {
for (int j = 0; j < NUMBER_OF_FILE_READ_ATTEMPTS; j++) { // we'll retry in case there is a
// compile going on
Iterator<String> it = dirs.iterator();
while (it.hasNext()) {
String dirString = it.next();
f = new File(dirString + File.separatorChar + path.replace('/', File.separatorChar));
if (f.exists()) {
exists = true;
break;
}
}
if (!exists) {
try {
synchronized (this) {
this.wait(1000);
}
System.err.println(String.format("trying to find :%s %d", path, j));
} catch (InterruptedException ex) {
}
} else {
break;
}
}
}
if (exists) {
if (perm.implies(new FilePermission(f.getPath(), "read"))) {
try {
return getBytes(new FileInputStream(f), f.length());
} catch (FileNotFoundException e) {
}
}
}
return null;
}
public void addPaths(String[] paths) {
for (int i = 0; i < paths.length; i++) {
String path = paths[i];
if (path.startsWith("file:\\")) {
path = path.substring(6);
}
if (path.endsWith(".jar")) {
try {
synchronized (jars) {
jars.add(new JarFile(new File(path)));
}
} catch (Exception ex) {
ex.printStackTrace();
continue;
}
} else {
if (dirs.add(path)) {
perm.add(new FilePermission(path + File.separator + '-', "read"));
}
}
if (trees) {
File fdir = new File(path);
String[] files = fdir.list();
if (files != null) {
try {
URL base = fdir.toURI().toURL();
for (int j = 0; j < files.length; j++) {
String jar = files[j];
if (jar.endsWith(".jar") || jar.endsWith(".zip")) {
ArrayList<JarFile> jfs = new ArrayList<>(10);
try {
addJar(jar, jfs, base);
map.put(jar.substring(0, jar.length() - 4), jfs.toArray(new JarFile[jfs.size()]));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
}
}
}
/** Add transitive Class-Path JARs to jfs. */
private void addJar(String jar, ArrayList<JarFile> jfs, URL base) throws IOException {
base = new URL(base, jar);
jar = base.getFile().replace('/', File.separatorChar);
for (int i = jfs.size(); --i >= 0;) {
if (jar.equals(jfs.get(i).getName())) {
return;
}
}
JarFile jf = new JarFile(jar);
jfs.add(jf);
try {
Manifest man = jf.getManifest();
if (man == null) {
return;
}
Attributes attrs = man.getMainAttributes();
if (attrs == null) {
return;
}
String val = attrs.getValue(Attributes.Name.CLASS_PATH);
if (val == null) {
return;
}
for (StringTokenizer st = new StringTokenizer(val); st.hasMoreTokens();) {
addJar(st.nextToken(), jfs, base);
}
} catch (IOException ex) {
jfs.remove(jf);
jf.close();
throw ex;
}
}
/**
* Finds the jarFile if it is being served.
*
* @param name The name of the jar file
* @return The jar represented as a File, or null if the jar was not found.
*/
public File getJarFile(String name) {
File jarFileReturn = null;
synchronized (jars) {
Iterator<JarFile> it = jars.iterator();
while (it.hasNext()) {
JarFile jarFile = it.next();
if (jarFile.getName().endsWith(File.separator + name)) {
jarFileReturn = new File(jarFile.getName());
break;
}
}
}
return jarFileReturn;
}
public void removeJarFile(String name) {
synchronized (jars) {
Iterator<JarFile> it = jars.iterator();
while (it.hasNext()) {
JarFile jarFile = it.next();
if (jarFile.getName().endsWith(File.separator + name)) {
try {
OseeLog.log(ClassServer.class, Level.INFO, "removing JAR file " + name);
jarFile.close();
} catch (IOException ex) {
// do nothing
}
it.remove();
return;
}
}
}
}
@Override
public void dispose() {
synchronized (jars) {
OseeLog.log(ClassServer.class, Level.INFO, "disposing path resource finder's cached JAR files");
Iterator<JarFile> it = jars.iterator();
while (it.hasNext()) {
JarFile jarFile = it.next();
try {
jarFile.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
jars.clear();
}
}
}