| /******************************************************************************* |
| * 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(); |
| } |
| } |
| } |