001: /*******************************************************************************
002: * Copyright (c) 2000, 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.plugin;
011:
012: import java.io.PrintWriter;
013: import java.io.Serializable;
014: import java.util.Locale;
015:
016: import org.eclipse.core.runtime.CoreException;
017: import org.eclipse.osgi.service.resolver.BundleDescription;
018: import org.eclipse.osgi.service.resolver.BundleSpecification;
019: import org.eclipse.osgi.service.resolver.VersionRange;
020: import org.eclipse.osgi.util.ManifestElement;
021: import org.eclipse.pde.core.plugin.IMatchRules;
022: import org.eclipse.pde.core.plugin.IPluginImport;
023: import org.eclipse.pde.core.plugin.IPluginModelBase;
024: import org.eclipse.pde.core.plugin.IPluginObject;
025: import org.eclipse.pde.core.plugin.ISharedPluginModel;
026: import org.eclipse.pde.internal.core.ICoreConstants;
027: import org.eclipse.pde.internal.core.bundle.BundlePluginBase;
028: import org.eclipse.pde.internal.core.ibundle.IBundle;
029: import org.eclipse.pde.internal.core.ibundle.IBundleModel;
030: import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
031: import org.eclipse.pde.internal.core.ibundle.IManifestHeader;
032: import org.eclipse.pde.internal.core.text.bundle.ManifestHeader;
033: import org.eclipse.pde.internal.core.text.bundle.RequireBundleObject;
034: import org.osgi.framework.Constants;
035: import org.w3c.dom.Node;
036:
037: public class PluginImport extends IdentifiablePluginObject implements
038: IPluginImport, Serializable {
039:
040: private static final long serialVersionUID = 1L;
041: private int match = NONE;
042: private boolean reexported = false;
043: private boolean optional = false;
044: private String version;
045:
046: public PluginImport() {
047: }
048:
049: public PluginImport(ISharedPluginModel model, String id) {
050: try {
051: setModel(model);
052: ensureModelEditable();
053: this .fID = id;
054: } catch (CoreException e) {
055: }
056: }
057:
058: public boolean isValid() {
059: return getId() != null;
060: }
061:
062: public int getMatch() {
063: return match;
064: }
065:
066: public String getVersion() {
067: return version;
068: }
069:
070: public boolean isReexported() {
071: return reexported;
072: }
073:
074: public boolean isOptional() {
075: return optional;
076: }
077:
078: public void load(BundleDescription description) {
079: this .fID = description.getSymbolicName();
080: }
081:
082: public void load(ManifestElement element, int bundleManifestVersion) {
083: this .fID = element.getValue();
084: if (bundleManifestVersion >= 2) {
085: this .optional = Constants.RESOLUTION_OPTIONAL
086: .equals(element
087: .getDirective(Constants.RESOLUTION_DIRECTIVE));
088: this .reexported = Constants.VISIBILITY_REEXPORT
089: .equals(element
090: .getDirective(Constants.VISIBILITY_DIRECTIVE));
091: } else {
092: this .optional = "true".equals(element.getAttribute(ICoreConstants.OPTIONAL_ATTRIBUTE)); //$NON-NLS-1$
093: this .reexported = "true".equals(element.getAttribute(ICoreConstants.REPROVIDE_ATTRIBUTE)); //$NON-NLS-1$
094: }
095: String bundleVersion = element
096: .getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE);
097: if (bundleVersion != null) {
098: try {
099: VersionRange versionRange = new VersionRange(
100: bundleVersion);
101: this .version = bundleVersion;
102: this .match = PluginBase.getMatchRule(versionRange);
103: } catch (IllegalArgumentException e) {
104: }
105: }
106: }
107:
108: public void load(BundleSpecification importModel) {
109: this .fID = importModel.getName();
110: this .reexported = importModel.isExported();
111: this .optional = importModel.isOptional();
112: VersionRange versionRange = importModel.getVersionRange();
113: if (versionRange == null
114: || VersionRange.emptyRange.equals(versionRange)) {
115: this .version = null;
116: match = IMatchRules.NONE;
117: } else {
118: this .version = versionRange.getMinimum() != null ? versionRange
119: .getMinimum().toString()
120: : null;
121: match = PluginBase.getMatchRule(versionRange);
122: }
123: }
124:
125: public boolean equals(Object obj) {
126: if (obj == this )
127: return true;
128: if (obj == null)
129: return false;
130: if (obj instanceof IPluginImport) {
131: IPluginImport target = (IPluginImport) obj;
132: // Objects from the same model must be
133: // binary equal
134: if (target.getModel().equals(getModel()))
135: return false;
136:
137: if (target.getId().equals(getId())
138: && target.isReexported() == isReexported()
139: && stringEqualWithNull(target.getVersion(),
140: getVersion())
141: && target.getMatch() == getMatch()
142: && target.isOptional() == isOptional())
143: return true;
144: }
145: return false;
146: }
147:
148: void load(Node node) {
149: String id = getNodeAttribute(node, "plugin"); //$NON-NLS-1$
150: String export = getNodeAttribute(node, "export"); //$NON-NLS-1$
151: String option = getNodeAttribute(node, "optional"); //$NON-NLS-1$
152: String version = getNodeAttribute(node, "version"); //$NON-NLS-1$
153: String match = getNodeAttribute(node, "match"); //$NON-NLS-1$
154: boolean reexport = export != null
155: && export.toLowerCase(Locale.ENGLISH).equals("true"); //$NON-NLS-1$
156: boolean optional = option != null
157: && option.toLowerCase(Locale.ENGLISH).equals("true"); //$NON-NLS-1$
158: this .match = NONE;
159: if (match != null) {
160: String lmatch = match.toLowerCase(Locale.ENGLISH);
161: if (lmatch.equals("exact")) //$NON-NLS-1$
162: lmatch = RULE_EQUIVALENT;
163: for (int i = 0; i < RULE_NAME_TABLE.length; i++) {
164: if (lmatch.equals(RULE_NAME_TABLE[i])) {
165: this .match = i;
166: break;
167: }
168: }
169: }
170: this .version = version;
171: this .fID = id;
172: this .reexported = reexport;
173: this .optional = optional;
174: }
175:
176: public void setMatch(int match) throws CoreException {
177: ensureModelEditable();
178: Integer oldValue = new Integer(this .match);
179: this .match = match;
180: firePropertyChanged(P_MATCH, oldValue, new Integer(match));
181: }
182:
183: public void setReexported(boolean value) throws CoreException {
184: ensureModelEditable();
185: Boolean oldValue = new Boolean(reexported);
186: this .reexported = value;
187: firePropertyChanged(P_REEXPORTED, oldValue, new Boolean(value));
188: }
189:
190: public void setOptional(boolean value) throws CoreException {
191: ensureModelEditable();
192: Boolean oldValue = new Boolean(this .optional);
193: this .optional = value;
194: firePropertyChanged(P_OPTIONAL, oldValue, new Boolean(value));
195: }
196:
197: public void setVersion(String version) throws CoreException {
198: ensureModelEditable();
199: String oldValue = this .version;
200: this .version = version;
201: firePropertyChanged(P_VERSION, oldValue, version);
202: }
203:
204: public void restoreProperty(String name, Object oldValue,
205: Object newValue) throws CoreException {
206: if (name.equals(P_MATCH)) {
207: setMatch(((Integer) newValue).intValue());
208: return;
209: }
210: if (name.equals(P_REEXPORTED)) {
211: setReexported(((Boolean) newValue).booleanValue());
212: return;
213: }
214: if (name.equals(P_OPTIONAL)) {
215: setOptional(((Boolean) newValue).booleanValue());
216: return;
217: }
218: if (name.equals(P_VERSION)) {
219: setVersion(newValue != null ? newValue.toString() : null);
220: return;
221: }
222: super .restoreProperty(name, oldValue, newValue);
223: }
224:
225: /* (non-Javadoc)
226: * @see org.eclipse.pde.core.IWritable#write(java.lang.String, java.io.PrintWriter)
227: */
228: public void write(String indent, PrintWriter writer) {
229: // This is a round-about way to do this; but, leveraging existing
230: // functionality is key. The fact we have to do this suggests a model
231: // limitation.
232: // Emulating the behaviour of the text edit operations.
233: // RequireBundleObjects are created from PluginImport objects and have
234: // access to the MANIFEST.MF write mechanism
235:
236: // Get the model
237: IPluginModelBase modelBase = getPluginModel();
238: // Ensure the model is a bundle model
239: if ((modelBase instanceof IBundlePluginModelBase) == false) {
240: writer.print(indent);
241: writer.print("<import plugin=\"" + getId() + "\""); //$NON-NLS-1$ //$NON-NLS-2$
242: if (isReexported())
243: writer.print(" export=\"true\""); //$NON-NLS-1$
244: if (isOptional())
245: writer.print(" optional=\"true\""); //$NON-NLS-1$
246: if (version != null && version.length() > 0)
247: writer.print(" version=\"" + version + "\""); //$NON-NLS-1$ //$NON-NLS-2$
248: if (match != NONE && match != COMPATIBLE) {
249: String matchValue = RULE_NAME_TABLE[match];
250: writer.print(" match=\"" + matchValue + "\""); //$NON-NLS-1$ //$NON-NLS-2$
251: }
252: writer.println("/>"); //$NON-NLS-1$
253: return;
254: }
255: IBundleModel bundleModel = ((IBundlePluginModelBase) modelBase)
256: .getBundleModel();
257: // Ensure the bundle manifest is present
258: if (bundleModel == null) {
259: return;
260: }
261: // Get the bundle
262: IBundle bundle = bundleModel.getBundle();
263: // Get the require bundle manifest header
264: IManifestHeader manifestHeader = bundle
265: .getManifestHeader(Constants.REQUIRE_BUNDLE);
266: // Ensure the header was found (it has to be there since the calling
267: // of this method is a result of a copy operation)
268: if ((manifestHeader instanceof ManifestHeader) == false) {
269: return;
270: }
271: ManifestHeader header = (ManifestHeader) manifestHeader;
272: // Create the new temporary require bundle object (used only for
273: // writing)
274: RequireBundleObject element = new RequireBundleObject(header,
275: fID);
276: // Get the manifest version for backwards compatibility
277: int bundleManifestVersion = BundlePluginBase
278: .getBundleManifestVersion(bundle);
279: // Configure its properties using the values of this object
280: // Field: Optional
281: if (optional) {
282: if (bundleManifestVersion > 1) {
283: element.setDirective(Constants.RESOLUTION_DIRECTIVE,
284: Constants.RESOLUTION_OPTIONAL);
285: } else {
286: element.setAttribute(ICoreConstants.OPTIONAL_ATTRIBUTE,
287: "true"); //$NON-NLS-1$
288: }
289: }
290: // Field: Re-exported
291: if (reexported) {
292: if (bundleManifestVersion > 1) {
293: element.setDirective(Constants.VISIBILITY_DIRECTIVE,
294: Constants.VISIBILITY_REEXPORT);
295: } else {
296: element.setAttribute(
297: ICoreConstants.REPROVIDE_ATTRIBUTE, "true"); //$NON-NLS-1$
298: }
299: }
300: // Field: Version
301: if ((version != null) && (version.trim().length() > 0)) {
302: element.setAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE,
303: version.trim());
304: }
305: // Write the textual representation
306: writer.print(element.write());
307: }
308:
309: /* (non-Javadoc)
310: * @see org.eclipse.pde.internal.core.plugin.IdentifiablePluginObject#reconnect(org.eclipse.pde.core.plugin.ISharedPluginModel, org.eclipse.pde.core.plugin.IPluginObject)
311: */
312: public void reconnect(ISharedPluginModel model, IPluginObject parent) {
313: super .reconnect(model, parent);
314: // No transient fields
315: }
316:
317: /* (non-Javadoc)
318: * @see org.eclipse.pde.internal.core.plugin.PluginObject#writeDelimeter(java.io.PrintWriter)
319: */
320: public void writeDelimeter(PrintWriter writer) {
321: writer.println(',');
322: writer.print(' ');
323: }
324:
325: }
|