blob: 5c4b2209ed4b282644a37068d135f639e8108e77 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2015 EclipseSource Muenchen GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Eugen Neufeld - initial API and implementation
* Edgar Mueller - refactorings
******************************************************************************/
package org.eclipse.emf.ecp.view.internal.provider;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecp.view.spi.model.VView;
import org.eclipse.emf.ecp.view.spi.model.VViewFactory;
import org.eclipse.emf.ecp.view.spi.model.VViewModelProperties;
import org.eclipse.emf.ecp.view.spi.provider.EMFFormsViewService;
import org.eclipse.emf.ecp.view.spi.provider.IViewProvider;
import org.eclipse.emf.ecp.view.spi.provider.reporting.NoViewProviderFoundReport;
import org.eclipse.emf.ecp.view.spi.provider.reporting.ViewModelIsNullReport;
import org.eclipse.emf.ecp.view.spi.provider.reporting.ViewProviderInitFailedReport;
import org.eclipse.emfforms.spi.common.report.AbstractReport;
import org.eclipse.emfforms.spi.common.report.ReportService;
import org.osgi.framework.Bundle;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
/**
* Implementation of the {@link EMFFormsViewService} which collects all known {@link IViewProvider} and finds the best
* fitting view.
*
* @author Eugen Neufeld
*/
@Component(name = "EMFFormsViewService")
public class ViewProviderImpl implements EMFFormsViewService {
private static final String CLASS_CANNOT_BE_RESOLVED = "%1$s cannot be loaded because bundle %2$s cannot be resolved."; //$NON-NLS-1$
private static final String CLASS = "class"; //$NON-NLS-1$
private static final String EXTENSION_POINT_ID = "org.eclipse.emf.ecp.ui.view.viewModelProviders"; //$NON-NLS-1$
private final Set<IViewProvider> viewProviders = new CopyOnWriteArraySet<IViewProvider>();
private ReportService reportService;
/**
* Component activate method.
*/
@Activate
protected void activate() {
readViewProviders();
}
private void readViewProviders() {
final IConfigurationElement[] controls = Platform.getExtensionRegistry()
.getConfigurationElementsFor(
EXTENSION_POINT_ID);
for (final IConfigurationElement e : controls) {
try {
final String clazz = e.getAttribute(CLASS);
final Class<? extends IViewProvider> resolvedClass = loadClass(e
.getContributor().getName(), clazz);
final Constructor<? extends IViewProvider> controlConstructor = resolvedClass
.getConstructor();
final IViewProvider viewProvider = controlConstructor.newInstance();
viewProviders.add(viewProvider);
} catch (final ClassNotFoundException ex) {
report(new ViewProviderInitFailedReport(ex));
} catch (final NoSuchMethodException ex) {
report(new ViewProviderInitFailedReport(ex));
} catch (final SecurityException ex) {
report(new ViewProviderInitFailedReport(ex));
} catch (final InstantiationException ex) {
report(new ViewProviderInitFailedReport(ex));
} catch (final IllegalAccessException ex) {
report(new ViewProviderInitFailedReport(ex));
} catch (final IllegalArgumentException ex) {
report(new ViewProviderInitFailedReport(ex));
} catch (final InvocationTargetException ex) {
report(new ViewProviderInitFailedReport(ex));
}
}
}
private void report(AbstractReport reportEntity) {
reportService.report(reportEntity);
}
@SuppressWarnings("unchecked")
private static <T> Class<T> loadClass(String bundleName, String clazz)
throws ClassNotFoundException {
final Bundle bundle = Platform.getBundle(bundleName);
if (bundle == null) {
throw new ClassNotFoundException(String.format(
CLASS_CANNOT_BE_RESOLVED, clazz, bundleName));
}
return (Class<T>) bundle.loadClass(clazz);
}
/**
* This allows to retrieve a {@link VView} based on an {@link EObject}. This method reads all {@link IViewProvider
* IViewProviders} and searches for the best fitting. If none can be found, then null is returned.
*
* @param eObject the {@link EObject} to find a {@link VView} for
* @param properties the {@link VViewModelProperties properties}
* @return a view model for the given {@link EObject} or null if no suited provider could be found
*/
@Override
public VView getView(EObject eObject, VViewModelProperties properties) {
double highestPrio = IViewProvider.NOT_APPLICABLE;
IViewProvider selectedProvider = null;
if (properties == null) {
properties = VViewFactory.eINSTANCE.createViewModelLoadingProperties();
}
if (viewProviders.isEmpty()) {
report(new NoViewProviderFoundReport());
}
for (final IViewProvider viewProvider : viewProviders) {
final double prio = viewProvider.canProvideViewModel(eObject, properties);
if (prio > highestPrio) {
highestPrio = prio;
selectedProvider = viewProvider;
}
}
if (selectedProvider != null) {
final VView view = selectedProvider.provideViewModel(eObject, properties);
if (view == null) {
report(new ViewModelIsNullReport());
}
return view;
}
return null;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.provider.EMFFormsViewService#addProvider(org.eclipse.emf.ecp.view.spi.provider.IViewProvider)
*/
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
@Override
public void addProvider(IViewProvider viewProvider) {
viewProviders.add(viewProvider);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.provider.EMFFormsViewService#removeProvider(org.eclipse.emf.ecp.view.spi.provider.IViewProvider)
*/
@Override
public void removeProvider(IViewProvider viewProvider) {
viewProviders.remove(viewProvider);
}
/**
* Set the ReportService.
*
* @param reportService The {@link ReportService}
*/
@Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.STATIC, unbind = "-")
protected void setReportService(ReportService reportService) {
this.reportService = reportService;
}
}