001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.core;
011:
012: import java.io.File;
013: import java.io.FileInputStream;
014: import java.io.FileNotFoundException;
015: import java.io.IOException;
016: import java.io.InputStream;
017: import java.util.Dictionary;
018: import java.util.jar.JarFile;
019: import java.util.zip.ZipEntry;
020: import java.util.zip.ZipFile;
021:
022: import org.eclipse.core.runtime.CoreException;
023: import org.eclipse.core.runtime.IStatus;
024: import org.eclipse.core.runtime.MultiStatus;
025: import org.eclipse.core.runtime.Path;
026: import org.eclipse.core.runtime.Platform;
027: import org.eclipse.core.runtime.Status;
028: import org.eclipse.osgi.service.pluginconversion.PluginConversionException;
029: import org.eclipse.osgi.service.pluginconversion.PluginConverter;
030: import org.eclipse.osgi.service.resolver.BundleDescription;
031: import org.eclipse.osgi.service.resolver.BundleSpecification;
032: import org.eclipse.osgi.service.resolver.HostSpecification;
033: import org.eclipse.osgi.service.resolver.ImportPackageSpecification;
034: import org.eclipse.osgi.service.resolver.State;
035: import org.eclipse.osgi.service.resolver.StateDelta;
036: import org.eclipse.osgi.service.resolver.StateHelper;
037: import org.eclipse.osgi.service.resolver.StateObjectFactory;
038: import org.eclipse.osgi.service.resolver.VersionConstraint;
039: import org.eclipse.osgi.service.resolver.VersionRange;
040: import org.eclipse.osgi.util.ManifestElement;
041: import org.eclipse.pde.core.plugin.IPluginModelBase;
042: import org.eclipse.pde.internal.core.util.Headers;
043: import org.osgi.framework.BundleException;
044: import org.osgi.framework.Constants;
045: import org.osgi.util.tracker.ServiceTracker;
046:
047: public class MinimalState {
048:
049: protected State fState;
050:
051: protected long fId;
052:
053: private PluginConverter fConverter = null;
054:
055: private boolean fEEListChanged = false; // indicates that the EE has changed
056: // this could be due to the system bundle changing location
057: // or initially when the ee list is first created.
058:
059: private String[] fExecutionEnvironments; // an ordered list of known/supported execution environments
060:
061: private boolean fNoProfile;
062:
063: private static final String SYSTEM_BUNDLE = "org.eclipse.osgi"; //$NON-NLS-1$
064:
065: protected static boolean DEBUG = false;
066:
067: protected static StateObjectFactory stateObjectFactory;
068:
069: protected static String DIR;
070:
071: static {
072: DEBUG = PDECore.getDefault().isDebugging()
073: && "true".equals(Platform.getDebugOption("org.eclipse.pde.core/cache")); //$NON-NLS-1$ //$NON-NLS-2$
074: DIR = PDECore.getDefault().getStateLocation().toOSString();
075: stateObjectFactory = Platform.getPlatformAdmin().getFactory();
076: }
077:
078: protected MinimalState(MinimalState state) {
079: this .fState = stateObjectFactory.createState(state.fState);
080: this .fState.setPlatformProperties(state.fState
081: .getPlatformProperties());
082: this .fState.setResolver(Platform.getPlatformAdmin()
083: .getResolver());
084: this .fId = state.fId;
085: this .fEEListChanged = state.fEEListChanged;
086: this .fExecutionEnvironments = state.fExecutionEnvironments;
087: this .fNoProfile = state.fNoProfile;
088: }
089:
090: protected MinimalState() {
091: }
092:
093: public void addBundle(IPluginModelBase model, boolean update) {
094: if (model == null)
095: return;
096:
097: BundleDescription desc = model.getBundleDescription();
098: long bundleId = desc == null || !update ? -1 : desc
099: .getBundleId();
100: try {
101: model.setBundleDescription(addBundle(new File(model
102: .getInstallLocation()), bundleId));
103: } catch (IOException e) {
104: } catch (PluginConversionException e) {
105: } catch (CoreException e) {
106: PDECore.log(e);
107: }
108: }
109:
110: public BundleDescription addBundle(IPluginModelBase model,
111: long bundleId) {
112: try {
113: return addBundle(new File(model.getInstallLocation()), -1);
114: } catch (IOException e) {
115: } catch (PluginConversionException e) {
116: } catch (CoreException e) {
117: }
118: return null;
119: }
120:
121: public BundleDescription addBundle(Dictionary manifest,
122: File bundleLocation, long bundleId) {
123: try {
124: BundleDescription descriptor = stateObjectFactory
125: .createBundleDescription(fState, manifest,
126: bundleLocation.getAbsolutePath(),
127: bundleId == -1 ? getNextId() : bundleId);
128: // new bundle
129: if (bundleId == -1) {
130: fState.addBundle(descriptor);
131: } else if (!fState.updateBundle(descriptor)) {
132: fState.addBundle(descriptor);
133: }
134: return descriptor;
135: } catch (BundleException e) {
136: } catch (NumberFormatException e) {
137: } catch (IllegalArgumentException e) {
138: }
139: return null;
140: }
141:
142: public BundleDescription addBundle(File bundleLocation,
143: long bundleId) throws PluginConversionException,
144: CoreException, IOException {
145: Dictionary manifest = loadManifest(bundleLocation);
146: boolean hasBundleStructure = manifest != null
147: && manifest.get(Constants.BUNDLE_SYMBOLICNAME) != null;
148: if (!hasBundleStructure) {
149: if (!bundleLocation.isFile()
150: && !new File(bundleLocation, "plugin.xml").exists() //$NON-NLS-1$
151: && !new File(bundleLocation, "fragment.xml").exists()) //$NON-NLS-1$
152: return null;
153: PluginConverter converter = acquirePluginConverter();
154: manifest = converter.convertManifest(bundleLocation, false,
155: null, false, null);
156: if (manifest == null
157: || manifest.get(Constants.BUNDLE_SYMBOLICNAME) == null)
158: throw new CoreException(
159: new Status(
160: IStatus.ERROR,
161: PDECore.PLUGIN_ID,
162: IStatus.ERROR,
163: "Error parsing plug-in manifest file at " + bundleLocation.toString(), null)); //$NON-NLS-1$
164: }
165: BundleDescription desc = addBundle(manifest, bundleLocation,
166: bundleId);
167: if (desc != null
168: && SYSTEM_BUNDLE.equals(desc.getSymbolicName())) {
169: // if this is the system bundle then
170: // indicate that the javaProfile has changed since the new system
171: // bundle may not contain profiles for all EE's in the list
172: fEEListChanged = true;
173: }
174: if (desc != null) {
175: addAuxiliaryData(desc, manifest, hasBundleStructure);
176: }
177: return desc;
178: }
179:
180: protected void addAuxiliaryData(BundleDescription desc,
181: Dictionary manifest, boolean hasBundleStructure) {
182: }
183:
184: protected void saveState(File dir) {
185: saveState(fState, dir);
186: }
187:
188: protected void saveState(State state, File dir) {
189: try {
190: if (!dir.exists())
191: dir.mkdirs();
192: stateObjectFactory.writeState(state, dir);
193: } catch (FileNotFoundException e) {
194: PDECore.log(e);
195: } catch (IOException e) {
196: PDECore.log(e);
197: } finally {
198: }
199: }
200:
201: public static Dictionary loadManifest(File bundleLocation)
202: throws IOException {
203: ZipFile jarFile = null;
204: InputStream manifestStream = null;
205: try {
206: String extension = new Path(bundleLocation.getName())
207: .getFileExtension();
208: if (extension != null
209: && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
210: jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
211: ZipEntry manifestEntry = jarFile
212: .getEntry(JarFile.MANIFEST_NAME);
213: if (manifestEntry != null) {
214: manifestStream = jarFile
215: .getInputStream(manifestEntry);
216: }
217: } else {
218: File file = new File(bundleLocation,
219: JarFile.MANIFEST_NAME);
220: if (file.exists())
221: manifestStream = new FileInputStream(file);
222: }
223: } catch (IOException e) {
224: }
225: if (manifestStream == null)
226: return null;
227: try {
228: return (Dictionary) ManifestElement.parseBundleManifest(
229: manifestStream, new Headers(10));
230: } catch (BundleException e) {
231: } finally {
232: try {
233: if (jarFile != null)
234: jarFile.close();
235: } catch (IOException e2) {
236: }
237: }
238: return null;
239: }
240:
241: public StateDelta resolveState(boolean incremental) {
242: return internalResolveState(incremental);
243: }
244:
245: private synchronized StateDelta internalResolveState(
246: boolean incremental) {
247: boolean fullBuildRequired = initializePlatformProperties();
248: return fState.resolve(incremental && !fullBuildRequired);
249: }
250:
251: protected boolean initializePlatformProperties() {
252: if (fExecutionEnvironments == null && !fNoProfile)
253: setExecutionEnvironments();
254:
255: if (fEEListChanged) {
256: fEEListChanged = false;
257: return fState
258: .setPlatformProperties(getProfilePlatformProperties());
259: }
260: return false;
261: }
262:
263: private Dictionary[] getProfilePlatformProperties() {
264: return TargetPlatformHelper.getPlatformProperties(
265: fExecutionEnvironments, this );
266: }
267:
268: public void removeBundleDescription(BundleDescription description) {
269: if (description != null)
270: fState.removeBundle(description);
271: }
272:
273: public State getState() {
274: return fState;
275: }
276:
277: private void setExecutionEnvironments() {
278: String[] knownExecutionEnviroments = TargetPlatformHelper
279: .getKnownExecutionEnvironments();
280: if (knownExecutionEnviroments.length == 0) {
281: String jreProfile = System.getProperty("pde.jreProfile"); //$NON-NLS-1$
282: if (jreProfile != null && jreProfile.length() > 0)
283: if ("none".equals(jreProfile)) //$NON-NLS-1$
284: fNoProfile = true;
285: }
286: if (!fNoProfile) {
287: fExecutionEnvironments = knownExecutionEnviroments;
288: }
289: fEEListChanged = true; // alway indicate the list has changed
290: }
291:
292: public void addBundleDescription(BundleDescription toAdd) {
293: if (toAdd != null)
294: fState.addBundle(toAdd);
295: }
296:
297: private PluginConverter acquirePluginConverter() {
298: if (fConverter == null) {
299: ServiceTracker tracker = new ServiceTracker(PDECore
300: .getDefault().getBundleContext(),
301: PluginConverter.class.getName(), null);
302: tracker.open();
303: fConverter = (PluginConverter) tracker.getService();
304: tracker.close();
305: }
306: return fConverter;
307: }
308:
309: public long getNextId() {
310: return ++fId;
311: }
312:
313: private BundleDescription findActiveBundle(String symbolicName) {
314: BundleDescription[] bundles = fState.getBundles(symbolicName);
315: for (int i = 0; i < bundles.length; i++) {
316: if (bundles[i].isResolved())
317: return bundles[i];
318: }
319: return null;
320: }
321:
322: protected void logResolutionErrors() {
323: MultiStatus errors = new MultiStatus(
324: PDECore.PLUGIN_ID,
325: 1,
326: "Problems occurred during the resolution of the target platform", //$NON-NLS-1$
327: null);
328:
329: StateHelper helper = Platform.getPlatformAdmin()
330: .getStateHelper();
331: BundleDescription[] all = fState.getBundles();
332: for (int i = 0; i < all.length; i++) {
333: if (!all[i].isResolved()) {
334: VersionConstraint[] unsatisfiedConstraints = helper
335: .getUnsatisfiedConstraints(all[i]);
336: if (unsatisfiedConstraints.length == 0) {
337: if (DEBUG) {
338: BundleDescription activeBundle = findActiveBundle(all[i]
339: .getSymbolicName());
340: String message = "Plug-in located at \"" + all[i].getLocation() + "\" was disabled because plug-in located at \"" + activeBundle.getLocation() + "\" was selected."; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
341: System.out.print(message);
342: }
343: } else {
344: for (int j = 0; j < unsatisfiedConstraints.length; j++) {
345: String message = getResolutionFailureMessage(unsatisfiedConstraints[j]);
346: if (message != null)
347: errors.add(new Status(IStatus.WARNING,
348: all[i].getSymbolicName(),
349: IStatus.WARNING, message, null));
350: }
351: }
352: }
353: }
354: if (errors.getChildren().length > 0)
355: PDECore.log(errors);
356: }
357:
358: private String getResolutionFailureMessage(
359: VersionConstraint unsatisfied) {
360: if (unsatisfied.isResolved())
361: throw new IllegalArgumentException();
362: if (unsatisfied instanceof ImportPackageSpecification)
363: return "Missing imported package: " + toString(unsatisfied); //$NON-NLS-1$
364: if (unsatisfied instanceof BundleSpecification
365: && !((BundleSpecification) unsatisfied).isOptional())
366: return "Missing required plug-in: " + toString(unsatisfied); //$NON-NLS-1$
367: if (unsatisfied instanceof HostSpecification)
368: return "Missing Fragment Host: " + toString(unsatisfied); //$NON-NLS-1$
369: return null;
370: }
371:
372: private String toString(VersionConstraint constraint) {
373: VersionRange versionRange = constraint.getVersionRange();
374: if (versionRange == null || versionRange.getMinimum() != null)
375: return constraint.getName();
376: return constraint.getName() + '_' + versionRange;
377: }
378:
379: }
|