blob: 7428a802ec91ee55329803255e1ee15dcaee5287 [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* 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:
* Florian Pirchner - Initial implementation
*
*/
package org.eclipse.osbp.ecview.extension.presentation.vaadin.components.common;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.osbp.ecview.core.common.context.ContextException;
import org.eclipse.osbp.ecview.core.common.context.IViewContext;
import org.eclipse.osbp.ecview.core.common.extender.IECViewProviderService;
import org.eclipse.osbp.ecview.core.common.model.core.YView;
import org.eclipse.osbp.runtime.web.ecview.presentation.vaadin.VaadinRenderer;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.VerticalLayout;
/**
* This component shows an rendered ECView component for the given DTO instance.
* <p>
* Attention: This component needs to be {@link #dispose() disposed} if not used
* anymore.
*/
@SuppressWarnings("serial")
public class ECViewComponent extends CustomComponent {
/** The Constant LOGGER. */
private static final Logger LOGGER = LoggerFactory
.getLogger(ECViewComponent.class);
/** The cache. */
private Map<String, IViewContext> cache = new HashMap<>();
/** The layout. */
private VerticalLayout layout;
/** The current view context. */
private IViewContext currentViewContext;
/** The callback. */
private ViewProviderCallback callback;
/**
* Instantiates a new EC view component.
*/
public ECViewComponent() {
this(null);
}
/**
* Instantiates a new EC view component.
*
* @param callback
* the callback
*/
public ECViewComponent(ViewProviderCallback callback) {
this.callback = callback;
setSizeFull();
layout = new VerticalLayout();
layout.setSizeFull();
setCompositionRoot(layout);
}
/**
* Will render and show a bound view instance for the given dto.
*
* @param viewId
* the id of the view
* @param dto
* the dto instance to be displayed
* @param properties
* render properties
* @return the rendered view context or <code>null</code>.
*/
public IViewContext setValue(String viewId, Object dto,
Map<String, Object> properties) {
// if the type of dto did not change, we only need to set the new dto
// instance
String currentId = null;
if (currentViewContext != null) {
currentId = currentViewContext.getViewEditpart().getName();
}
if (viewId.equals(currentId)) {
currentViewContext.setBean(getBeanSlotName(properties), dto);
} else {
// remove all components
layout.removeAllComponents();
// determine the resulting ui content
IViewContext context = cache.get(viewId);
if (context == null) {
context = createNewContext(viewId, properties);
}
if (context != null) {
if (!context.isRendered()) {
try {
new VaadinRenderer()
.render(context, layout, properties);
} catch (ContextException e) {
LOGGER.error("{}", e);
Notification.show(
viewId + " caused " + e.getLocalizedMessage()
+ "!", Type.ERROR_MESSAGE);
}
}
// set data to the view
if (dto != null) {
context.setBean(getBeanSlotName(properties), dto);
}
}
currentViewContext = context;
}
return currentViewContext;
}
/**
* Gets the bean slot name.
*
* @param properties
* the properties
* @return the bean slot name
*/
protected String getBeanSlotName(Map<String, Object> properties) {
return (String) properties.get(IViewContext.PROP_SLOT);
}
/**
* Creates a new context for the given dto using the properties.
*
* @param viewId
* the view id
* @param properties
* the properties
* @return the i view context
*/
protected IViewContext createNewContext(String viewId,
Map<String, Object> properties) {
IViewContext context = null;
BundleContext bc = FrameworkUtil.getBundle(getClass())
.getBundleContext();
ServiceReference<IECViewProviderService> ref = bc
.getServiceReference(IECViewProviderService.class);
if (ref != null) {
IECViewProviderService service = bc.getService(ref);
YView yView = null;
// check whether the owner wants to contribute a view model
if (callback != null) {
yView = callback.getView(viewId, properties);
}
if (yView != null) {
// create a context for the provided view model
context = service.getViewContext(yView);
} else {
// else check the service for a proper view model
context = service.getViewContext(viewId);
}
if (context != null) {
cache.put(viewId, context);
}
bc.ungetService(ref);
} else {
LOGGER.error("No view available for " + viewId);
}
return context;
}
/**
* Disposes the component.
*/
public void dispose() {
cache.values().forEach(it -> {
try {
it.dispose();
} catch (Exception e) {
LOGGER.error("{}", e);
}
});
cache.clear();
cache = null;
layout = null;
currentViewContext = null;
}
/**
* A callback class to allow owners of this class to create context specifix
* views.
*/
public interface ViewProviderCallback {
/**
* Returns a custom view for the given id and properties. Or
* <code>null</code> if a default view should be used.
*
* @param viewId
* the view id
* @param properties
* the properties
* @return the view
*/
YView getView(String viewId, Map<String, Object> properties);
}
}