001: /*******************************************************************************
002: * Copyright (c) 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.BufferedInputStream;
013: import java.io.File;
014: import java.io.FileInputStream;
015: import java.io.FileNotFoundException;
016: import java.io.IOException;
017: import java.io.InputStream;
018: import java.util.zip.ZipEntry;
019: import java.util.zip.ZipFile;
020:
021: import javax.xml.parsers.SAXParserFactory;
022:
023: import org.eclipse.core.runtime.IContributor;
024: import org.eclipse.core.runtime.IExtensionRegistry;
025: import org.eclipse.core.runtime.spi.IDynamicExtensionRegistry;
026: import org.eclipse.core.runtime.spi.RegistryContributor;
027: import org.eclipse.core.runtime.spi.RegistryStrategy;
028: import org.eclipse.osgi.service.resolver.BundleDescription;
029: import org.eclipse.osgi.service.resolver.HostSpecification;
030: import org.eclipse.pde.core.plugin.IPluginModelBase;
031: import org.eclipse.pde.core.plugin.ModelEntry;
032: import org.osgi.util.tracker.ServiceTracker;
033:
034: public class PDERegistryStrategy extends RegistryStrategy {
035:
036: /**
037: * Tracker for the XML parser service
038: */
039: private ServiceTracker xmlTracker = null;
040:
041: private Object fKey = null;
042:
043: private ModelListener fModelListener = null;
044: private ExtensionListener fExtensionListener = null;
045: private PDEExtensionRegistry fPDERegistry = null;
046:
047: class RegistryListener {
048: IExtensionRegistry fRegistry;
049:
050: protected final void removeModels(IPluginModelBase[] bases,
051: boolean onlyInactive) {
052: for (int i = 0; i < bases.length; i++) {
053: // resetModel(bases[i]);
054: if (onlyInactive && bases[i].isEnabled())
055: continue;
056: removeBundle(fRegistry, bases[i]);
057: }
058: }
059:
060: public void setRegistry(IExtensionRegistry registry) {
061: fRegistry = registry;
062: }
063: }
064:
065: class ModelListener extends RegistryListener implements
066: IPluginModelListener {
067:
068: public void modelsChanged(PluginModelDelta delta) {
069: if (fRegistry == null)
070: createRegistry();
071: // can ignore removed models since the ModelEntries is empty
072: ModelEntry[] entries = delta.getChangedEntries();
073: for (int i = 0; i < entries.length; i++) {
074: // remove all external models if there are any workspace models since they are considered 'activeModels'. See ModelEntry.getActiveModels().
075: removeModels(entries[i].getExternalModels(),
076: !entries[i].hasWorkspaceModels());
077: removeModels(entries[i].getWorkspaceModels(), true);
078: addBundles(fRegistry, entries[i].getActiveModels());
079: }
080: entries = delta.getAddedEntries();
081: for (int i = 0; i < entries.length; i++)
082: addBundles(fRegistry, entries[i].getActiveModels());
083: }
084:
085: }
086:
087: class ExtensionListener extends RegistryListener implements
088: IExtensionDeltaListener {
089:
090: public void extensionsChanged(IExtensionDeltaEvent event) {
091: if (fRegistry == null)
092: createRegistry();
093: removeModels(event.getRemovedModels(), false);
094: removeModels(event.getChangedModels(), false);
095: addBundles(fRegistry, event.getChangedModels());
096: addBundles(fRegistry, event.getAddedModels());
097: }
098:
099: }
100:
101: public PDERegistryStrategy(File[] storageDirs,
102: boolean[] cacheReadOnly, Object key,
103: PDEExtensionRegistry registry) {
104: super (storageDirs, cacheReadOnly);
105: init();
106: fKey = key;
107: fPDERegistry = registry;
108: }
109:
110: protected void init() {
111: connectListeners();
112: }
113:
114: protected void connectListeners() {
115: // Listen for model changes to register new bundles and unregister removed bundles
116: PluginModelManager manager = PDECore.getDefault()
117: .getModelManager();
118: manager
119: .addPluginModelListener(fModelListener = new ModelListener());
120: manager
121: .addExtensionDeltaListener(fExtensionListener = new ExtensionListener());
122: }
123:
124: protected void setListenerRegistry(IExtensionRegistry registry) {
125: if (fModelListener != null)
126: fModelListener.setRegistry(registry);
127: if (fExtensionListener != null)
128: fExtensionListener.setRegistry(registry);
129: }
130:
131: public void onStart(IExtensionRegistry registry,
132: boolean loadedFromCache) {
133: super .onStart(registry, loadedFromCache);
134: setListenerRegistry(registry);
135: if (!loadedFromCache)
136: processBundles(registry);
137: }
138:
139: public void onStop(IExtensionRegistry registry) {
140: super .onStop(registry);
141: setListenerRegistry(null);
142: }
143:
144: /* (non-Javadoc)
145: * @see org.eclipse.core.runtime.spi.RegistryStrategy#getXMLParser()
146: */
147: public SAXParserFactory getXMLParser() {
148: if (xmlTracker == null) {
149: xmlTracker = new ServiceTracker(PDECore.getDefault()
150: .getBundleContext(), SAXParserFactory.class
151: .getName(), null);
152: xmlTracker.open();
153: }
154: return (SAXParserFactory) xmlTracker.getService();
155: }
156:
157: private void processBundles(IExtensionRegistry registry) {
158: addBundles(registry, fPDERegistry.getModels());
159: }
160:
161: private void addBundles(IExtensionRegistry registry,
162: IPluginModelBase[] bases) {
163: for (int i = 0; i < bases.length; i++)
164: addBundle(registry, bases[i]);
165: }
166:
167: private void addBundle(IExtensionRegistry registry,
168: IPluginModelBase base) {
169: IContributor contributor = createContributor(base);
170: if (contributor == null)
171: return;
172: if (((IDynamicExtensionRegistry) registry)
173: .hasContributor(contributor))
174: return;
175:
176: File input = getFile(base);
177: if (input == null)
178: return;
179: InputStream is = getInputStream(input, base);
180: if (is == null)
181: return;
182: registry.addContribution(new BufferedInputStream(is),
183: contributor, true, input.getPath(), null, fKey);
184: }
185:
186: private void removeBundle(IExtensionRegistry registry,
187: IPluginModelBase base) {
188: if (registry instanceof IDynamicExtensionRegistry) {
189: IContributor contributor = createContributor(base);
190: if (contributor != null
191: && ((IDynamicExtensionRegistry) registry)
192: .hasContributor(contributor)) {
193: ((IDynamicExtensionRegistry) registry)
194: .removeContributor(createContributor(base),
195: fKey);
196: }
197: }
198: }
199:
200: // added for releasing cached information from IPluginModelBase
201: // private void resetModel(IPluginModelBase model) {
202: // IPluginBase base = model.getPluginBase();
203: // if (base instanceof BundlePluginBase) {
204: // IExtensions ext = ((BundlePluginBase)base).getExtensionsRoot();
205: // if (ext != null && ext instanceof AbstractExtensions) {
206: // ((AbstractExtensions)ext).reset();
207: // }
208: // } else if (base instanceof AbstractExtensions){
209: // ((AbstractExtensions)base).resetExtensions();
210: // }
211: // }
212:
213: private File getFile(IPluginModelBase base) {
214: String loc = base.getInstallLocation();
215: File file = new File(loc);
216: if (!file.exists())
217: return null;
218: if (file.isFile())
219: return file;
220: String fileName = (base.isFragmentModel()) ? "fragment.xml" : "plugin.xml"; //$NON-NLS-1$ //$NON-NLS-2$
221: File inputFile = new File(file, fileName);
222: return (inputFile.exists()) ? inputFile : null;
223: }
224:
225: private InputStream getInputStream(File file, IPluginModelBase base) {
226: if (file.getName().endsWith(".jar")) { //$NON-NLS-1$
227: try {
228: ZipFile jfile = new ZipFile(file, ZipFile.OPEN_READ);
229: String fileName = (base.isFragmentModel()) ? "fragment.xml" : "plugin.xml"; //$NON-NLS-1$ //$NON-NLS-2$
230: ZipEntry entry = jfile.getEntry(fileName);
231: if (entry != null)
232: return jfile.getInputStream(entry);
233: } catch (IOException e) {
234: }
235: return null;
236: }
237: try {
238: return new FileInputStream(file);
239: } catch (FileNotFoundException e) {
240: }
241: return null;
242: }
243:
244: public IContributor createContributor(IPluginModelBase base) {
245: BundleDescription desc = base == null ? null : base
246: .getBundleDescription();
247: // return null if the IPluginModelBase does not have a BundleDescription (since then we won't have a valid 'id')
248: if (desc == null)
249: return null;
250: String name = desc.getSymbolicName();
251: String id = Long.toString(desc.getBundleId());
252: String hostName = null;
253: String hostId = null;
254:
255: HostSpecification host = desc.getHost();
256: // make sure model is a singleton. If it is a fragment, make sure host is singleton
257: if (host != null && host.getBundle() != null
258: && !host.getBundle().isSingleton() || host == null
259: && !desc.isSingleton())
260: return null;
261: if (host != null) {
262: BundleDescription hostDesc = host.getBundle();
263: hostName = hostDesc.getSymbolicName();
264: hostId = Long.toString(hostDesc.getBundleId());
265: }
266: return new RegistryContributor(id, name, hostId, hostName);
267: }
268:
269: public void dispose() {
270: PluginModelManager manager = PDECore.getDefault()
271: .getModelManager();
272: manager.removePluginModelListener(fModelListener);
273: manager.removeExtensionDeltaListener(fExtensionListener);
274: if (xmlTracker != null) {
275: xmlTracker.close();
276: xmlTracker = null;
277: }
278: }
279:
280: private void createRegistry() {
281: fPDERegistry.getRegistry();
282: }
283:
284: public long getContributionsTimestamp() {
285: IPluginModelBase[] bases = fPDERegistry.getModels();
286: long timeStamp = 0;
287: for (int i = 0; i < bases.length; i++) {
288: File location = getFile(bases[i]);
289: if (location != null)
290: timeStamp ^= location.lastModified();
291: }
292: return timeStamp;
293: }
294:
295: }
|