1 /*******************************************************************************
2  * Copyright (c) 2008, 2017 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.pde.internal.build.site;
15 
16 import java.io.*;
17 import java.net.*;
18 import java.util.*;
19 import org.eclipse.equinox.frameworkadmin.BundleInfo;
20 import org.eclipse.equinox.internal.p2.publisher.eclipse.ProductFile;
21 import org.eclipse.equinox.simpleconfigurator.manipulator.SimpleConfiguratorManipulator;
22 import org.eclipse.osgi.service.resolver.BundleDescription;
23 import org.eclipse.pde.internal.build.*;
24 
25 /**
26  * Temporary utilities until P2 and FrameworkAdmin are graduated into the SDK.
27  *
28  * @since 3.4
29  */
30 public class P2Utils {
31 
32 	/**
33 	 * Returns bundles defined by the 'bundles.info' file in the
34 	 * specified location, or <code>null</code> if none. The "bundles.info" file
35 	 * is assumed to be at a fixed relative location to the specified file.  This
36 	 * method will also look for a "source.info".  If available, any source
37 	 * bundles found will also be added to the returned list.
38 	 *
39 	 * @param platformHome absolute path in the local file system to an installation
40 	 * @return URLs of all bundles in the installation or <code>null</code> if not able
41 	 * 	to locate a bundles.info
42 	 */
readBundlesTxt(String platformHome)43 	public static URL[] readBundlesTxt(String platformHome) {
44 		SimpleConfiguratorManipulator manipulator = BundleHelper.getDefault().acquireService(SimpleConfiguratorManipulator.class);
45 
46 		File root = new File(platformHome);
47 		File bundlesTxt = new File(root, "configuration/" + SimpleConfiguratorManipulator.BUNDLES_INFO_PATH); //$NON-NLS-1$
48 		File sourceTxt = new File(root, "configuration/" + SimpleConfiguratorManipulator.SOURCE_INFO_PATH); //$NON-NLS-1$
49 
50 		List<BundleInfo> infos = new ArrayList<>();
51 		try {
52 			//streams are closed for us
53 			if (bundlesTxt.exists())
54 				infos.addAll(Arrays.asList(manipulator.loadConfiguration(new FileInputStream(bundlesTxt), root.toURI())));
55 			if (sourceTxt.exists())
56 				infos.addAll(Arrays.asList(manipulator.loadConfiguration(new FileInputStream(sourceTxt), root.toURI())));
57 		} catch (MalformedURLException e) {
58 			// TODO Auto-generated catch block
59 			e.printStackTrace();
60 		} catch (IOException e) {
61 			// TODO Auto-generated catch block
62 			e.printStackTrace();
63 		}
64 
65 		URL[] bundles = null;
66 		if (infos.size() > 0) {
67 			bundles = new URL[infos.size()];
68 			for (int i = 0; i < bundles.length; i++) {
69 				try {
70 					bundles[i] = new File(infos.get(i).getLocation()).toURL();
71 				} catch (MalformedURLException e) {
72 					// TODO Auto-generated catch block
73 					e.printStackTrace();
74 				}
75 			}
76 		} else {
77 			bundles = new URL[0];
78 		}
79 		return bundles;
80 	}
81 
82 	/**
83 	 * Creates a bundles.info file in the given directory containing the name,
84 	 * version, location, start level and expected state of every bundle in the
85 	 * given collection.  Will also create a source.info file containing
86 	 * a lsit of all source bundles found in the given collection. Uses special
87 	 * defaults for the start level and auto start settings. Returns the URL
88 	 * location of the bundle.txt or <code>null</code> if there was a problem
89 	 * creating it.
90 	 *
91 	 * @param bundles collection of IPluginModelBase objects to write into the bundles.info/source.info
92 	 * @param directory directory to create the bundles.info and source.info files in
93 	 * @return URL location of the bundles.info or <code>null</code>
94 	 */
writeBundlesTxt(Collection<BundleDescription> bundles, File directory, ProductFile productFile, boolean refactoredRuntime)95 	public static File writeBundlesTxt(Collection<BundleDescription> bundles, File directory, ProductFile productFile, boolean refactoredRuntime) {
96 		List<BundleInfo> bundleInfos = new ArrayList<>(bundles.size());
97 		List<BundleInfo> sourceInfos = new ArrayList<>(bundles.size());
98 		ShapeAdvisor advisor = new ShapeAdvisor();
99 
100 		int defaultStartLevel = 4;
101 		Properties props = productFile != null ? productFile.getConfigProperties() : null;
102 		if (props != null && props.containsKey("osgi.bundles.defaultStartLevel")) { //$NON-NLS-1$
103 			try {
104 				defaultStartLevel = Integer.parseInt(props.getProperty("osgi.bundles.defaultStartLevel")); //$NON-NLS-1$
105 			} catch (NumberFormatException e) {
106 				//ignore and keep 4
107 			}
108 		}
109 
110 		Map<String, BundleInfo> userInfos = productFile != null ? productFile.getConfigurationInfo() : null;
111 
112 		for (Iterator<BundleDescription> iterator = bundles.iterator(); iterator.hasNext();) {
113 			BundleDescription desc = iterator.next();
114 			if (desc != null) {
115 				String modelName = desc.getSymbolicName();
116 
117 				URI location = null;
118 				try {
119 					location = new URI("plugins/" + (String) advisor.getFinalShape(desc)[0]); //$NON-NLS-1$
120 				} catch (URISyntaxException e) {
121 					continue;
122 				}
123 				BundleInfo info = new BundleInfo();
124 				info.setLocation(location);
125 				info.setSymbolicName(modelName);
126 				info.setVersion(desc.getVersion().toString());
127 				if (userInfos != null && userInfos.size() > 0) {
128 					if (userInfos.containsKey(modelName)) {
129 						BundleInfo userInfo = userInfos.get(modelName);
130 						int start = userInfo.getStartLevel();
131 						if (start <= 0)
132 							start = defaultStartLevel;
133 						info.setStartLevel(start);
134 						info.setMarkedAsStarted(userInfo.isMarkedAsStarted());
135 					} else {
136 						info.setStartLevel(defaultStartLevel);
137 						info.setMarkedAsStarted(false);
138 					}
139 				} else {
140 					if (IPDEBuildConstants.BUNDLE_SIMPLE_CONFIGURATOR.equals(modelName)) {
141 						info.setStartLevel(1);
142 						info.setMarkedAsStarted(true);
143 					} else if (IPDEBuildConstants.BUNDLE_EQUINOX_COMMON.equals(modelName)) {
144 						info.setStartLevel(2);
145 						info.setMarkedAsStarted(true);
146 					} else if (IPDEBuildConstants.BUNDLE_OSGI.equals(modelName)) {
147 						info.setStartLevel(-1);
148 						info.setMarkedAsStarted(true);
149 					} else if (IPDEBuildConstants.BUNDLE_CORE_RUNTIME.equals(modelName)) {
150 						info.setStartLevel(refactoredRuntime ? 4 : 2);
151 						info.setMarkedAsStarted(true);
152 					} else if (IPDEBuildConstants.BUNDLE_DS.equals(modelName)) {
153 						info.setStartLevel(2);
154 						info.setMarkedAsStarted(true);
155 					} else {
156 						info.setStartLevel(defaultStartLevel);
157 						info.setMarkedAsStarted(false);
158 					}
159 				}
160 				if (Utils.isSourceBundle(desc))
161 					sourceInfos.add(info);
162 				else
163 					bundleInfos.add(info);
164 			}
165 		}
166 
167 		File bundlesTxt = new File(directory, SimpleConfiguratorManipulator.BUNDLES_INFO_PATH);
168 		File srcBundlesTxt = new File(directory, SimpleConfiguratorManipulator.SOURCE_INFO_PATH);
169 		File base = directory.getParentFile();
170 
171 		BundleInfo[] infos = bundleInfos.toArray(new BundleInfo[bundleInfos.size()]);
172 		BundleInfo[] sources = sourceInfos.toArray(new BundleInfo[sourceInfos.size()]);
173 
174 		SimpleConfiguratorManipulator manipulator = BundleHelper.getDefault().acquireService(SimpleConfiguratorManipulator.class);
175 		try {
176 			manipulator.saveConfiguration(infos, bundlesTxt, base.toURI());
177 			manipulator.saveConfiguration(sources, srcBundlesTxt, base.toURI());
178 		} catch (IOException e) {
179 			return null;
180 		}
181 
182 		return bundlesTxt;
183 	}
184 }
185