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.FileNotFoundException;
014: import java.io.IOException;
015: import java.net.MalformedURLException;
016: import java.net.URL;
017: import java.util.ArrayList;
018: import java.util.Dictionary;
019: import java.util.HashMap;
020:
021: import org.eclipse.core.resources.IFile;
022: import org.eclipse.core.resources.IProject;
023: import org.eclipse.core.runtime.CoreException;
024: import org.eclipse.core.runtime.IProgressMonitor;
025: import org.eclipse.core.runtime.IStatus;
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.resolver.BundleDescription;
030: import org.eclipse.osgi.service.resolver.State;
031: import org.eclipse.pde.core.plugin.IPluginModelBase;
032: import org.eclipse.pde.core.plugin.PluginRegistry;
033: import org.eclipse.pde.internal.core.bundle.BundleFragmentModel;
034: import org.eclipse.pde.internal.core.bundle.BundlePluginModel;
035: import org.eclipse.pde.internal.core.bundle.BundlePluginModelBase;
036: import org.eclipse.pde.internal.core.bundle.WorkspaceBundleModel;
037: import org.eclipse.pde.internal.core.plugin.ExternalFragmentModel;
038: import org.eclipse.pde.internal.core.plugin.ExternalPluginModel;
039: import org.eclipse.pde.internal.core.plugin.ExternalPluginModelBase;
040: import org.eclipse.pde.internal.core.plugin.WorkspaceExtensionsModel;
041: import org.eclipse.pde.internal.core.plugin.WorkspaceFragmentModel;
042: import org.eclipse.pde.internal.core.plugin.WorkspacePluginModel;
043: import org.eclipse.pde.internal.core.plugin.WorkspacePluginModelBase;
044: import org.eclipse.pde.internal.core.util.CoreUtility;
045:
046: public class PDEState extends MinimalState {
047:
048: private PDEAuxiliaryState fAuxiliaryState;
049:
050: private ArrayList fTargetModels = new ArrayList();
051: private ArrayList fWorkspaceModels = new ArrayList();
052: private boolean fCombined;
053: private long fTargetTimestamp;
054: private boolean fNewState;
055:
056: public PDEState(PDEState state) {
057: super (state);
058: fTargetModels = new ArrayList(state.fTargetModels);
059: fCombined = false;
060: fTargetTimestamp = state.fTargetTimestamp;
061: fAuxiliaryState = new PDEAuxiliaryState(state.fAuxiliaryState);
062: if (fAuxiliaryState.fPluginInfos.isEmpty())
063: fAuxiliaryState.readPluginInfoCache(new File(DIR, Long
064: .toString(fTargetTimestamp)
065: + ".target")); //$NON-NLS-1$
066: }
067:
068: public PDEState(URL[] urls, boolean resolve,
069: IProgressMonitor monitor) {
070: this (new URL[0], urls, resolve, monitor);
071: }
072:
073: public PDEState(URL[] workspace, URL[] target, boolean resolve,
074: IProgressMonitor monitor) {
075: long start = System.currentTimeMillis();
076: fAuxiliaryState = new PDEAuxiliaryState();
077:
078: if (resolve) {
079: readTargetState(target, monitor);
080: } else {
081: createNewTargetState(resolve, target, monitor);
082: }
083: createTargetModels(fState.getBundles());
084:
085: if (resolve && workspace.length > 0 && !fNewState
086: && !"true".equals(System.getProperty("pde.nocache"))) //$NON-NLS-1$ //$NON-NLS-2$
087: readWorkspaceState(workspace);
088:
089: fAuxiliaryState.clear();
090:
091: if (DEBUG)
092: System.out
093: .println("Time to create state: " + (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
094: }
095:
096: private void readTargetState(URL[] urls, IProgressMonitor monitor) {
097: fTargetTimestamp = computeTimestamp(urls);
098: File dir = new File(DIR, Long.toString(fTargetTimestamp)
099: + ".target"); //$NON-NLS-1$
100: if ((fState = readStateCache(dir)) == null
101: || !fAuxiliaryState.readPluginInfoCache(dir)) {
102: createNewTargetState(true, urls, monitor);
103: if (!dir.exists())
104: dir.mkdirs();
105: fAuxiliaryState.savePluginInfo(dir);
106: resolveState(false);
107: saveState(dir);
108: } else {
109: boolean propertiesChanged = initializePlatformProperties();
110: fState.setResolver(Platform.getPlatformAdmin()
111: .getResolver());
112: if (propertiesChanged)
113: fState.resolve(false);
114: fId = fState.getBundles().length;
115: }
116: }
117:
118: private void createNewTargetState(boolean resolve, URL[] urls,
119: IProgressMonitor monitor) {
120: fState = stateObjectFactory.createState(resolve);
121: monitor.beginTask("", urls.length); //$NON-NLS-1$
122: for (int i = 0; i < urls.length; i++) {
123: File file = new File(urls[i].getFile());
124: try {
125: if (monitor.isCanceled())
126: // if canceled, stop loading bundles
127: return;
128: monitor.subTask(file.getName());
129: addBundle(file, -1);
130: } catch (PluginConversionException e) {
131: } catch (CoreException e) {
132: } catch (IOException e) {
133: PDECore
134: .log(new Status(
135: IStatus.ERROR,
136: PDECore.PLUGIN_ID,
137: IStatus.ERROR,
138: "Invalid manifest format at " + file.getAbsolutePath(), //$NON-NLS-1$
139: null));
140: } finally {
141: monitor.worked(1);
142: }
143: }
144: fNewState = true;
145: }
146:
147: protected void addAuxiliaryData(BundleDescription desc,
148: Dictionary manifest, boolean hasBundleStructure) {
149: fAuxiliaryState.addAuxiliaryData(desc, manifest,
150: hasBundleStructure);
151: }
152:
153: public IPluginModelBase[] createTargetModels(
154: BundleDescription[] bundleDescriptions) {
155: HashMap models = new HashMap((4 / 3)
156: * bundleDescriptions.length + 1);
157: for (int i = 0; i < bundleDescriptions.length; i++) {
158: BundleDescription desc = bundleDescriptions[i];
159: IPluginModelBase base = createExternalModel(desc);
160: fTargetModels.add(base);
161: models.put(desc.getSymbolicName(), base);
162: }
163: if (models.isEmpty())
164: return new IPluginModelBase[0];
165: return (IPluginModelBase[]) models.values().toArray(
166: new IPluginModelBase[models.size()]);
167: }
168:
169: private void readWorkspaceState(URL[] urls) {
170: long workspace = computeTimestamp(urls);
171: File dir = new File(DIR, Long.toString(workspace)
172: + ".workspace"); //$NON-NLS-1$
173: State localState = readStateCache(dir);
174: fCombined = localState != null
175: && fAuxiliaryState.readPluginInfoCache(dir);
176: if (fCombined) {
177: long targetCount = fId;
178: BundleDescription[] bundles = localState.getBundles();
179: for (int i = 0; i < bundles.length; i++) {
180: BundleDescription desc = bundles[i];
181: String id = desc.getSymbolicName();
182: BundleDescription[] conflicts = fState.getBundles(id);
183:
184: for (int j = 0; j < conflicts.length; j++) {
185: // only remove bundles with a conflicting symblic name
186: // if the conflicting bundles come from the target.
187: // Workspace bundles with conflicting symbolic names are allowed
188: if (conflicts[j].getBundleId() <= targetCount)
189: fState.removeBundle(conflicts[j]);
190: }
191:
192: BundleDescription newbundle = stateObjectFactory
193: .createBundleDescription(desc);
194: IPluginModelBase model = createWorkspaceModel(newbundle);
195: if (model != null && fState.addBundle(newbundle)) {
196: fId = Math.max(fId, newbundle.getBundleId());
197: fWorkspaceModels.add(model);
198: }
199: }
200: fId = Math.max(fId, fState.getBundles().length);
201: fState.resolve(false);
202: }
203: }
204:
205: public boolean isCombined() {
206: return fCombined;
207: }
208:
209: private State readStateCache(File dir) {
210: if (dir.exists() && dir.isDirectory()) {
211: try {
212: return stateObjectFactory.readState(dir);
213: } catch (IllegalStateException e) {
214: PDECore.log(e);
215: } catch (FileNotFoundException e) {
216: PDECore.log(e);
217: } catch (IOException e) {
218: PDECore.log(e);
219: } finally {
220: }
221: }
222: return null;
223: }
224:
225: private long computeTimestamp(URL[] urls) {
226: return computeTimestamp(urls, 0);
227: }
228:
229: private long computeTimestamp(URL[] urls, long timestamp) {
230: for (int i = 0; i < urls.length; i++) {
231: File file = new File(urls[i].getFile());
232: if (file.exists()) {
233: if (file.isFile()) {
234: timestamp ^= file.lastModified();
235: } else {
236: File manifest = new File(file,
237: "META-INF/MANIFEST.MF"); //$NON-NLS-1$
238: if (manifest.exists())
239: timestamp ^= manifest.lastModified();
240: manifest = new File(file, "plugin.xml"); //$NON-NLS-1$
241: if (manifest.exists())
242: timestamp ^= manifest.lastModified();
243: manifest = new File(file, "fragment.xml"); //$NON-NLS-1$
244: if (manifest.exists())
245: timestamp ^= manifest.lastModified();
246: }
247: timestamp ^= file.getAbsolutePath().hashCode();
248: }
249: }
250: return timestamp;
251: }
252:
253: private IPluginModelBase createWorkspaceModel(BundleDescription desc) {
254: String projectName = fAuxiliaryState.getProject(desc
255: .getBundleId());
256: if (projectName == null)
257: return null;
258: IProject project = PDECore.getWorkspace().getRoot().getProject(
259: projectName);
260: if (!project.exists())
261: return null;
262: if (project.exists(ICoreConstants.MANIFEST_PATH)) {
263: BundlePluginModelBase model = null;
264: if (desc.getHost() == null)
265: model = new BundlePluginModel();
266: else
267: model = new BundleFragmentModel();
268: model.setEnabled(true);
269: WorkspaceBundleModel bundle = new WorkspaceBundleModel(
270: project.getFile("META-INF/MANIFEST.MF")); //$NON-NLS-1$
271: bundle.load(desc, this );
272: model.setBundleDescription(desc);
273: model.setBundleModel(bundle);
274: bundle.setEditable(false);
275:
276: String filename = (desc.getHost() == null) ? "plugin.xml" : "fragment.xml"; //$NON-NLS-1$ //$NON-NLS-2$
277: IFile file = project.getFile(filename);
278: if (file.exists()) {
279: WorkspaceExtensionsModel extensions = new WorkspaceExtensionsModel(
280: file);
281: extensions.setEditable(false);
282: extensions.setBundleModel(model);
283: extensions.load(desc, this );
284: model.setExtensionsModel(extensions);
285: }
286: return model;
287: }
288:
289: WorkspacePluginModelBase model = null;
290: if (desc.getHost() == null)
291: model = new WorkspacePluginModel(project
292: .getFile("plugin.xml"), true); //$NON-NLS-1$
293: else
294: model = new WorkspaceFragmentModel(project
295: .getFile("fragment.xml"), true); //$NON-NLS-1$
296: model.load(desc, this );
297: model.setBundleDescription(desc);
298: return model;
299: }
300:
301: private IPluginModelBase createExternalModel(BundleDescription desc) {
302: ExternalPluginModelBase model = null;
303: if (desc.getHost() == null)
304: model = new ExternalPluginModel();
305: else
306: model = new ExternalFragmentModel();
307: model.load(desc, this );
308: model.setBundleDescription(desc);
309: return model;
310: }
311:
312: public IPluginModelBase[] getTargetModels() {
313: return (IPluginModelBase[]) fTargetModels
314: .toArray(new IPluginModelBase[fTargetModels.size()]);
315: }
316:
317: public IPluginModelBase[] getWorkspaceModels() {
318: return (IPluginModelBase[]) fWorkspaceModels
319: .toArray(new IPluginModelBase[fWorkspaceModels.size()]);
320: }
321:
322: public void shutdown() {
323: IPluginModelBase[] models = PluginRegistry.getWorkspaceModels();
324: long timestamp = 0;
325: if (!"true".equals(System.getProperty("pde.nocache")) && shouldSaveState(models)) { //$NON-NLS-1$ //$NON-NLS-2$
326: timestamp = computeTimestamp(models);
327: File dir = new File(DIR, Long.toString(timestamp)
328: + ".workspace"); //$NON-NLS-1$
329: State state = stateObjectFactory.createState(false);
330: for (int i = 0; i < models.length; i++) {
331: state.addBundle(models[i].getBundleDescription());
332: }
333: saveState(state, dir);
334: PDEAuxiliaryState.writePluginInfo(models, dir);
335: }
336: clearStaleStates(".target", fTargetTimestamp); //$NON-NLS-1$
337: clearStaleStates(".workspace", timestamp); //$NON-NLS-1$
338: clearStaleStates(".cache", 0); //$NON-NLS-1$
339: }
340:
341: private long computeTimestamp(IPluginModelBase[] models) {
342: URL[] urls = new URL[models.length];
343: for (int i = 0; i < models.length; i++) {
344: try {
345: IProject project = models[i].getUnderlyingResource()
346: .getProject();
347: urls[i] = new File(project.getLocation().toString())
348: .toURL();
349: } catch (MalformedURLException e) {
350: }
351: }
352: return computeTimestamp(urls);
353: }
354:
355: private boolean shouldSaveState(IPluginModelBase[] models) {
356: for (int i = 0; i < models.length; i++) {
357: String id = models[i].getPluginBase().getId();
358: if (id == null || id.trim().length() == 0
359: || !models[i].isLoaded() || !models[i].isInSync()
360: || models[i].getBundleDescription() == null)
361: return false;
362: }
363: return models.length > 0;
364: }
365:
366: private void clearStaleStates(String extension, long latest) {
367: File dir = new File(PDECore.getDefault().getStateLocation()
368: .toOSString());
369: File[] children = dir.listFiles();
370: if (children != null) {
371: for (int i = 0; i < children.length; i++) {
372: File child = children[i];
373: if (child.isDirectory()) {
374: String name = child.getName();
375: if (name.endsWith(extension)
376: && name.length() > extension.length()
377: && !name.equals(Long.toString(latest)
378: + extension)) {
379: CoreUtility.deleteContent(child);
380: }
381: }
382: }
383: }
384: }
385:
386: public String getClassName(long bundleID) {
387: return fAuxiliaryState.getClassName(bundleID);
388: }
389:
390: public boolean hasExtensibleAPI(long bundleID) {
391: return fAuxiliaryState.hasExtensibleAPI(bundleID);
392: }
393:
394: public boolean isPatchFragment(long bundleID) {
395: return fAuxiliaryState.isPatchFragment(bundleID);
396: }
397:
398: public boolean hasBundleStructure(long bundleID) {
399: return fAuxiliaryState.hasBundleStructure(bundleID);
400: }
401:
402: public String getPluginName(long bundleID) {
403: return fAuxiliaryState.getPluginName(bundleID);
404: }
405:
406: public String getProviderName(long bundleID) {
407: return fAuxiliaryState.getProviderName(bundleID);
408: }
409:
410: public String[] getLibraryNames(long bundleID) {
411: return fAuxiliaryState.getLibraryNames(bundleID);
412: }
413:
414: public String getBundleLocalization(long bundleID) {
415: return fAuxiliaryState.getBundleLocalization(bundleID);
416: }
417:
418: public String getProject(long bundleID) {
419: return fAuxiliaryState.getProject(bundleID);
420: }
421:
422: public BundleDescription[] addAdditionalBundles(URL[] newBundleURLs) {
423: // add new Bundles to the State
424: ArrayList descriptions = new ArrayList(newBundleURLs.length);
425: for (int i = 0; i < newBundleURLs.length; i++) {
426: File file = new File(newBundleURLs[i].getFile());
427: try {
428: BundleDescription desc = addBundle(file, -1);
429: if (desc != null)
430: descriptions.add(desc);
431: } catch (PluginConversionException e) {
432: } catch (CoreException e) {
433: } catch (IOException e) {
434: PDECore
435: .log(new Status(
436: IStatus.ERROR,
437: PDECore.PLUGIN_ID,
438: IStatus.ERROR,
439: "Invalid manifest format at " + file.getAbsolutePath(), //$NON-NLS-1$
440: null));
441: }
442: }
443: // compute Timestamp and save all new information
444: fTargetTimestamp = computeTimestamp(newBundleURLs,
445: fTargetTimestamp);
446: File dir = new File(DIR, Long.toString(fTargetTimestamp)
447: + ".target"); //$NON-NLS-1$
448: if (!dir.exists())
449: dir.mkdirs();
450: fAuxiliaryState.savePluginInfo(dir);
451: saveState(dir);
452:
453: // resolve state - same steps as when populating a new State
454: resolveState(false);
455:
456: return (BundleDescription[]) descriptions
457: .toArray(new BundleDescription[descriptions.size()]);
458: }
459:
460: public File getTargetDirectory() {
461: return new File(DIR, Long.toString(fTargetTimestamp)
462: + ".target"); //$NON-NLS-1$
463: }
464:
465: }
|