KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > pde > internal > core > WorkspacePluginModelManager


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.pde.internal.core;
12
13 import java.io.File JavaDoc;
14 import java.io.FileOutputStream JavaDoc;
15 import java.io.IOException JavaDoc;
16 import java.io.OutputStream JavaDoc;
17 import java.io.PrintWriter JavaDoc;
18 import java.net.MalformedURLException JavaDoc;
19 import java.net.URL JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Collections JavaDoc;
22 import java.util.HashMap JavaDoc;
23
24 import org.eclipse.core.resources.IFile;
25 import org.eclipse.core.resources.IFolder;
26 import org.eclipse.core.resources.IProject;
27 import org.eclipse.core.resources.IResourceChangeEvent;
28 import org.eclipse.core.resources.IResourceDelta;
29 import org.eclipse.core.resources.IWorkspace;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IPath;
32 import org.eclipse.core.runtime.Path;
33 import org.eclipse.jdt.core.JavaCore;
34 import org.eclipse.pde.core.IModelProviderEvent;
35 import org.eclipse.pde.core.plugin.IPluginModelBase;
36 import org.eclipse.pde.core.plugin.ISharedExtensionsModel;
37 import org.eclipse.pde.internal.core.builders.SchemaTransformer;
38 import org.eclipse.pde.internal.core.bundle.BundleFragmentModel;
39 import org.eclipse.pde.internal.core.bundle.BundlePluginModel;
40 import org.eclipse.pde.internal.core.bundle.WorkspaceBundleModel;
41 import org.eclipse.pde.internal.core.ibundle.IBundleModel;
42 import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
43 import org.eclipse.pde.internal.core.ischema.ISchema;
44 import org.eclipse.pde.internal.core.ischema.ISchemaDescriptor;
45 import org.eclipse.pde.internal.core.plugin.WorkspaceExtensionsModel;
46 import org.eclipse.pde.internal.core.plugin.WorkspaceFragmentModel;
47 import org.eclipse.pde.internal.core.plugin.WorkspacePluginModel;
48 import org.eclipse.pde.internal.core.schema.SchemaDescriptor;
49
50 public class WorkspacePluginModelManager extends WorkspaceModelManager {
51
52     /**
53      * The workspace plug-in model manager is only interested
54      * in changes to plug-in projects.
55      */

56     protected boolean isInterestingProject(IProject project) {
57         return isPluginProject(project);
58     }
59
60     /**
61      * Creates a plug-in model based on the project structure.
62      * <p>
63      * A bundle model is created if the project has a MANIFEST.MF file and optionally
64      * a plugin.xml/fragment.xml file.
65      * </p>
66      * <p>
67      * An old-style plugin model is created if the project only has a plugin.xml/fragment.xml
68      * file.
69      * </p>
70      */

71     protected void createModel(IProject project, boolean notify) {
72         IPluginModelBase model = null;
73         if (project.exists(ICoreConstants.MANIFEST_PATH)) {
74             WorkspaceBundleModel bmodel = new WorkspaceBundleModel(project.getFile(ICoreConstants.MANIFEST_PATH));
75             loadModel(bmodel, false);
76             if (bmodel.isFragmentModel())
77                 model = new BundleFragmentModel();
78             else
79                 model = new BundlePluginModel();
80             model.setEnabled(true);
81             ((IBundlePluginModelBase)model).setBundleModel(bmodel);
82             
83             IFile efile = project.getFile(bmodel.isFragmentModel()
84                             ? ICoreConstants.FRAGMENT_PATH : ICoreConstants.PLUGIN_PATH);
85             if (efile.exists()) {
86                 WorkspaceExtensionsModel extModel = new WorkspaceExtensionsModel(efile);
87                 loadModel(extModel, false);
88                 ((IBundlePluginModelBase)model).setExtensionsModel(extModel);
89                 extModel.setBundleModel((IBundlePluginModelBase)model);
90             }
91             
92         } else if (project.exists(ICoreConstants.PLUGIN_PATH)) {
93             model = new WorkspacePluginModel(project.getFile(ICoreConstants.PLUGIN_PATH), true);
94             loadModel(model, false);
95         } else if (project.exists(ICoreConstants.FRAGMENT_PATH)) {
96             model = new WorkspaceFragmentModel(project.getFile(ICoreConstants.FRAGMENT_PATH), true);
97             loadModel(model, false);
98         }
99         
100         if (project.getFile(".options").exists()) //$NON-NLS-1$
101
PDECore.getDefault().getTracingOptionsManager().reset();
102
103         if (model != null) {
104             if (fModels == null)
105                 fModels = new HashMap JavaDoc();
106             fModels.put(project, model);
107             if (notify)
108                 addChange(model, IModelProviderEvent.MODELS_ADDED);
109         }
110     }
111     
112     /**
113      * Reacts to changes in files of interest to PDE
114      */

115     protected void handleFileDelta(IResourceDelta delta) {
116         IFile file = (IFile)delta.getResource();
117         String JavaDoc filename = file.getName();
118         if (filename.equals(".options")) { //$NON-NLS-1$
119
PDECore.getDefault().getTracingOptionsManager().reset();
120         } else if (filename.endsWith(".properties")) { //$NON-NLS-1$
121
// change in build.properties should trigger a Classpath Update
122
// we therefore fire a notification
123
//TODO this is inefficient. we could do better.
124
if (filename.equals("build.properties")) { //$NON-NLS-1$
125
Object JavaDoc model = getModel(file.getProject());
126                 if (model != null)
127                     addChange(model, IModelProviderEvent.MODELS_CHANGED);
128              } else {
129                  // reset bundle resource if localization file has changed.
130
IPluginModelBase model = getPluginModel(file.getProject());
131                  String JavaDoc localization = null;
132                  if (model instanceof IBundlePluginModelBase) {
133                     localization = ((IBundlePluginModelBase)model).getBundleLocalization();
134                  } else if (model != null) {
135                      localization = "plugin"; //$NON-NLS-1$
136
}
137                  if (localization != null && filename.startsWith(localization)) {
138                     ((AbstractNLModel)model).resetNLResourceHelper();
139                  }
140              }
141         } else if (filename.endsWith(".exsd")) { //$NON-NLS-1$
142
handleEclipseSchemaDelta(file, delta);
143         } else {
144             IPath path = file.getProjectRelativePath();
145             if (path.equals(ICoreConstants.PLUGIN_PATH)
146                     || path.equals(ICoreConstants.FRAGMENT_PATH)){
147                 handleExtensionFileDelta(file, delta);
148             } else if (path.equals(ICoreConstants.MANIFEST_PATH)) {
149                 handleBundleManifestDelta(file, delta);
150             }
151         }
152     }
153     
154     /**
155      * @param file
156      * @param delta
157      */

158     private void handleEclipseSchemaDelta(IFile schemaFile, IResourceDelta delta) {
159         // Get the kind of resource delta
160
int kind = delta.getKind();
161         // We are only interested in schema files whose contents have changed
162
if (kind != IResourceDelta.CHANGED) {
163             return;
164         } else if ((IResourceDelta.CONTENT & delta.getFlags()) == 0) {
165             return;
166         }
167         // Get the schema preview file session property
168
Object JavaDoc property = null;
169         try {
170             property =
171                 schemaFile.getSessionProperty(PDECore.SCHEMA_PREVIEW_FILE);
172         } catch (CoreException e) {
173             // Ignore
174
return;
175         }
176         // Check if the schema file has an associated HTML schema preview file
177
// (That is, whether a show description action has been executed before)
178
// Property set in
179
// org.eclipse.pde.internal.ui.search.ShowDescriptionAction.linkPreviewFileToSchemaFile()
180
if (property == null) {
181             return;
182         } else if ((property instanceof File JavaDoc) == false) {
183             return;
184         }
185         File JavaDoc schemaPreviewFile = (File JavaDoc)property;
186         // Ensure the file exists and is writable
187
if (schemaPreviewFile.exists() == false) {
188             return;
189         } else if (schemaPreviewFile.isFile() == false) {
190             return;
191         } else if (schemaPreviewFile.canWrite() == false) {
192             return;
193         }
194         // Get the schema model object
195
ISchemaDescriptor descriptor = new SchemaDescriptor(schemaFile, false);
196         ISchema schema = descriptor.getSchema(false);
197         
198         try {
199             // Re-generate the schema preview file contents in order to reflect
200
// the changes in the schema
201
recreateSchemaPreviewFileContents(schemaPreviewFile, schema);
202         } catch (IOException JavaDoc e) {
203             // Ignore
204
}
205     }
206
207     /**
208      * @param schemaPreviewFile
209      * @param schema
210      * @throws IOException
211      */

212     private void recreateSchemaPreviewFileContents(File JavaDoc schemaPreviewFile,
213             ISchema schema) throws IOException JavaDoc {
214         SchemaTransformer transformer = new SchemaTransformer();
215         OutputStream JavaDoc os = new FileOutputStream JavaDoc(schemaPreviewFile);
216         PrintWriter JavaDoc printWriter = new PrintWriter JavaDoc(os, true);
217         transformer.transform(schema, printWriter);
218         os.flush();
219         os.close();
220     }
221     
222     /**
223      * Reacts to changes in the plugin.xml or fragment.xml file.
224      * <ul>
225      * <li>If the file has been deleted and the project has a MANIFEST.MF file,
226      * then this deletion only affects extensions and extension points.</li>
227      * <li>If the file has been deleted and the project does not have a MANIFEST.MF file,
228      * then it's an old-style plug-in and the entire model must be removed from the table.</li>
229      * <li>If the file has been added and the project already has a MANIFEST.MF, then
230      * this file only contributes extensions and extensions. No need to send a notification
231      * to trigger update classpath of dependent plug-ins</li>
232      * <li>If the file has been added and the project does not have a MANIFEST.MF, then
233      * an old-style plug-in has been created.</li>
234      * <li>If the file has been modified and the project already has a MANIFEST.MF,
235      * then reload the extensions model but do not send out notifications</li>
236      * </li>If the file has been modified and the project has no MANIFEST.MF, then
237      * it's an old-style plug-in, reload and send out notifications to trigger a classpath update
238      * for dependent plug-ins</li>
239      * </ul>
240      * @param file the manifest file
241      * @param delta the resource delta
242      */

243     private void handleExtensionFileDelta(IFile file, IResourceDelta delta) {
244         int kind = delta.getKind();
245         IPluginModelBase model = (IPluginModelBase)getModel(file.getProject());
246         if (kind == IResourceDelta.REMOVED) {
247             if (model instanceof IBundlePluginModelBase) {
248                 ((IBundlePluginModelBase)model).setExtensionsModel(null);
249             } else {
250                 removeModel(file.getProject());
251             }
252         } else if (kind == IResourceDelta.ADDED) {
253             if (model instanceof IBundlePluginModelBase){
254                 WorkspaceExtensionsModel extensions = new WorkspaceExtensionsModel(file);
255                 ((IBundlePluginModelBase)model).setExtensionsModel(extensions);
256                 extensions.setBundleModel((IBundlePluginModelBase)model);
257                 loadModel(extensions, false);
258             } else {
259                 createModel(file.getProject(), true);
260             }
261         } else if (kind == IResourceDelta.CHANGED
262                     && (IResourceDelta.CONTENT & delta.getFlags()) != 0) {
263             if (model instanceof IBundlePluginModelBase) {
264                 ISharedExtensionsModel extensions = ((IBundlePluginModelBase)model).getExtensionsModel();
265                 boolean reload = extensions != null;
266                 if (extensions == null) {
267                     extensions = new WorkspaceExtensionsModel(file);
268                     ((IBundlePluginModelBase)model).setExtensionsModel(extensions);
269                     ((WorkspaceExtensionsModel)extensions).setBundleModel((IBundlePluginModelBase)model);
270                 }
271                 loadModel(extensions, reload);
272             } else if (model != null) {
273                 loadModel(model, true);
274                 addChange(model, IModelProviderEvent.MODELS_CHANGED);
275             }
276         }
277     }
278     
279     /**
280      * Reacts to changes in the MANIFEST.MF file.
281      * <ul>
282      * <li>If the file has been deleted, switch to the old-style plug-in if a plugin.xml file exists</li>
283      * <li>If the file has been added, create a new bundle model</li>
284      * <li>If the file has been modified, reload the model, reset the resource bundle
285      * if the localization has changed and fire a notification that the model has changed</li>
286      * </ul>
287      *
288      * @param file the manifest file that was modified
289      * @param delta the resource delta
290      */

291     private void handleBundleManifestDelta(IFile file, IResourceDelta delta) {
292         int kind = delta.getKind();
293         IProject project = file.getProject();
294         Object JavaDoc model = getModel(project);
295         if (kind == IResourceDelta.REMOVED && model != null) {
296             removeModel(project);
297             // switch to legacy plugin structure, if applicable
298
createModel(project, true);
299         } else if (kind == IResourceDelta.ADDED || model == null) {
300             createModel(project, true);
301         } else if (kind == IResourceDelta.CHANGED
302                     && (IResourceDelta.CONTENT & delta.getFlags()) != 0) {
303             if (model instanceof IBundlePluginModelBase) {
304                 // check to see if localization changed (bug 146912)
305
String JavaDoc oldLocalization = ((IBundlePluginModelBase)model).getBundleLocalization();
306                 IBundleModel bmodel = ((IBundlePluginModelBase)model).getBundleModel();
307                 boolean wasFragment = bmodel.isFragmentModel();
308                 loadModel(bmodel, true);
309                 String JavaDoc newLocalization = ((IBundlePluginModelBase)model).getBundleLocalization();
310                 
311                 // Fragment-Host header was added or removed
312
if (wasFragment != bmodel.isFragmentModel()) {
313                     removeModel(project);
314                     createModel(project, true);
315                 } else {
316                     if (model instanceof AbstractNLModel &&
317                             (oldLocalization != null && (newLocalization == null || !oldLocalization.equals(newLocalization))) ||
318                             (newLocalization != null && (oldLocalization == null || !newLocalization.equals(oldLocalization))))
319                         ((AbstractNLModel)model).resetNLResourceHelper();
320                     addChange(model, IModelProviderEvent.MODELS_CHANGED);
321                 }
322             }
323         }
324     }
325     
326     /**
327      * Removes the model associated with the given project from the table,
328      * if the given project is a plug-in project
329      */

330     protected Object JavaDoc removeModel(IProject project) {
331         Object JavaDoc model = super.removeModel(project);
332         if (model != null && project.exists(new Path(".options"))) //$NON-NLS-1$
333
PDECore.getDefault().getTracingOptionsManager().reset();
334         return model;
335     }
336     
337     /**
338      * Returns a plug-in model associated with the given project, or <code>null</code>
339      * if the project is not a plug-in project or the manifest file is missing vital data
340      * such as a symbolic name or version
341      *
342      * @param project the given project
343      *
344      * @return a plug-in model associated with the given project or <code>null</code>
345      * if no such valid model exists
346      */

347     protected IPluginModelBase getPluginModel(IProject project) {
348         return (IPluginModelBase)getModel(project);
349     }
350     
351     /**
352      * Returns a list of all workspace plug-in models
353      *
354      * @return an array of workspace plug-in models
355      */

356     protected IPluginModelBase[] getPluginModels() {
357         initialize();
358         return (IPluginModelBase[])fModels.values().toArray(new IPluginModelBase[fModels.size()]);
359     }
360     
361     /**
362      * Adds listeners to the workspace and to the java model
363      * to be notified of PRE_CLOSE events and POST_CHANGE events.
364      */

365     protected void addListeners() {
366         IWorkspace workspace = PDECore.getWorkspace();
367         workspace.addResourceChangeListener(this, IResourceChangeEvent.PRE_CLOSE);
368         // PDE must process the POST_CHANGE events before the Java model
369
// for the PDE container classpath update to proceed smoothly
370
JavaCore.addPreProcessingResourceChangedListener(this, IResourceChangeEvent.POST_CHANGE);
371     }
372
373     /**
374      * Removes listeners that the model manager attached on others,
375      * as well as listeners attached on the model manager
376      */

377     protected void removeListeners() {
378         PDECore.getWorkspace().removeResourceChangeListener(this);
379         JavaCore.removePreProcessingResourceChangedListener(this);
380         super.removeListeners();
381     }
382     
383     /**
384      * Returns true if the folder being visited is of interest to PDE.
385      * In this case, PDE is only interested in META-INF folders at the root of a plug-in project
386      * We are also interested in schema folders
387      *
388      * @return <code>true</code> if the folder (and its children) is of interest to PDE;
389      * <code>false</code> otherwise.
390      *
391      */

392     protected boolean isInterestingFolder(IFolder folder) {
393         if (folder.getName().equals("META-INF") && folder.getParent() instanceof IProject) { //$NON-NLS-1$
394
return true;
395         }
396         
397         if (folder.getName().equals("schema") && folder.getParent() instanceof IProject) { //$NON-NLS-1$
398
return true;
399         }
400         
401         return false;
402     }
403     
404     /**
405      * This method is called when workspace models are read and initialized
406      * from the cache. No need to read the workspace plug-ins from scratch.
407      *
408      * @param models the workspace plug-in models
409      */

410     protected void initializeModels(IPluginModelBase[] models) {
411         fModels = Collections.synchronizedMap(new HashMap JavaDoc());
412         for (int i = 0; i < models.length; i++) {
413             IProject project = models[i].getUnderlyingResource().getProject();
414             fModels.put(project, models[i]);
415         }
416         addListeners();
417     }
418     
419     /**
420      * Return URLs to projects in the workspace that have a manifest file (MANIFEST.MF
421      * or plugin.xml)
422      *
423      * @return an array of URLs to workspace plug-ins
424      */

425     protected URL JavaDoc[] getPluginPaths() {
426         ArrayList JavaDoc list = new ArrayList JavaDoc();
427         IProject[] projects = PDECore.getWorkspace().getRoot().getProjects();
428         for (int i = 0; i < projects.length; i++) {
429             if (isPluginProject(projects[i])) {
430                 try {
431                     IPath path = projects[i].getLocation();
432                     if (path != null) {
433                         list.add(path.toFile().toURL());
434                     }
435                 } catch (MalformedURLException JavaDoc e) {
436                 }
437             }
438         }
439         return (URL JavaDoc[])list.toArray(new URL JavaDoc[list.size()]);
440     }
441     
442 }
443
Popular Tags