1 /*******************************************************************************
2  * Copyright (c) 2007, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.equinox.internal.frameworkadmin.utils;
15 
16 import java.io.File;
17 import java.io.IOException;
18 import java.net.URI;
19 import java.util.*;
20 import org.eclipse.equinox.frameworkadmin.BundleInfo;
21 import org.eclipse.equinox.internal.provisional.frameworkadmin.*;
22 import org.osgi.framework.Constants;
23 
24 /**
25  * This implementation of BundlesState doesn't support any of - resolving
26  * bundles, - retrieving fw persistent data.
27  *
28  * This implementation can be used for those cases.
29  */
30 public class SimpleBundlesState implements BundlesState {
31 	public static final BundleInfo[] NULL_BUNDLEINFOS = new BundleInfo[0];
32 
33 	/**
34 	 * Check if the specified FrameworkAdmin is available.
35 	 *
36 	 * @param fwAdmin
37 	 * @throws FrameworkAdminRuntimeException
38 	 */
checkAvailability(FrameworkAdmin fwAdmin)39 	public static void checkAvailability(FrameworkAdmin fwAdmin) throws FrameworkAdminRuntimeException {
40 		if (!fwAdmin.isActive())
41 			throw new FrameworkAdminRuntimeException("FrameworkAdmin creates this object is no more available.", //$NON-NLS-1$
42 					FrameworkAdminRuntimeException.FRAMEWORKADMIN_UNAVAILABLE);
43 	}
44 
45 	/**
46 	 *
47 	 * @param launcherData
48 	 * @return File of fwJar to be used.
49 	 * @throws IOException
50 	 */
getFwJar(LauncherData launcherData)51 	static File getFwJar(LauncherData launcherData) {
52 		if (launcherData.getFwJar() != null)
53 			return launcherData.getFwJar();
54 		return null;
55 	}
56 
57 	private final String systemBundleSymbolicName;
58 
59 	private final String systemBundleName;
60 
61 	private final String systemBundleVendor;
62 	List<BundleInfo> bundleInfosList = new LinkedList<>();
63 
64 	FrameworkAdmin fwAdmin = null;
65 
66 	Manipulator manipulator = null;
67 
68 	/**
69 	 * If the manifest of the target fw implementation has
70 	 * Constants.BUNDLE_SYMBOLICNAME header, this constructor should be used.
71 	 *
72 	 * @param ManipulatorAdmin
73 	 * @param Manipulator
74 	 * @param systemBundleSymbolicName
75 	 */
SimpleBundlesState(FrameworkAdmin ManipulatorAdmin, Manipulator Manipulator, String systemBundleSymbolicName)76 	public SimpleBundlesState(FrameworkAdmin ManipulatorAdmin, Manipulator Manipulator,
77 			String systemBundleSymbolicName) {
78 		super();
79 		this.fwAdmin = ManipulatorAdmin;
80 		// copy Manipulator object for avoiding modifying the parameters of the
81 		// Manipulator.
82 		this.manipulator = ManipulatorAdmin.getManipulator();
83 		this.manipulator.setConfigData(Manipulator.getConfigData());
84 		this.manipulator.setLauncherData(Manipulator.getLauncherData());
85 		this.systemBundleSymbolicName = systemBundleSymbolicName;
86 		this.systemBundleName = null;
87 		this.systemBundleVendor = null;
88 		initialize();
89 	}
90 
91 	/**
92 	 * If the manifest of the target fw implementation has not
93 	 * Constants.BUNDLE_SYMBOLICNAME header but , Constants.BUNDLE_NAME and
94 	 * BUNDLE_VERSION, this constructor should be used.
95 	 *
96 	 * @param ManipulatorAdmin
97 	 * @param Manipulator
98 	 * @param systemBundleName
99 	 * @param systemBundleVender
100 	 */
SimpleBundlesState(FrameworkAdmin ManipulatorAdmin, Manipulator Manipulator, String systemBundleName, String systemBundleVender)101 	public SimpleBundlesState(FrameworkAdmin ManipulatorAdmin, Manipulator Manipulator, String systemBundleName,
102 			String systemBundleVender) {
103 		super();
104 		this.fwAdmin = ManipulatorAdmin;
105 		// copy Manipulator object for avoiding modifying the parameters of the
106 		// Manipulator.
107 		this.manipulator = ManipulatorAdmin.getManipulator();
108 		this.manipulator.setConfigData(Manipulator.getConfigData());
109 		this.manipulator.setLauncherData(Manipulator.getLauncherData());
110 		this.systemBundleSymbolicName = null;
111 		this.systemBundleName = systemBundleName;
112 		this.systemBundleVendor = systemBundleVender;
113 		initialize();
114 	}
115 
116 	@Override
getExpectedState()117 	public BundleInfo[] getExpectedState() throws FrameworkAdminRuntimeException {
118 		if (!fwAdmin.isActive())
119 			throw new FrameworkAdminRuntimeException("FrameworkAdmin creates this object is no more available.", //$NON-NLS-1$
120 					FrameworkAdminRuntimeException.FRAMEWORKADMIN_UNAVAILABLE);
121 		return Utils.getBundleInfosFromList(this.bundleInfosList);
122 	}
123 
124 	/*
125 	 * Just return required bundles.
126 	 *
127 	 * @see org.eclipse.equinox.internal.provisional.frameworkadmin.BundlesState#
128 	 * getPrerequisteBundles(org.eclipse.equinox.internal.provisional.frameworkadmin
129 	 * .BundleInfo)
130 	 */
131 	@Override
getPrerequisteBundles(BundleInfo bInfo)132 	public BundleInfo[] getPrerequisteBundles(BundleInfo bInfo) {
133 		URI location = bInfo.getLocation();
134 		final String requiredBundles = Utils.getManifestMainAttributes(location, Constants.REQUIRE_BUNDLE);
135 		if (requiredBundles == null)
136 			return new BundleInfo[] { this.getSystemBundle() };
137 
138 		String[] clauses = Utils.getClauses(requiredBundles);
139 		List<String> list = new LinkedList<>();
140 		for (String clause : clauses)
141 			list.add(Utils.getPathFromClause(clause));
142 
143 		List<BundleInfo> ret = new LinkedList<>();
144 		ret.add(this.getSystemBundle());
145 		for (BundleInfo currentBInfo : this.bundleInfosList) {
146 			URI currentLocation = currentBInfo.getLocation();
147 			String currentSymbolicName = Utils.getManifestMainAttributes(currentLocation,
148 					Constants.BUNDLE_SYMBOLICNAME);
149 			if (currentSymbolicName == null)
150 				continue;
151 			currentSymbolicName = Utils.getPathFromClause(currentSymbolicName);
152 			for (String symbolicName : list) {
153 				if (symbolicName.equals(currentSymbolicName)) {
154 					ret.add(currentBInfo);
155 					break;
156 				}
157 			}
158 		}
159 		return Utils.getBundleInfosFromList(ret);
160 	}
161 
162 	@Override
getSystemBundle()163 	public BundleInfo getSystemBundle() {
164 		if (this.systemBundleSymbolicName == null) {
165 			for (BundleInfo bInfo : this.bundleInfosList) {
166 				// if (bInfo.getStartLevel() != 1)
167 				// return null;;
168 				URI location = bInfo.getLocation();
169 				String bundleName = Utils.getManifestMainAttributes(location, Constants.BUNDLE_NAME);
170 				if (systemBundleName.equals(bundleName)) {
171 					String bundleVendor = Utils.getManifestMainAttributes(location, Constants.BUNDLE_VENDOR);
172 					if (systemBundleVendor.equals(bundleVendor))
173 						return bInfo;
174 				}
175 			}
176 			return null;
177 		}
178 		for (BundleInfo bInfo : this.bundleInfosList) {
179 			URI location = bInfo.getLocation();
180 			String symbolicName = Utils.getManifestMainAttributes(location, Constants.BUNDLE_SYMBOLICNAME);
181 			symbolicName = Utils.getPathFromClause(symbolicName);
182 			if (this.systemBundleSymbolicName.equals(symbolicName))
183 				return bInfo;
184 		}
185 		return null;
186 	}
187 
188 	@Override
189 	@SuppressWarnings("unchecked")
getSystemFragmentedBundles()190 	public BundleInfo[] getSystemFragmentedBundles() {
191 		BundleInfo systemBInfo = this.getSystemBundle();
192 		if (systemBInfo == null)
193 			return NULL_BUNDLEINFOS;
194 
195 		@SuppressWarnings("rawtypes")
196 		List list = new LinkedList();
197 		for (BundleInfo bInfo : this.bundleInfosList) {
198 			URI location = bInfo.getLocation();
199 			String manifestVersion = Utils.getManifestMainAttributes(location, Constants.BUNDLE_MANIFESTVERSION);
200 			if (manifestVersion == null)
201 				continue;
202 			if (manifestVersion.equals("1") || manifestVersion.equals("1.0")) //$NON-NLS-1$//$NON-NLS-2$
203 				continue;
204 
205 			String fragmentHost = Utils.getManifestMainAttributes(location, Constants.FRAGMENT_HOST);
206 			if (fragmentHost == null)
207 				continue;
208 			int index = fragmentHost.indexOf(";"); //$NON-NLS-1$
209 			if (index == -1)
210 				continue;
211 			String symbolicName = fragmentHost.substring(0, index).trim();
212 			String parameter = fragmentHost.substring(index + 1).trim();
213 			// TODO What to do ,in case of alias name of system bundle is not used ?
214 			if (symbolicName.equals(Constants.SYSTEM_BUNDLE_SYMBOLICNAME))
215 				if (parameter.equals(Constants.EXTENSION_DIRECTIVE + ":=" + Constants.EXTENSION_FRAMEWORK)) { //$NON-NLS-1$
216 					list.add(location);
217 					break;
218 				}
219 		}
220 		return Utils.getBundleInfosFromList(list);
221 	}
222 
223 	@Override
getUnsatisfiedConstraints(BundleInfo bInfo)224 	public String[] getUnsatisfiedConstraints(BundleInfo bInfo) throws FrameworkAdminRuntimeException {
225 		throw new FrameworkAdminRuntimeException(
226 				"getUnsatisfiedConstraints(BundleInfo bInfo) is not supported in this implementation", //$NON-NLS-1$
227 				FrameworkAdminRuntimeException.UNSUPPORTED_OPERATION);
228 	}
229 
initialize()230 	private void initialize() {
231 		this.bundleInfosList.clear();
232 		LauncherData launcherData = manipulator.getLauncherData();
233 		ConfigData configData = manipulator.getConfigData();
234 		File fwJar = getFwJar(launcherData);
235 
236 		if (fwJar == null)
237 			throw new IllegalStateException("launcherData.getLauncherConfigFile() == null && fwJar is not set."); //$NON-NLS-1$
238 		// No fw persistent data location is taken into consideration.
239 
240 		BundleInfo[] bInfos = configData.getBundles();
241 		for (BundleInfo bInfo : bInfos)
242 			this.installBundle(bInfo);
243 
244 		if (getSystemBundle() == null) {
245 			BundleInfo sysBInfo = new BundleInfo(launcherData.getFwJar().toURI(), 0, true);
246 			sysBInfo.setBundleId(0);
247 			this.installBundle(sysBInfo);
248 		}
249 	}
250 
251 	@Override
installBundle(BundleInfo bInfo)252 	public void installBundle(BundleInfo bInfo) throws FrameworkAdminRuntimeException {
253 
254 		URI newLocation = bInfo.getLocation();
255 		Dictionary<String, String> newManifest = Utils.getOSGiManifest(newLocation);
256 		if (newManifest == null) {
257 			// TODO log something here
258 			return;
259 		}
260 		String newSymbolicName = newManifest.get(Constants.BUNDLE_SYMBOLICNAME);
261 		String newVersion = newManifest.get(Constants.BUNDLE_VERSION);
262 		// System.out.println("> currentInstalledBundles.length=" +
263 		// currentInstalledBundles.length);
264 		boolean found = false;
265 		for (BundleInfo currentBInfo : this.bundleInfosList) {
266 			URI location = currentBInfo.getLocation();
267 			if (newLocation.equals(location)) {
268 				found = true;
269 				break;
270 			}
271 			Dictionary<String, String> manifest = Utils.getOSGiManifest(location);
272 			String symbolicName = manifest.get(Constants.BUNDLE_SYMBOLICNAME);
273 			String version = manifest.get(Constants.BUNDLE_VERSION);
274 			if (newSymbolicName != null && newVersion != null)
275 				if (newSymbolicName.equals(symbolicName) && newVersion.equals(version)) {
276 					found = true;
277 					break;
278 				}
279 		}
280 		if (!found) {
281 			this.bundleInfosList.add(bInfo);
282 		}
283 	}
284 
285 	// public String toString() {
286 	// if (state == null)
287 	// return null;
288 	// StringBuffer sb = new StringBuffer();
289 	// BundleDescription[] bundleDescriptions = state.getBundles();
290 	// for (int i = 0; i < bundleDescriptions.length; i++) {
291 	// sb.append(bundleDescriptions[i].getBundleId() + ":");
292 	// sb.append(bundleDescriptions[i].toString() + "(");
293 	// sb.append(bundleDescriptions[i].isResolved() + ")");
294 	// String[] ees = bundleDescriptions[i].getExecutionEnvironments();
295 	// for (int j = 0; j < ees.length; j++)
296 	// sb.append(ees[j] + " ");
297 	// sb.append("\n");
298 	// }
299 	// sb.append("PlatformProperties:\n");
300 	// Dictionary[] dics = state.getPlatformProperties();
301 	// for (int i = 0; i < dics.length; i++) {
302 	// for (Enumeration enum = dics[i].keys(); enum.hasMoreElements();) {
303 	// String key = (String) enum.nextElement();
304 	// String value = (String) dics[i].get(key);
305 	// sb.append(" (" + key + "," + value + ")\n");
306 	// }
307 	// }
308 	// sb.append("\n");
309 	// return sb.toString();
310 	// }
311 
312 	@Override
isFullySupported()313 	public boolean isFullySupported() {
314 		return false;
315 	}
316 
317 	@Override
isResolved()318 	public boolean isResolved() throws FrameworkAdminRuntimeException {
319 		throw new FrameworkAdminRuntimeException("isResolved() is not supported in this implementation", //$NON-NLS-1$
320 				FrameworkAdminRuntimeException.UNSUPPORTED_OPERATION);
321 	}
322 
323 	@Override
isResolved(BundleInfo bInfo)324 	public boolean isResolved(BundleInfo bInfo) throws FrameworkAdminRuntimeException {
325 		throw new FrameworkAdminRuntimeException("isResolved(BundleInfo bInfo) is not supported in this implementation", //$NON-NLS-1$
326 				FrameworkAdminRuntimeException.UNSUPPORTED_OPERATION);
327 	}
328 
329 	@Override
resolve(boolean increment)330 	public void resolve(boolean increment) throws FrameworkAdminRuntimeException {
331 		throw new FrameworkAdminRuntimeException("resolve(boolean increment) is not supported in this implementation", //$NON-NLS-1$
332 				FrameworkAdminRuntimeException.UNSUPPORTED_OPERATION);
333 	}
334 
335 	@Override
uninstallBundle(BundleInfo bInfo)336 	public void uninstallBundle(BundleInfo bInfo) throws FrameworkAdminRuntimeException {
337 		URI targetLocation = bInfo.getLocation();
338 		int index = -1;
339 		for (BundleInfo currentBInfo : this.bundleInfosList) {
340 			index++;
341 			URI location = currentBInfo.getLocation();
342 			if (targetLocation.equals(location)) {
343 				break;
344 			}
345 		}
346 		if (index != -1)
347 			this.bundleInfosList.remove(index);
348 	}
349 
350 }
351