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;
011:
012: import java.io.ByteArrayInputStream;
013: import java.io.ByteArrayOutputStream;
014: import java.io.File;
015: import java.io.IOException;
016: import java.io.InputStream;
017: import java.util.ArrayList;
018: import java.util.Iterator;
019: import java.util.Locale;
020: import java.util.Map;
021: import java.util.Properties;
022: import java.util.Set;
023: import java.util.StringTokenizer;
024: import java.util.TreeMap;
025: import java.util.TreeSet;
026:
027: import org.eclipse.core.resources.IFile;
028: import org.eclipse.core.resources.IProject;
029: import org.eclipse.core.resources.ISaveContext;
030: import org.eclipse.core.resources.ISaveParticipant;
031: import org.eclipse.core.resources.IWorkspaceRoot;
032: import org.eclipse.core.runtime.CoreException;
033: import org.eclipse.core.runtime.IPath;
034: import org.eclipse.core.runtime.IProgressMonitor;
035: import org.eclipse.core.runtime.NullProgressMonitor;
036: import org.eclipse.core.runtime.Path;
037: import org.eclipse.core.runtime.SubProgressMonitor;
038: import org.eclipse.jdt.core.ElementChangedEvent;
039: import org.eclipse.jdt.core.IClasspathContainer;
040: import org.eclipse.jdt.core.IClasspathEntry;
041: import org.eclipse.jdt.core.IElementChangedListener;
042: import org.eclipse.jdt.core.IJavaElementDelta;
043: import org.eclipse.jdt.core.IJavaModel;
044: import org.eclipse.jdt.core.IJavaProject;
045: import org.eclipse.jdt.core.IPackageFragmentRoot;
046: import org.eclipse.jdt.core.JavaCore;
047: import org.eclipse.jdt.core.JavaModelException;
048: import org.eclipse.jdt.launching.JavaRuntime;
049: import org.eclipse.osgi.util.NLS;
050: import org.eclipse.pde.core.plugin.IPluginModelBase;
051: import org.eclipse.pde.core.plugin.ModelEntry;
052: import org.eclipse.pde.core.plugin.PluginRegistry;
053: import org.eclipse.pde.internal.core.util.CoreUtility;
054:
055: /**
056: * This class manages the ability of external plug-ins in the model manager to
057: * take part in the Java search. It manages a proxy Java projects and for each
058: * external plug-in added to Java search, it adds its Java libraries as external
059: * JARs to the proxy project. This makes the libraries visible to the Java
060: * model, and they can take part in various Java searches.
061: */
062: public class SearchablePluginsManager implements IFileAdapterFactory,
063: IPluginModelListener, ISaveParticipant {
064:
065: private static final String PROXY_FILE_NAME = ".searchable"; //$NON-NLS-1$
066: public static final String PROXY_PROJECT_NAME = "External Plug-in Libraries"; //$NON-NLS-1$
067: private static final String KEY = "searchablePlugins"; //$NON-NLS-1$
068:
069: private Listener fElementListener;
070: private Set fPluginIdSet;
071: private ArrayList fListeners;
072:
073: class Listener implements IElementChangedListener {
074: public void elementChanged(ElementChangedEvent e) {
075: if (e.getType() == ElementChangedEvent.POST_CHANGE) {
076: handleDelta(e.getDelta());
077: }
078: }
079:
080: private boolean handleDelta(IJavaElementDelta delta) {
081: Object element = delta.getElement();
082: if (element instanceof IJavaModel) {
083: IJavaElementDelta[] projectDeltas = delta
084: .getAffectedChildren();
085: for (int i = 0; i < projectDeltas.length; i++) {
086: if (handleDelta(projectDeltas[i]))
087: break;
088: }
089: return true;
090: }
091: if (delta.getElement() instanceof IJavaProject) {
092: IJavaProject project = (IJavaProject) delta
093: .getElement();
094: if (project.getElementName().equals(PROXY_PROJECT_NAME)) {
095: if (delta.getKind() == IJavaElementDelta.REMOVED) {
096: fPluginIdSet.clear();
097: } else if (delta.getKind() == IJavaElementDelta.ADDED) {
098: initializeStates();
099: }
100: }
101: return true;
102: }
103: return false;
104: }
105: }
106:
107: public SearchablePluginsManager() {
108: initializeStates();
109: fElementListener = new Listener();
110: JavaCore.addElementChangedListener(fElementListener);
111: PDECore.getDefault().getModelManager().addPluginModelListener(
112: this );
113: }
114:
115: private void initializeStates() {
116: fPluginIdSet = new TreeSet();
117: IWorkspaceRoot root = PDECore.getWorkspace().getRoot();
118: IProject project = root.getProject(PROXY_PROJECT_NAME);
119: try {
120: if (project.exists() && project.isOpen()) {
121: IFile proxyFile = project.getFile(PROXY_FILE_NAME);
122: if (proxyFile.exists()) {
123: Properties properties = new Properties();
124: InputStream stream = proxyFile.getContents(true);
125: properties.load(stream);
126: stream.close();
127: String value = properties.getProperty(KEY);
128: if (value != null) {
129: StringTokenizer stok = new StringTokenizer(
130: value, ","); //$NON-NLS-1$
131: while (stok.hasMoreTokens())
132: fPluginIdSet.add(stok.nextToken());
133: }
134: }
135: }
136: } catch (IOException e) {
137: } catch (CoreException e) {
138: }
139: }
140:
141: public IJavaProject getProxyProject() {
142: IWorkspaceRoot root = PDECore.getWorkspace().getRoot();
143: IProject project = root.getProject(PROXY_PROJECT_NAME);
144: try {
145: if (project.exists() && project.isOpen()
146: && project.hasNature(JavaCore.NATURE_ID)) {
147: return JavaCore.create(project);
148: }
149:
150: } catch (CoreException e) {
151: }
152: return null;
153: }
154:
155: public void shutdown() throws CoreException {
156: // remove listener
157: JavaCore.removeElementChangedListener(fElementListener);
158: PDECore.getDefault().getModelManager()
159: .removePluginModelListener(this );
160: if (fListeners != null)
161: fListeners.clear();
162: }
163:
164: public IClasspathEntry[] computeContainerClasspathEntries()
165: throws CoreException {
166: ArrayList result = new ArrayList();
167:
168: IPluginModelBase[] wModels = PluginRegistry
169: .getWorkspaceModels();
170: for (int i = 0; i < wModels.length; i++) {
171: IProject project = wModels[i].getUnderlyingResource()
172: .getProject();
173: if (project.hasNature(JavaCore.NATURE_ID)) {
174: result.add(JavaCore.newProjectEntry(project
175: .getFullPath()));
176: }
177: }
178: Iterator iter = fPluginIdSet.iterator();
179: while (iter.hasNext()) {
180: ModelEntry entry = PluginRegistry.findEntry(iter.next()
181: .toString());
182: if (entry != null) {
183: boolean addModel = true;
184: wModels = entry.getWorkspaceModels();
185: for (int i = 0; i < wModels.length; i++) {
186: IProject project = wModels[i]
187: .getUnderlyingResource().getProject();
188: if (project.hasNature(JavaCore.NATURE_ID))
189: addModel = false;
190: }
191: if (!addModel)
192: continue;
193: IPluginModelBase[] models = entry.getExternalModels();
194: for (int i = 0; i < models.length; i++) {
195: if (models[i].isEnabled())
196: ClasspathUtilCore.addLibraries(models[i],
197: result);
198: }
199: }
200: }
201:
202: if (result.size() > 1) {
203: // sort
204: Map map = new TreeMap();
205: for (int i = 0; i < result.size(); i++) {
206: IClasspathEntry entry = (IClasspathEntry) result.get(i);
207: String key = entry.getPath().lastSegment().toString();
208: if (map.containsKey(key)) {
209: key += System.currentTimeMillis();
210: }
211: map.put(key, entry);
212: }
213: return (IClasspathEntry[]) map.values().toArray(
214: new IClasspathEntry[map.size()]);
215: }
216: return (IClasspathEntry[]) result
217: .toArray(new IClasspathEntry[result.size()]);
218: }
219:
220: public Object createAdapterChild(FileAdapter parent, File file) {
221: if (!file.isDirectory()) {
222: String name = file.getName().toLowerCase(Locale.ENGLISH);
223: try {
224: if (name.endsWith(".jar")) { //$NON-NLS-1$
225: IPackageFragmentRoot root = findPackageFragmentRoot(new Path(
226: file.getAbsolutePath()));
227: if (root != null)
228: return root;
229: }
230: } catch (CoreException e) {
231: PDECore.log(e);
232: }
233: }
234: return new FileAdapter(parent, file, this );
235: }
236:
237: private IPackageFragmentRoot findPackageFragmentRoot(IPath jarPath)
238: throws CoreException {
239: IJavaProject jProject = getProxyProject();
240: if (jProject != null) {
241: try {
242: IPackageFragmentRoot[] roots = jProject
243: .getAllPackageFragmentRoots();
244: for (int i = 0; i < roots.length; i++) {
245: IPackageFragmentRoot root = roots[i];
246: IPath path = root.getPath();
247: if (path.equals(jarPath))
248: return root;
249:
250: }
251: } catch (JavaModelException e) {
252: }
253: }
254:
255: // Find in other plugin (and fragments) projects dependencies
256: IPluginModelBase[] pluginModels = PluginRegistry
257: .getWorkspaceModels();
258: for (int i = 0; i < pluginModels.length; i++) {
259: IProject project = pluginModels[i].getUnderlyingResource()
260: .getProject();
261: IJavaProject javaProject = JavaCore.create(project);
262: try {
263: IPackageFragmentRoot[] roots = javaProject
264: .getAllPackageFragmentRoots();
265: for (int j = 0; j < roots.length; j++) {
266: IPackageFragmentRoot root = roots[j];
267: IPath path = root.getPath();
268: if (path.equals(jarPath))
269: return root;
270: }
271: } catch (JavaModelException e) {
272: }
273: }
274:
275: return null;
276: }
277:
278: private void checkForProxyProject() {
279: IWorkspaceRoot root = PDECore.getWorkspace().getRoot();
280: try {
281: IProject project = root
282: .getProject(SearchablePluginsManager.PROXY_PROJECT_NAME);
283: if (!project.exists())
284: createProxyProject(new NullProgressMonitor());
285: } catch (CoreException e) {
286: }
287: }
288:
289: public void addToJavaSearch(IPluginModelBase[] models) {
290: checkForProxyProject();
291: PluginModelDelta delta = new PluginModelDelta();
292: int size = fPluginIdSet.size();
293: for (int i = 0; i < models.length; i++) {
294: String id = models[i].getPluginBase().getId();
295: if (fPluginIdSet.add(id)) {
296: ModelEntry entry = PluginRegistry.findEntry(id);
297: if (entry != null)
298: delta.addEntry(entry, PluginModelDelta.CHANGED);
299: }
300: }
301: if (fPluginIdSet.size() > size) {
302: resetContainer();
303: fireDelta(delta);
304: }
305: }
306:
307: public void removeFromJavaSearch(IPluginModelBase[] models) {
308: PluginModelDelta delta = new PluginModelDelta();
309: int size = fPluginIdSet.size();
310: for (int i = 0; i < models.length; i++) {
311: String id = models[i].getPluginBase().getId();
312: if (fPluginIdSet.remove(id)) {
313: ModelEntry entry = PluginRegistry.findEntry(id);
314: if (entry != null) {
315: delta.addEntry(entry, PluginModelDelta.CHANGED);
316: }
317: }
318: }
319: if (fPluginIdSet.size() < size) {
320: resetContainer();
321: fireDelta(delta);
322: }
323: }
324:
325: public boolean isInJavaSearch(String symbolicName) {
326: return fPluginIdSet.contains(symbolicName);
327: }
328:
329: private void resetContainer() {
330: IJavaProject jProject = getProxyProject();
331: try {
332: if (jProject != null) {
333: JavaCore
334: .setClasspathContainer(
335: PDECore.JAVA_SEARCH_CONTAINER_PATH,
336: new IJavaProject[] { jProject },
337: new IClasspathContainer[] { new ExternalJavaSearchClasspathContainer() },
338: null);
339: }
340: } catch (JavaModelException e) {
341: }
342: }
343:
344: public void modelsChanged(PluginModelDelta delta) {
345: ModelEntry[] entries = delta.getRemovedEntries();
346: for (int i = 0; i < entries.length; i++) {
347: if (fPluginIdSet.contains(entries[i].getId())) {
348: fPluginIdSet.remove(entries[i].getId());
349: }
350: }
351: resetContainer();
352: }
353:
354: private void fireDelta(PluginModelDelta delta) {
355: if (fListeners != null) {
356: for (int i = 0; i < fListeners.size(); i++) {
357: ((IPluginModelListener) fListeners.get(i))
358: .modelsChanged(delta);
359: }
360: }
361: }
362:
363: public void addPluginModelListener(IPluginModelListener listener) {
364: if (fListeners == null)
365: fListeners = new ArrayList();
366: if (!fListeners.contains(listener))
367: fListeners.add(listener);
368: }
369:
370: public void removePluginModelListener(IPluginModelListener listener) {
371: if (fListeners != null)
372: fListeners.remove(listener);
373: }
374:
375: public void doneSaving(ISaveContext context) {
376: // nothing is required here
377: }
378:
379: public void prepareToSave(ISaveContext context)
380: throws CoreException {
381: // no need for preparation
382: }
383:
384: public void rollback(ISaveContext context) {
385: // do nothing. not the end of the world.
386: }
387:
388: public void saving(ISaveContext context) throws CoreException {
389: if (context.getKind() != ISaveContext.FULL_SAVE)
390: return;
391:
392: // persist state
393: IWorkspaceRoot root = PDECore.getWorkspace().getRoot();
394: IProject project = root.getProject(PROXY_PROJECT_NAME);
395: if (project.exists() && project.isOpen()) {
396: IFile file = project.getFile(PROXY_FILE_NAME);
397: Properties properties = new Properties();
398: StringBuffer buffer = new StringBuffer();
399: Iterator iter = fPluginIdSet.iterator();
400: while (iter.hasNext()) {
401: if (buffer.length() > 0)
402: buffer.append(","); //$NON-NLS-1$
403: buffer.append(iter.next().toString());
404: }
405: properties.setProperty(KEY, buffer.toString());
406: try {
407: ByteArrayOutputStream outStream = new ByteArrayOutputStream();
408: properties.store(outStream, ""); //$NON-NLS-1$
409: outStream.flush();
410: outStream.close();
411: ByteArrayInputStream inStream = new ByteArrayInputStream(
412: outStream.toByteArray());
413: if (file.exists())
414: file.setContents(inStream, true, false,
415: new NullProgressMonitor());
416: else
417: file.create(inStream, true,
418: new NullProgressMonitor());
419: inStream.close();
420: } catch (IOException e) {
421: PDECore.log(e);
422: }
423: }
424: }
425:
426: public IProject createProxyProject(IProgressMonitor monitor)
427: throws CoreException {
428: IWorkspaceRoot root = PDECore.getWorkspace().getRoot();
429: IProject project = root
430: .getProject(SearchablePluginsManager.PROXY_PROJECT_NAME);
431: if (project.exists()) {
432: if (!project.isOpen()) {
433: project.open(monitor);
434: }
435: return project;
436: }
437:
438: monitor
439: .beginTask(
440: NLS
441: .bind(
442: PDECoreMessages.SearchablePluginsManager_createProjectTaskName,
443: SearchablePluginsManager.PROXY_PROJECT_NAME),
444: 5);
445: project.create(new SubProgressMonitor(monitor, 1));
446: project.open(new SubProgressMonitor(monitor, 1));
447: CoreUtility.addNatureToProject(project, JavaCore.NATURE_ID,
448: new SubProgressMonitor(monitor, 1));
449: IJavaProject jProject = JavaCore.create(project);
450: jProject.setOutputLocation(project.getFullPath(),
451: new SubProgressMonitor(monitor, 1));
452: computeClasspath(jProject, new SubProgressMonitor(monitor, 1));
453: return project;
454: }
455:
456: private void computeClasspath(IJavaProject project,
457: IProgressMonitor monitor) throws CoreException {
458: IClasspathEntry[] classpath = new IClasspathEntry[2];
459: classpath[0] = JavaCore.newContainerEntry(JavaRuntime
460: .newDefaultJREContainerPath());
461: classpath[1] = JavaCore
462: .newContainerEntry(PDECore.JAVA_SEARCH_CONTAINER_PATH);
463: try {
464: project.setRawClasspath(classpath, monitor);
465: } catch (JavaModelException e) {
466: }
467: }
468:
469: }
|