blob: f3d0a2f282112454b5ec632bcc8908678dd86017 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2017 BestSolution.at and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
******************************************************************************/
package org.eclipse.e4.tools.services.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.e4.tools.services.IResourcePool;
import org.eclipse.e4.tools.services.IResourceProviderService;
import org.eclipse.e4.tools.services.IResourceService;
import org.eclipse.e4.tools.services.ToolsServicesActivator;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Resource;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
public class ResourceService implements IResourceService {
private enum Type {
IMAGE, FONT, COLOR
}
static class PooledResource<T extends Resource> implements
IPooledResource<T> {
private final Display display;
private int count;
private T resource;
private String id;
private ResourceService resourceService;
PooledResource(Display display, ResourceService resourceService,
String id, T resource) {
this.display = display;
this.id = id;
this.count = 1;
this.resourceService = resourceService;
this.resource = resource;
}
@Override
public String getId() {
return id;
}
@Override
public T getResource() {
return resource;
}
@Override
public void dispose() {
this.count--;
if (this.count == 0) {
resourceService.removePooledResource(this);
if (resource != null) {
resource.dispose();
}
resource = null;
id = null;
resourceService = null;
}
}
}
public static class ResourcePool implements IDiposeableResourcePool {
private IResourceService resourceService;
private List<IPooledResource<Image>> pooledImages = new ArrayList<>();
private List<IPooledResource<Font>> pooledFonts = new ArrayList<>();
private List<IPooledResource<Color>> pooledColors = new ArrayList<>();
private final Display display;
@Inject
public ResourcePool(IResourceService resourceService, Display display) {
this.display = display;
this.resourceService = resourceService;
}
@Override
public Image getImage(String key) throws CoreException {
if (resourceService == null) {
throw new CoreException(
new Status(IStatus.ERROR,
ToolsServicesActivator.PLUGIN_ID,
Messages.ResourceService_PoolDisposed));
}
IPooledResource<Image> image = null;
for (final IPooledResource<Image> img : pooledImages) {
if (img.getId().equals(key)) {
image = img;
}
}
if (image == null) {
image = resourceService.getImage(display, key);
pooledImages.add(image);
}
return image.getResource();
}
@Override
public Font getFont(String key) throws CoreException {
if (resourceService == null) {
throw new CoreException(
new Status(IStatus.ERROR,
ToolsServicesActivator.PLUGIN_ID,
Messages.ResourceService_PoolDisposed));
}
IPooledResource<Font> font = null;
for (final IPooledResource<Font> fon : pooledFonts) {
if (fon.getId().equals(key)) {
font = fon;
}
}
if (font == null) {
font = resourceService.getFont(display, key);
pooledFonts.add(font);
}
return font.getResource();
}
@Override
public Color getColor(String key) throws CoreException {
if (resourceService == null) {
throw new CoreException(
new Status(IStatus.ERROR,
ToolsServicesActivator.PLUGIN_ID,
Messages.ResourceService_PoolDisposed));
}
IPooledResource<Color> color = null;
for (final IPooledResource<Color> col : pooledColors) {
if (col.getId().equals(key)) {
color = col;
}
}
if (color == null) {
color = resourceService.getColor(display,
key);
pooledColors.add(color);
}
return color.getResource();
}
@Override
public Image getImageUnchecked(String key) {
try {
return getImage(key);
} catch (final CoreException e) {
return null;
}
}
@Override
public Font getFontUnchecked(String key) {
try {
return getFont(key);
} catch (final CoreException e) {
return null;
}
}
@Override
public Color getColorUnchecked(String key) {
try {
return getColor(key);
} catch (final CoreException e) {
return null;
}
}
@Override
@PreDestroy
public void dispose() {
for (final IPooledResource<Image> img : pooledImages) {
img.dispose();
}
for (final IPooledResource<Font> font : pooledFonts) {
font.dispose();
}
for (final IPooledResource<Color> col : pooledColors) {
col.dispose();
}
resourceService = null;
pooledImages = null;
pooledFonts = null;
pooledColors = null;
}
}
static class DisplayPool {
private Map<String, PooledResource<Image>> imagePool;
private Map<String, PooledResource<Color>> colorPool;
private Map<String, PooledResource<Font>> fontPool;
public Map<String, PooledResource<Color>> getColorPool() {
if (colorPool == null) {
colorPool = new HashMap<>();
}
return colorPool;
}
public Map<String, PooledResource<Image>> getImagePool() {
if (imagePool == null) {
imagePool = new HashMap<>();
}
return imagePool;
}
public Map<String, PooledResource<Font>> getFontPool() {
if (fontPool == null) {
fontPool = new HashMap<>();
}
return fontPool;
}
}
private final Map<Display, DisplayPool> displayPool = new HashMap<>();
// private Map<String, IResourceProviderService> imagekey2providers = new
// HashMap<String, IResourceProviderService>();
// private Map<String, IResourceProviderService> fontkey2providers = new
// HashMap<String, IResourceProviderService>();
// private Map<String, IResourceProviderService> colorkey2providers = new
// HashMap<String, IResourceProviderService>();
private final BundleContext context;
public ResourceService() {
final Bundle b = FrameworkUtil.getBundle(ResourceService.class);
context = b.getBundleContext();
}
protected void removePooledResource(PooledResource<?> resource) {
if (resource.getResource() instanceof Image) {
displayPool.get(resource.display).getImagePool().remove(resource.getId());
} else if (resource.getResource() instanceof Color) {
displayPool.get(resource.display).getColorPool().remove(resource.getId());
} else if (resource.getResource() instanceof Font) {
displayPool.get(resource.display).getFontPool().remove(resource.getId());
}
}
@SuppressWarnings("unchecked")
private <R extends Resource> PooledResource<R> loadResource(
Display display, String key, Type type) {
DisplayPool p = displayPool.get(display);
PooledResource<R> resource = null;
if (p != null) {
if (type == Type.IMAGE) {
resource = (PooledResource<R>) p.getImagePool().get(key);
} else if (type == Type.COLOR) {
resource = (PooledResource<R>) p.getColorPool().get(key);
} else {
resource = (PooledResource<R>) p.getFontPool().get(key);
}
}
if (resource != null && resource.getResource() != null) {
resource.count++;
} else {
resource = new PooledResource<>(display, this, key,
(R) lookupResource(display, key, type));
if (p == null) {
p = new DisplayPool();
displayPool.put(display, p);
}
if (type == Type.IMAGE) {
p.getImagePool().put(key, (PooledResource<Image>) resource);
} else if (type == Type.COLOR) {
p.getColorPool().put(key, (PooledResource<Color>) resource);
} else {
p.getFontPool().put(key, (PooledResource<Font>) resource);
}
}
return resource;
}
@SuppressWarnings("unchecked")
private <R> R lookupResource(Display display, String key, Type type) {
if (type == Type.IMAGE) {
final IResourceProviderService provider = lookupOSGI(key);
if (provider != null) {
return (R) provider.getImage(display, key);
}
} else if (type == Type.COLOR) {
final IResourceProviderService provider = lookupOSGI(key);
if (provider != null) {
return (R) provider.getColor(display, key);
}
} else {
final IResourceProviderService provider = lookupOSGI(key);
if (provider != null) {
return (R) provider.getFont(display, key);
}
}
throw new IllegalArgumentException(Messages.ResourceService_NoProvider + key
+ "'."); //$NON-NLS-1$
}
private IResourceProviderService lookupOSGI(String key) {
try {
final Collection<ServiceReference<IResourceProviderService>> refs = context
.getServiceReferences(IResourceProviderService.class, "(" //$NON-NLS-1$
+ key + "=*)"); //$NON-NLS-1$
if (!refs.isEmpty()) {
final ServiceReference<IResourceProviderService> ref = refs
.iterator().next();
return context.getService(ref);
}
} catch (final InvalidSyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
// public void addProvider(IResourceProviderService provider,
// Map<String, String> map) {
// for (Entry<String, String> e : map.entrySet()) {
// if( e.getKey().startsWith("IMAGE") ) {
// imagekey2providers.put(e.getKey(), provider);
// } else if( e.getKey().startsWith("FONT") ) {
// fontkey2providers.put(e.getKey(), provider);
// } else if( e.getKey().startsWith("COLOR") ) {
// colorkey2providers.put(e.getKey(), provider);
// }
// }
// }
//
// public void removeProvider(IResourceProviderService provider,
// Map<String, String> map) {
// for (Entry<String, String> e : map.entrySet()) {
// if( e.getKey().startsWith("IMAGE") ) {
// imagekey2providers.remove(e.getKey());
// } else if( e.getKey().startsWith("FONT") ) {
// fontkey2providers.remove(e.getKey());
// } else if( e.getKey().startsWith("COLOR") ) {
// colorkey2providers.remove(e.getKey());
// }
// }
// }
@Override
public PooledResource<Image> getImage(Display display, String key) {
return loadResource(display, key, Type.IMAGE);
}
@Override
public PooledResource<Color> getColor(Display display, String key) {
return loadResource(display, key, Type.COLOR);
}
@Override
public PooledResource<Font> getFont(Display display, String key) {
return loadResource(display, key, Type.FONT);
}
@Override
public IDiposeableResourcePool getResourcePool(Display display) {
return new ResourcePool(this, display);
}
@Override
public IResourcePool getControlPool(Control control) {
final ResourcePool pool = new ResourcePool(this, control.getDisplay());
control.addDisposeListener(e -> pool.dispose());
return pool;
}
}