1 /*******************************************************************************
2  *  Copyright (c) 2003, 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.core.bundle;
15 
16 import java.io.PrintWriter;
17 import java.io.Serializable;
18 import java.util.ArrayList;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.core.runtime.IStatus;
21 import org.eclipse.core.runtime.PlatformObject;
22 import org.eclipse.core.runtime.Status;
23 import org.eclipse.osgi.service.resolver.BundleDescription;
24 import org.eclipse.osgi.service.resolver.BundleSpecification;
25 import org.eclipse.osgi.util.ManifestElement;
26 import org.eclipse.pde.core.IIdentifiable;
27 import org.eclipse.pde.core.IModelChangedEvent;
28 import org.eclipse.pde.core.ModelChangedEvent;
29 import org.eclipse.pde.core.plugin.IExtensions;
30 import org.eclipse.pde.core.plugin.IPluginBase;
31 import org.eclipse.pde.core.plugin.IPluginExtension;
32 import org.eclipse.pde.core.plugin.IPluginExtensionPoint;
33 import org.eclipse.pde.core.plugin.IPluginImport;
34 import org.eclipse.pde.core.plugin.IPluginLibrary;
35 import org.eclipse.pde.core.plugin.IPluginModelBase;
36 import org.eclipse.pde.core.plugin.IPluginObject;
37 import org.eclipse.pde.core.plugin.ISharedExtensionsModel;
38 import org.eclipse.pde.core.plugin.ISharedPluginModel;
39 import org.eclipse.pde.internal.core.ICoreConstants;
40 import org.eclipse.pde.internal.core.PDECore;
41 import org.eclipse.pde.internal.core.PDECoreMessages;
42 import org.eclipse.pde.internal.core.TargetPlatformHelper;
43 import org.eclipse.pde.internal.core.ibundle.IBundle;
44 import org.eclipse.pde.internal.core.ibundle.IBundleModel;
45 import org.eclipse.pde.internal.core.ibundle.IBundlePluginBase;
46 import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
47 import org.eclipse.pde.internal.core.ibundle.IManifestHeader;
48 import org.eclipse.pde.internal.core.plugin.AbstractExtensions;
49 import org.eclipse.pde.internal.core.plugin.PluginBase;
50 import org.eclipse.pde.internal.core.plugin.PluginImport;
51 import org.eclipse.pde.internal.core.plugin.PluginLibrary;
52 import org.eclipse.pde.internal.core.text.bundle.BundleClasspathHeader;
53 import org.eclipse.pde.internal.core.text.bundle.BundleNameHeader;
54 import org.eclipse.pde.internal.core.text.bundle.BundleSymbolicNameHeader;
55 import org.eclipse.pde.internal.core.text.bundle.BundleVendorHeader;
56 import org.eclipse.pde.internal.core.text.bundle.BundleVersionHeader;
57 import org.eclipse.pde.internal.core.text.bundle.RequireBundleHeader;
58 import org.osgi.framework.BundleException;
59 import org.osgi.framework.Constants;
60 import org.osgi.framework.Version;
61 
62 public class BundlePluginBase extends PlatformObject implements IBundlePluginBase, Serializable {
63 
64 	private static final long serialVersionUID = 1L;
65 	protected IBundlePluginModelBase model;
66 	private ArrayList<IPluginLibrary> libraries;
67 	private ArrayList<IPluginImport> imports;
68 	private String fTarget;
69 
reset()70 	public void reset() {
71 		libraries = null;
72 		imports = null;
73 	}
74 
75 	@Override
getSchemaVersion()76 	public String getSchemaVersion() {
77 		IExtensions root = getExtensionsRoot();
78 		if (root instanceof AbstractExtensions) {
79 			return ((AbstractExtensions) root).getSchemaVersion();
80 		}
81 		return (root instanceof IPluginBase) ? ((IPluginBase) root).getSchemaVersion() : null;
82 	}
83 
84 	@Override
setSchemaVersion(String value)85 	public void setSchemaVersion(String value) throws CoreException {
86 		IExtensions root = getExtensionsRoot();
87 		if (root == null) {
88 			return;
89 		}
90 		if (root instanceof AbstractExtensions) {
91 			((AbstractExtensions) root).setSchemaVersion(value);
92 		}
93 		if (root instanceof IPluginBase) {
94 			((IPluginBase) root).setSchemaVersion(value);
95 		}
96 	}
97 
98 	@Override
modelChanged(IModelChangedEvent event)99 	public void modelChanged(IModelChangedEvent event) {
100 		if (event.getChangeType() == IModelChangedEvent.WORLD_CHANGED) {
101 			if (event.getChangeProvider().equals(model.getBundleModel())) {
102 				reset();
103 			}
104 			getModel().fireModelChanged(event);
105 		} else if (!event.getChangeProvider().equals(model.getBundleModel())) {
106 			getModel().fireModelChanged(event);
107 		}
108 	}
109 
getBundle()110 	public IBundle getBundle() {
111 		if (model != null) {
112 			IBundleModel bmodel = model.getBundleModel();
113 			return bmodel != null ? bmodel.getBundle() : null;
114 		}
115 		return null;
116 	}
117 
getManifestHeader(String key)118 	protected IManifestHeader getManifestHeader(String key) {
119 		IBundle bundle = getBundle();
120 		return (bundle != null) ? bundle.getManifestHeader(key) : null;
121 	}
122 
123 	@Override
getModel()124 	public ISharedPluginModel getModel() {
125 		return model;
126 	}
127 
setModel(IBundlePluginModelBase model)128 	void setModel(IBundlePluginModelBase model) {
129 		this.model = model;
130 	}
131 
getExtensionsRoot()132 	public IExtensions getExtensionsRoot() {
133 		if (model != null) {
134 			ISharedExtensionsModel emodel = model.getExtensionsModel();
135 			return emodel != null ? emodel.getExtensions() : null;
136 		}
137 		return null;
138 	}
139 
140 	@Override
add(IPluginLibrary library)141 	public void add(IPluginLibrary library) throws CoreException {
142 		ensureModelEditable();
143 		if (libraries == null) {
144 			// if libraries == null, initialize the libraries varible by calling getLibraries()
145 			getLibraries();
146 		}
147 		libraries.add(library);
148 		IManifestHeader header = getManifestHeader(Constants.BUNDLE_CLASSPATH);
149 		if (header instanceof BundleClasspathHeader) {
150 			((BundleClasspathHeader) header).addLibrary(library.getName());
151 		} else {
152 			addLibrary(library, header);
153 		}
154 		fireStructureChanged(library, true);
155 	}
156 
157 	/**
158 	 * @param library
159 	 * @param header
160 	 */
addLibrary(IPluginLibrary library, IManifestHeader header)161 	private void addLibrary(IPluginLibrary library, IManifestHeader header) {
162 		String value = header == null ? null : header.getValue();
163 		StringBuilder buffer = new StringBuilder(value == null ? "" : value); //$NON-NLS-1$
164 		if (value != null) {
165 			buffer.append(",\n "); //$NON-NLS-1$
166 		}
167 		buffer.append(library.getName());
168 		getBundle().setHeader(Constants.BUNDLE_CLASSPATH, buffer.toString());
169 	}
170 
171 	/**
172 	 * Removes the specified library from the given 'Bundle-Classpath' header.
173 	 *
174 	 * @param library library to remove
175 	 * @param header header to update
176 	 */
removeLibrary(IPluginLibrary library, IManifestHeader header)177 	private void removeLibrary(IPluginLibrary library, IManifestHeader header) {
178 		if (header == null) {
179 			return;
180 		}
181 		String value = header.getValue();
182 		String name = library.getName();
183 		int index = value.indexOf(name);
184 		if (index >= 0) {
185 			// copy up to the removed library
186 			StringBuilder buffer = new StringBuilder();
187 			for (int i = 0; i > index; i++) {
188 				buffer.append(value.charAt(i));
189 			}
190 			int after = index + name.length();
191 			// delete (skip) comma
192 			if (after < value.length()) {
193 				while (value.charAt(after) == ',') {
194 					after++;
195 				}
196 			}
197 			// delete (skip) whitespace
198 			if (after < value.length()) {
199 				while (Character.isWhitespace(value.charAt(after))) {
200 					after++;
201 				}
202 			}
203 			// keep everything else
204 			while (after < value.length()) {
205 				buffer.append(value.charAt(after));
206 				after++;
207 			}
208 			getBundle().setHeader(Constants.BUNDLE_CLASSPATH, buffer.toString());
209 		}
210 	}
211 
212 	@Override
remove(IPluginLibrary library)213 	public void remove(IPluginLibrary library) throws CoreException {
214 		ensureModelEditable();
215 		if (libraries != null) {
216 			libraries.remove(library);
217 			IManifestHeader header = getManifestHeader(Constants.BUNDLE_CLASSPATH);
218 			if (header instanceof BundleClasspathHeader) {
219 				((BundleClasspathHeader) header).removeLibrary(library.getName());
220 			} else if (header != null) {
221 				removeLibrary(library, header);
222 			}
223 			fireStructureChanged(library, false);
224 		}
225 	}
226 
227 	@Override
add(IPluginImport iimport)228 	public void add(IPluginImport iimport) throws CoreException {
229 		ensureModelEditable();
230 		if (iimport == null) {
231 			return;
232 		}
233 		if (imports == null) {
234 			// if imports == null, intitialize the imports list by calling getImports()
235 			getImports();
236 		}
237 		addImport(iimport);
238 		fireStructureChanged(iimport, true);
239 	}
240 
add(IPluginImport[] iimports)241 	public void add(IPluginImport[] iimports) throws CoreException {
242 		ensureModelEditable();
243 		if (iimports != null && iimports.length > 0) {
244 			if (imports == null) {
245 				// if imports == null, initialize the imports list by calling getImports()
246 				getImports();
247 			}
248 			for (IPluginImport pluginImport : iimports) {
249 				if (pluginImport != null) {
250 					addImport(pluginImport);
251 				}
252 			}
253 			fireStructureChanged(iimports, true);
254 		}
255 	}
256 
addImport(IPluginImport iimport)257 	private void addImport(IPluginImport iimport) {
258 		imports.add(iimport);
259 		Object header = getManifestHeader(Constants.REQUIRE_BUNDLE);
260 		if (header instanceof RequireBundleHeader) {
261 			((RequireBundleHeader) header).addBundle(iimport);
262 		} else {
263 			String value = header == null ? null : ((IManifestHeader) header).getValue();
264 			StringBuilder buffer = new StringBuilder(value == null ? "" : value); //$NON-NLS-1$
265 			if (value != null) {
266 				buffer.append(",\n "); //$NON-NLS-1$
267 			}
268 			buffer.append(iimport.getId());
269 			int bundleManifestVersion = getBundleManifestVersion(getBundle());
270 			if (iimport.isOptional()) {
271 				if (bundleManifestVersion > 1) {
272 					buffer.append(";" + Constants.RESOLUTION_DIRECTIVE + ":=" + Constants.RESOLUTION_OPTIONAL); //$NON-NLS-1$ //$NON-NLS-2$
273 				}
274 				else {
275 					buffer.append(";" + ICoreConstants.OPTIONAL_ATTRIBUTE + "=true"); //$NON-NLS-1$ //$NON-NLS-2$
276 				}
277 			}
278 			if (iimport.isReexported()) {
279 				if (bundleManifestVersion > 1) {
280 					buffer.append(";" + Constants.VISIBILITY_DIRECTIVE + ":=" + Constants.VISIBILITY_REEXPORT); //$NON-NLS-1$ //$NON-NLS-2$
281 				}
282 				else {
283 					buffer.append(";" + ICoreConstants.REPROVIDE_ATTRIBUTE + "=true"); //$NON-NLS-1$ //$NON-NLS-2$
284 				}
285 			}
286 			String version = iimport.getVersion();
287 			if (version != null && version.trim().length() > 0) {
288 				buffer.append(";" + Constants.BUNDLE_VERSION_ATTRIBUTE + "=\"" + version.trim() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
289 			}
290 			getBundle().setHeader(Constants.REQUIRE_BUNDLE, buffer.toString());
291 		}
292 	}
293 
294 	@Override
remove(IPluginImport pluginImport)295 	public void remove(IPluginImport pluginImport) throws CoreException {
296 		ensureModelEditable();
297 		if (imports != null) {
298 			imports.remove(pluginImport);
299 			Object header = getManifestHeader(Constants.REQUIRE_BUNDLE);
300 			if (header instanceof RequireBundleHeader) {
301 				((RequireBundleHeader) header).removeBundle(pluginImport.getId());
302 			}
303 			fireStructureChanged(pluginImport, false);
304 		}
305 	}
306 
remove(IPluginImport[] pluginImports)307 	public void remove(IPluginImport[] pluginImports) throws CoreException {
308 		ensureModelEditable();
309 		if (imports != null) {
310 			for (IPluginImport pluginImport : pluginImports) {
311 				imports.remove(pluginImport);
312 				Object header = getManifestHeader(Constants.REQUIRE_BUNDLE);
313 				if (header instanceof RequireBundleHeader) {
314 					((RequireBundleHeader) header).removeBundle(pluginImport.getId());
315 				}
316 			}
317 			fireStructureChanged(pluginImports, false);
318 		}
319 	}
320 
321 	@Override
getLibraries()322 	public IPluginLibrary[] getLibraries() {
323 		IBundle bundle = getBundle();
324 		if (bundle == null) {
325 			return new IPluginLibrary[0];
326 		}
327 		if (libraries == null) {
328 			libraries = new ArrayList<>();
329 			String value = bundle.getHeader(Constants.BUNDLE_CLASSPATH);
330 			if (value != null) {
331 				try {
332 					ManifestElement[] elements = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, value);
333 					for (ManifestElement element : elements) {
334 						PluginLibrary library = new PluginLibrary();
335 						library.setModel(getModel());
336 						library.setInTheModel(true);
337 						library.setParent(this);
338 						library.load(element.getValue());
339 						libraries.add(library);
340 					}
341 				} catch (BundleException e) {
342 				}
343 			}
344 		}
345 		return libraries.toArray(new IPluginLibrary[libraries.size()]);
346 	}
347 
348 	@Override
getImports()349 	public IPluginImport[] getImports() {
350 		if (imports == null) {
351 			imports = new ArrayList<>();
352 			BundleDescription description = model.getBundleDescription();
353 			if (description != null) {
354 				BundleSpecification[] required = description.getRequiredBundles();
355 				for (BundleSpecification element : required) {
356 					PluginImport importElement = new PluginImport();
357 					importElement.setModel(getModel());
358 					importElement.setInTheModel(true);
359 					importElement.setParent(this);
360 					imports.add(importElement);
361 					importElement.load(element);
362 				}
363 				BundleDescription[] imported = PluginBase.getImportedBundles(description);
364 				for (BundleDescription element : imported) {
365 					PluginImport importElement = new PluginImport();
366 					importElement.setModel(getModel());
367 					importElement.setInTheModel(true);
368 					importElement.setParent(this);
369 					imports.add(importElement);
370 					importElement.load(element);
371 				}
372 			} else {
373 				IBundle bundle = getBundle();
374 				if (bundle != null) {
375 					try {
376 						String value = bundle.getHeader(Constants.REQUIRE_BUNDLE);
377 						int bundleManifestVersion = getBundleManifestVersion(bundle);
378 						if (value != null) {
379 							ManifestElement[] elements = ManifestElement.parseHeader(Constants.REQUIRE_BUNDLE, value);
380 							for (ManifestElement element : elements) {
381 								PluginImport importElement = new PluginImport();
382 								importElement.setModel(getModel());
383 								importElement.setInTheModel(true);
384 								importElement.setParent(this);
385 								imports.add(importElement);
386 								importElement.load(element, bundleManifestVersion);
387 							}
388 						}
389 					} catch (BundleException e) {
390 					}
391 				}
392 			}
393 		}
394 		return imports.toArray(new IPluginImport[imports.size()]);
395 	}
396 
397 	@Override
getProviderName()398 	public String getProviderName() {
399 		IBundle bundle = getBundle();
400 		return bundle == null ? null : bundle.getHeader(Constants.BUNDLE_VENDOR);
401 	}
402 
403 	@Override
setProviderName(String providerName)404 	public void setProviderName(String providerName) throws CoreException {
405 		ensureModelEditable();
406 		IBundle bundle = getBundle();
407 		if (bundle != null) {
408 			String old = getProviderName();
409 			IManifestHeader header = bundle.getManifestHeader(Constants.BUNDLE_VENDOR);
410 			if (header instanceof BundleVendorHeader) {
411 				((BundleVendorHeader) header).setVendor(providerName);
412 			} else {
413 				bundle.setHeader(Constants.BUNDLE_VENDOR, providerName);
414 			}
415 			model.fireModelObjectChanged(this, IPluginBase.P_PROVIDER, old, providerName);
416 		}
417 	}
418 
419 	@Override
getVersion()420 	public String getVersion() {
421 		BundleDescription desc = model.getBundleDescription();
422 		if (desc != null) {
423 			Version version = desc.getVersion();
424 			return (version != null) ? version.toString() : null;
425 		}
426 		return getValue(Constants.BUNDLE_VERSION, false);
427 	}
428 
429 	@Override
setVersion(String version)430 	public void setVersion(String version) throws CoreException {
431 		ensureModelEditable();
432 		IBundle bundle = getBundle();
433 		if (bundle != null) {
434 			String old = getVersion();
435 			IManifestHeader header = bundle.getManifestHeader(Constants.BUNDLE_VERSION);
436 			if (header instanceof BundleVersionHeader) {
437 				((BundleVersionHeader) header).setVersionRange(version);
438 			} else {
439 				bundle.setHeader(Constants.BUNDLE_VERSION, version);
440 			}
441 			model.fireModelObjectChanged(this, IPluginBase.P_VERSION, old, version);
442 		}
443 	}
444 
445 	@Override
swap(IPluginLibrary l1, IPluginLibrary l2)446 	public void swap(IPluginLibrary l1, IPluginLibrary l2) throws CoreException {
447 		ensureModelEditable();
448 		if (libraries != null) {
449 			int index1 = libraries.indexOf(l1);
450 			int index2 = libraries.indexOf(l2);
451 			libraries.set(index1, l2);
452 			libraries.set(index2, l1);
453 			Object header = getManifestHeader(Constants.BUNDLE_CLASSPATH);
454 			if (header instanceof BundleClasspathHeader) {
455 				((BundleClasspathHeader) header).swap(index1, index2);
456 			}
457 			model.fireModelObjectChanged(this, P_IMPORT_ORDER, l1, l2);
458 		}
459 	}
460 
fireStructureChanged(Object object, boolean added)461 	protected void fireStructureChanged(Object object, boolean added) {
462 		int type = (added) ? IModelChangedEvent.INSERT : IModelChangedEvent.REMOVE;
463 		model.fireModelChanged(new ModelChangedEvent(model, type, new Object[] {object}, null));
464 	}
465 
fireStructureChanged(Object[] objects, boolean added)466 	protected void fireStructureChanged(Object[] objects, boolean added) {
467 		int type = (added) ? IModelChangedEvent.INSERT : IModelChangedEvent.REMOVE;
468 		model.fireModelChanged(new ModelChangedEvent(model, type, objects, null));
469 	}
470 
471 	@Override
add(IPluginExtension extension)472 	public void add(IPluginExtension extension) throws CoreException {
473 		ensureModelEditable();
474 		IExtensions extensions = getExtensionsRoot();
475 		if (extensions == null) {
476 			return;
477 		}
478 		extensions.add(extension);
479 
480 		// reset singleton
481 		if (getExtensions().length == 1 && getExtensionPoints().length == 0) {
482 			updateSingleton(true);
483 		}
484 	}
485 
486 	@Override
add(IPluginExtensionPoint point)487 	public void add(IPluginExtensionPoint point) throws CoreException {
488 		ensureModelEditable();
489 		IExtensions extensions = getExtensionsRoot();
490 		if (extensions == null) {
491 			return;
492 		}
493 		extensions.add(point);
494 
495 		//reset singleton
496 		if (getExtensions().length == 0 && getExtensionPoints().length == 1) {
497 			updateSingleton(true);
498 		}
499 	}
500 
501 	@Override
getResourceString(String key)502 	public String getResourceString(String key) {
503 		return model.getResourceString(key);
504 	}
505 
506 	@Override
getExtensionPoints()507 	public IPluginExtensionPoint[] getExtensionPoints() {
508 		IExtensions extensions = getExtensionsRoot();
509 		if (extensions == null) {
510 			return new IPluginExtensionPoint[0];
511 		}
512 		return extensions.getExtensionPoints();
513 	}
514 
515 	@Override
getExtensions()516 	public IPluginExtension[] getExtensions() {
517 		IExtensions extensions = getExtensionsRoot();
518 		if (extensions == null) {
519 			return new IPluginExtension[0];
520 		}
521 		return extensions.getExtensions();
522 	}
523 
524 	@Override
getIndexOf(IPluginExtension e)525 	public int getIndexOf(IPluginExtension e) {
526 		IExtensions extensions = getExtensionsRoot();
527 		if (extensions == null) {
528 			return -1;
529 		}
530 		return extensions.getIndexOf(e);
531 	}
532 
533 	@Override
remove(IPluginExtension extension)534 	public void remove(IPluginExtension extension) throws CoreException {
535 		ensureModelEditable();
536 		IExtensions extensions = getExtensionsRoot();
537 		if (extensions != null) {
538 			extensions.remove(extension);
539 			// reset singleton directive
540 			if (getExtensions().length == 0 && getExtensionPoints().length == 0) {
541 				updateSingleton(false);
542 			}
543 		}
544 	}
545 
546 	@Override
remove(IPluginExtensionPoint extensionPoint)547 	public void remove(IPluginExtensionPoint extensionPoint) throws CoreException {
548 		ensureModelEditable();
549 		IExtensions extensions = getExtensionsRoot();
550 		if (extensions != null) {
551 			extensions.remove(extensionPoint);
552 			// reset singleton directive
553 			if (getExtensions().length == 0 && getExtensionPoints().length == 0) {
554 				updateSingleton(false);
555 			}
556 		}
557 	}
558 
updateSingleton(boolean singleton)559 	protected void updateSingleton(boolean singleton) {
560 		IManifestHeader header = getManifestHeader(Constants.BUNDLE_SYMBOLICNAME);
561 		if (header instanceof BundleSymbolicNameHeader) {
562 			((BundleSymbolicNameHeader) header).setSingleton(singleton);
563 		} else {
564 			if (singleton) {
565 				String version = getBundle().getHeader(Constants.BUNDLE_MANIFESTVERSION);
566 				if (version == null)
567 				 {
568 					version = "1"; //$NON-NLS-1$
569 				}
570 				String value = header.getValue();
571 				String singletonValue = null;
572 				if (Integer.parseInt(version) >= 2) {
573 					singletonValue = Constants.SINGLETON_DIRECTIVE + ":=true"; //$NON-NLS-1$
574 				}
575 				else {
576 					singletonValue = Constants.SINGLETON_DIRECTIVE + "=true"; //$NON-NLS-1$
577 				}
578 				if (value.contains(singletonValue)) {
579 					return;
580 				}
581 				getBundle().setHeader(Constants.BUNDLE_SYMBOLICNAME, value + "; " + singletonValue); //$NON-NLS-1$
582 			}
583 			// No current need to remove singleton directive outside of text model.
584 		}
585 	}
586 
587 	@Override
swap(IPluginExtension e1, IPluginExtension e2)588 	public void swap(IPluginExtension e1, IPluginExtension e2) throws CoreException {
589 		ensureModelEditable();
590 		IExtensions extensions = getExtensionsRoot();
591 		if (extensions != null) {
592 			extensions.swap(e1, e2);
593 		}
594 	}
595 
596 	@Override
swap(IPluginImport import1, IPluginImport import2)597 	public void swap(IPluginImport import1, IPluginImport import2) throws CoreException {
598 		ensureModelEditable();
599 		if (imports != null) {
600 			int index1 = imports.indexOf(import1);
601 			int index2 = imports.indexOf(import2);
602 			imports.set(index1, import2);
603 			imports.set(index2, import1);
604 			Object header = getManifestHeader(Constants.REQUIRE_BUNDLE);
605 			if (header instanceof RequireBundleHeader) {
606 				((RequireBundleHeader) header).swap(index1, index2);
607 			}
608 			model.fireModelObjectChanged(this, P_IMPORT_ORDER, import1, import2);
609 		}
610 	}
611 
612 	@Override
getId()613 	public String getId() {
614 		return getValue(Constants.BUNDLE_SYMBOLICNAME, true);
615 	}
616 
617 	// The key should be a manifest header key, and parse should be true if it needs to be parsed by ManifestElement.parseHeader()
getValue(String key, boolean parse)618 	protected String getValue(String key, boolean parse) {
619 		IBundle bundle = getBundle();
620 		if (bundle == null) {
621 			return null;
622 		}
623 		String value = bundle.getHeader(key);
624 		if (value == null || !parse) {
625 			return value;
626 		}
627 		try {
628 			ManifestElement[] elements = ManifestElement.parseHeader(key, value);
629 			if (elements.length > 0) {
630 				return elements[0].getValue();
631 			}
632 		} catch (BundleException e) {
633 		}
634 		return null;
635 	}
636 
637 	@Override
setId(String id)638 	public void setId(String id) throws CoreException {
639 		ensureModelEditable();
640 		IBundle bundle = getBundle();
641 		if (bundle != null) {
642 			String old = getId();
643 			IManifestHeader header = bundle.getManifestHeader(Constants.BUNDLE_SYMBOLICNAME);
644 			if (header instanceof BundleSymbolicNameHeader) {
645 				((BundleSymbolicNameHeader) header).setId(id);
646 			} else {
647 				bundle.setHeader(Constants.BUNDLE_SYMBOLICNAME, id);
648 			}
649 			model.fireModelObjectChanged(this, IIdentifiable.P_ID, old, id);
650 		}
651 	}
652 
653 	@Override
getPluginModel()654 	public IPluginModelBase getPluginModel() {
655 		return model;
656 	}
657 
658 	@Override
getName()659 	public String getName() {
660 		return getValue(Constants.BUNDLE_NAME, false);
661 	}
662 
663 	@Override
setName(String name)664 	public void setName(String name) throws CoreException {
665 		ensureModelEditable();
666 		IBundle bundle = getBundle();
667 		if (bundle != null) {
668 			String old = getName();
669 			IManifestHeader header = bundle.getManifestHeader(Constants.BUNDLE_NAME);
670 			if (header instanceof BundleNameHeader) {
671 				((BundleNameHeader) header).setBundleName(name);
672 			} else {
673 				bundle.setHeader(Constants.BUNDLE_NAME, name);
674 			}
675 			model.fireModelObjectChanged(this, IPluginObject.P_NAME, old, name);
676 		}
677 	}
678 
679 	@Override
isInTheModel()680 	public boolean isInTheModel() {
681 		return model != null;
682 	}
683 
684 	@Override
getTranslatedName()685 	public String getTranslatedName() {
686 		return getResourceString(getName());
687 	}
688 
689 	@Override
getParent()690 	public IPluginObject getParent() {
691 		return null;
692 	}
693 
694 	@Override
getPluginBase()695 	public IPluginBase getPluginBase() {
696 		return this;
697 	}
698 
699 	@Override
isValid()700 	public boolean isValid() {
701 		IExtensions extensions = getExtensionsRoot();
702 		return getBundle() != null && getBundle().getHeader(Constants.BUNDLE_SYMBOLICNAME) != null && (extensions == null || extensions.isValid());
703 	}
704 
705 	@Override
write(String indent, PrintWriter writer)706 	public void write(String indent, PrintWriter writer) {
707 	}
708 
709 	@Override
setInTheModel(boolean inModel)710 	public void setInTheModel(boolean inModel) {
711 	}
712 
getBundleManifestVersion(IBundle bundle)713 	static public int getBundleManifestVersion(IBundle bundle) {
714 		String version = bundle.getHeader(Constants.BUNDLE_MANIFESTVERSION);
715 		if (version == null) {
716 			return 1; // default to 1
717 		}
718 		try {
719 			return Integer.parseInt(version);
720 		} catch (NumberFormatException e) {
721 			return 1; // default to 1
722 		}
723 	}
724 
updateImport(IPluginImport iimport)725 	public void updateImport(IPluginImport iimport) {
726 		Object header = getManifestHeader(Constants.REQUIRE_BUNDLE);
727 		if (header instanceof RequireBundleHeader && imports != null) {
728 			((RequireBundleHeader) header).updateBundle(imports.indexOf(iimport), iimport);
729 		}
730 	}
731 
732 	@Override
getTargetVersion()733 	public String getTargetVersion() {
734 		return fTarget != null ? fTarget : TargetPlatformHelper.getTargetVersionString();
735 	}
736 
737 	@Override
setTargetVersion(String target)738 	public void setTargetVersion(String target) {
739 		fTarget = target;
740 	}
741 
getIndexOf(IPluginImport targetImport)742 	public int getIndexOf(IPluginImport targetImport) {
743 		if (imports == null) {
744 			return -1;
745 		}
746 		return imports.indexOf(targetImport);
747 	}
748 
getPreviousImport(IPluginImport targetImport)749 	public IPluginImport getPreviousImport(IPluginImport targetImport) {
750 		// Ensure we have imports
751 		if (imports == null) {
752 			return null;
753 		} else if (imports.size() <= 1) {
754 			return null;
755 		}
756 		// Get the index of the target import
757 		int targetIndex = getIndexOf(targetImport);
758 		// Validate index
759 		if (targetIndex < 0) {
760 			// Target import does not exist
761 			return null;
762 		} else if (targetIndex == 0) {
763 			// Target import has no previous import
764 			return null;
765 		}
766 		// 1 <= index < size()
767 		// Get the previous import
768 		IPluginImport previousImport = imports.get(targetIndex - 1);
769 
770 		return previousImport;
771 	}
772 
getNextImport(IPluginImport targetImport)773 	public IPluginImport getNextImport(IPluginImport targetImport) {
774 		// Ensure we have imports
775 		if (imports == null) {
776 			return null;
777 		} else if (imports.size() <= 1) {
778 			return null;
779 		}
780 		// Get the index of the target import
781 		int targetIndex = getIndexOf(targetImport);
782 		// Get the index of the last import
783 		int lastIndex = imports.size() - 1;
784 		// Validate index
785 		if (targetIndex < 0) {
786 			// Target import does not exist
787 			return null;
788 		} else if (targetIndex >= lastIndex) {
789 			// Target import has no next element
790 			return null;
791 		}
792 		// 0 <= index < last element < size()
793 		// Get the next element
794 		IPluginImport nextImport = imports.get(targetIndex + 1);
795 
796 		return nextImport;
797 	}
798 
add(IPluginImport iimport, int index)799 	public void add(IPluginImport iimport, int index) throws CoreException {
800 		ensureModelEditable();
801 		int importCount = 0;
802 		if (imports != null) {
803 			importCount = imports.size();
804 		}
805 		// Validate index
806 		if (index < 0) {
807 			return;
808 		} else if (index > importCount) {
809 			return;
810 		}
811 		// 0 <= index <= importCount
812 		// Add the element to the list
813 		if (imports == null) {
814 			// Intitialize the imports list by calling getImports()
815 			getImports();
816 			// Add the import to the end of the list
817 			addImport(iimport);
818 		} else {
819 			// Add the import to the list at the specified index
820 			addImport(iimport, index);
821 		}
822 		// Fire event
823 		fireStructureChanged(iimport, true);
824 	}
825 
826 	/**
827 	 * @param iimport
828 	 * @param index
829 	 */
addImport(IPluginImport iimport, int index)830 	private void addImport(IPluginImport iimport, int index) {
831 		// Get the header
832 		IManifestHeader header = getManifestHeader(Constants.REQUIRE_BUNDLE);
833 		if ((header instanceof RequireBundleHeader) == false) {
834 			addImport(iimport);
835 		} else {
836 			// Add the import to the local container
837 			imports.add(index, iimport);
838 			// Add the import to the header
839 			((RequireBundleHeader) header).addBundle(iimport, index);
840 		}
841 	}
842 
add(IPluginLibrary library, int index)843 	public void add(IPluginLibrary library, int index) throws CoreException {
844 		ensureModelEditable();
845 		int libraryCount = 0;
846 		if (libraries != null) {
847 			libraryCount = libraries.size();
848 		}
849 		// Validate index
850 		if (index < 0) {
851 			return;
852 		} else if (index > libraryCount) {
853 			return;
854 		}
855 		// 0 <= index <= libraryCount
856 		if (libraries == null) {
857 			// Intitialize the library list by calling getLibraries()
858 			getLibraries();
859 		}
860 		// Get the header
861 		IManifestHeader header = getManifestHeader(Constants.BUNDLE_CLASSPATH);
862 		if ((header instanceof BundleClasspathHeader) == false) {
863 			// Add the library to the local container
864 			libraries.add(library);
865 			// Add the library to a newly created header
866 			addLibrary(library, header);
867 		} else {
868 			// Add the library to the local container at the specified index
869 			libraries.add(index, library);
870 			// Add the library to the existing header at the specified index
871 			((BundleClasspathHeader) header).addLibrary(library.getName(), index);
872 		}
873 		// Fire event
874 		fireStructureChanged(library, true);
875 	}
876 
getIndexOf(IPluginLibrary targetLibrary)877 	public int getIndexOf(IPluginLibrary targetLibrary) {
878 		if (libraries == null) {
879 			return -1;
880 		}
881 		return libraries.indexOf(targetLibrary);
882 	}
883 
getNextLibrary(IPluginLibrary targetLibrary)884 	public IPluginLibrary getNextLibrary(IPluginLibrary targetLibrary) {
885 		// Ensure we have libraries
886 		if (libraries == null) {
887 			return null;
888 		} else if (libraries.size() <= 1) {
889 			return null;
890 		}
891 		// Get the index of the target library
892 		int targetIndex = getIndexOf(targetLibrary);
893 		// Get the index of the last library
894 		int lastIndex = libraries.size() - 1;
895 		// Validate index
896 		if (targetIndex < 0) {
897 			// Target library does not exist
898 			return null;
899 		} else if (targetIndex >= lastIndex) {
900 			// Target library has no next element
901 			return null;
902 		}
903 		// 0 <= index < last element < size()
904 		// Get the next library
905 		IPluginLibrary nextLibrary = libraries.get(targetIndex + 1);
906 
907 		return nextLibrary;
908 	}
909 
getPreviousLibrary(IPluginLibrary targetLibrary)910 	public IPluginLibrary getPreviousLibrary(IPluginLibrary targetLibrary) {
911 		// Ensure we have libraries
912 		if (libraries == null) {
913 			return null;
914 		} else if (libraries.size() <= 1) {
915 			return null;
916 		}
917 		// Get the index of the target library
918 		int targetIndex = getIndexOf(targetLibrary);
919 		// Validate index
920 		if (targetIndex < 0) {
921 			// Target library does not exist
922 			return null;
923 		} else if (targetIndex == 0) {
924 			// Target library has no previous library
925 			return null;
926 		}
927 		// 1 <= index < size()
928 		// Get the previous library
929 		IPluginLibrary previousLibrary = libraries.get(targetIndex - 1);
930 
931 		return previousLibrary;
932 	}
933 
ensureModelEditable()934 	protected void ensureModelEditable() throws CoreException {
935 		if (!getModel().isEditable()) {
936 			throwCoreException(PDECoreMessages.PluginObject_readOnlyChange);
937 		}
938 	}
939 
throwCoreException(String message)940 	protected void throwCoreException(String message) throws CoreException {
941 		Status status = new Status(IStatus.ERROR, PDECore.PLUGIN_ID, IStatus.OK, message, null);
942 		CoreException ce = new CoreException(status);
943 		ce.fillInStackTrace();
944 		throw ce;
945 	}
946 
947 }
948