1 /*******************************************************************************
2  * Copyright (c) 2006, 2018 IBM Corp. and others
3  *
4  * This program and the accompanying materials are made available under
5  * the terms of the Eclipse Public License 2.0 which accompanies this
6  * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7  * or the Apache License, Version 2.0 which accompanies this distribution and
8  * is available at https://www.apache.org/licenses/LICENSE-2.0.
9  *
10  * This Source Code may also be made available under the following
11  * Secondary Licenses when the conditions for such availability set
12  * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13  * General Public License, version 2 with the GNU Classpath
14  * Exception [1] and GNU General Public License, version 2 with the
15  * OpenJDK Assembly Exception [2].
16  *
17  * [1] https://www.gnu.org/software/classpath/license.html
18  * [2] http://openjdk.java.net/legal/assembly-exception.html
19  *
20  * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21  *******************************************************************************/
22 
23 package org.eclipse.osgi.internal.cds;
24 
25 import com.ibm.oti.shared.SharedClassURLHelper;
26 import java.net.MalformedURLException;
27 import java.net.URL;
28 import org.eclipse.osgi.storage.bundlefile.BundleEntry;
29 import org.eclipse.osgi.storage.bundlefile.BundleFile;
30 import org.eclipse.osgi.storage.bundlefile.BundleFileWrapper;
31 
32 /**
33  * Wraps an actual BundleFile object for purposes of loading classes from the
34  * shared classes cache.
35  */
36 public class CDSBundleFile extends BundleFileWrapper {
37 	private final static String classFileExt = ".class"; //$NON-NLS-1$
38 	private final URL url; // the URL to the content of the real bundle file
39 	private SharedClassURLHelper urlHelper; // the url helper set by the classloader
40 	private boolean primed = false;
41 
42 	/**
43 	 * The constructor
44 	 * @param wrapped the real bundle file
45 	 */
CDSBundleFile(BundleFile wrapped)46 	public CDSBundleFile(BundleFile wrapped) {
47 		super(wrapped);
48 		// get the url to the content of the real bundle file
49 		URL content = null;
50 		try {
51 			content = new URL("file", "", wrapped.getBaseFile().getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$
52 		} catch (MalformedURLException e) {
53 			// do nothing
54 		}
55 		this.url = content;
56 	}
57 
CDSBundleFile(BundleFile bundleFile, SharedClassURLHelper urlHelper)58 	public CDSBundleFile(BundleFile bundleFile, SharedClassURLHelper urlHelper) {
59 		this(bundleFile);
60 		this.urlHelper = urlHelper;
61 	}
62 
63 	/*
64 	 * (non-Javadoc)
65 	 * @see org.eclipse.osgi.storage.bundlefile.BundleFile#getEntry(java.lang.String)
66 	 *
67 	 * If path is not for a class then just use the wrapped bundle file to answer the call.
68 	 * If the path is for a class, it returns a CDSBundleEntry object.
69 	 * If the path is for a class, it will look for the magic cookie in the
70 	 * shared classes cache. If found, the bytes representing the magic cookie are stored in CDSBundleEntry object.
71 	 */
72 	@Override
getEntry(String path)73 	public BundleEntry getEntry(String path) {
74 		if (!primed || !path.endsWith(classFileExt)) {
75 			return super.getEntry(path);
76 		}
77 		byte[] classbytes = getClassBytes(path.substring(0, path.length() - classFileExt.length()));
78 		if (classbytes == null) {
79 			return super.getEntry(path);
80 		}
81 
82 		BundleEntry be = new CDSBundleEntry(path, classbytes, this);
83 		return be;
84 	}
85 
getWrappedEntry(String path)86 	BundleEntry getWrappedEntry(String path) {
87 		return super.getEntry(path);
88 	}
89 
90 	/**
91 	 * Returns the file url to the content of the actual bundle file
92 	 * @return the file url to the content of the actual bundle file
93 	 */
getURL()94 	URL getURL() {
95 		return url;
96 	}
97 
98 	/**
99 	 * Returns the url helper for this bundle file.  This is set by the
100 	 * class loading hook
101 	 * @return the url helper for this bundle file
102 	 */
getURLHelper()103 	SharedClassURLHelper getURLHelper() {
104 		return urlHelper;
105 	}
106 
107 	/**
108 	 * Sets the url helper for this bundle file.  This is called by the
109 	 * class loading hook.
110 	 * @param urlHelper the url helper
111 	 */
setURLHelper(SharedClassURLHelper urlHelper)112 	void setURLHelper(SharedClassURLHelper urlHelper) {
113 		this.urlHelper = urlHelper;
114 		this.primed = false; // always unprime when a new urlHelper is set
115 	}
116 
117 	/**
118 	 * Sets the primed flag for the bundle file.  This is called by the
119 	 * class loading hook after the first class has been loaded from disk for
120 	 * this bundle file.
121 	 * @param primed the primed flag
122 	 */
setPrimed(boolean primed)123 	void setPrimed(boolean primed) {
124 		this.primed = primed;
125 	}
126 
127 	/**
128 	 * Searches in the shared classes cache for the specified class name.
129 	 * @param name the name of the class
130 	 * @return the magic cookie to the shared class or null if the class is not in the cache.
131 	 */
getClassBytes(String name)132 	private byte[] getClassBytes(String name) {
133 		if (urlHelper == null || url == null)
134 			return null;
135 		return urlHelper.findSharedClass(null, url, name);
136 	}
137 
138 	/**
139 	 * Returns the primed flag for this bundle file.
140 	 * @return the primed flag
141 	 */
getPrimed()142 	public boolean getPrimed() {
143 		return this.primed;
144 	}
145 }
146