| /** |
| * |
| * 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 v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation |
| */ |
| package org.eclipse.osbp.osgi.hybrid.api; |
| |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.annotation.PostConstruct; |
| import javax.annotation.PreDestroy; |
| import javax.inject.Inject; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.core.di.extensions.EventUtils; |
| import org.eclipse.e4.core.services.events.IEventBroker; |
| import org.eclipse.e4.ui.model.application.MApplication; |
| import org.eclipse.e4.ui.model.application.ui.MUIElement; |
| import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective; |
| import org.eclipse.e4.ui.model.application.ui.basic.MPart; |
| import org.eclipse.e4.ui.workbench.modeling.EModelService; |
| import org.eclipse.e4.ui.workbench.modeling.EPartService; |
| import org.eclipse.e4.ui.workbench.modeling.IPartListener; |
| import org.eclipse.osbp.bpm.api.IBlipBPMConstants; |
| import org.eclipse.osbp.dsl.common.datatypes.IDto; |
| import org.eclipse.osbp.eventbroker.EventBrokerMsg; |
| import org.eclipse.osbp.persistence.IPersistenceService; |
| import org.eclipse.osbp.runtime.web.vaadin.databinding.VaadinObservables; |
| import org.eclipse.osbp.ui.api.themes.IThemeResourceService; |
| import org.eclipse.osbp.ui.api.themes.IThemeResourceService.ThemeResourceType; |
| import org.eclipse.osbp.ui.api.useraccess.AbstractAuthorization.Permission; |
| import org.eclipse.osbp.ui.api.useraccess.AbstractAuthorization.PermissionResult; |
| import org.eclipse.osbp.ui.api.useraccess.AbstractPosition; |
| import org.eclipse.osbp.ui.api.useraccess.IPermissionList; |
| import org.eclipse.osbp.utils.common.IEntityIdModificationListenerView; |
| import org.eclipse.osbp.webserver.messagequeue.ECXMqMessageAttribute; |
| import org.eclipse.osbp.webserver.messagequeue.ECXMqMessageEvent; |
| import org.osgi.service.event.Event; |
| import org.osgi.service.event.EventHandler; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.vaadin.server.VaadinRequest; |
| import com.vaadin.ui.AbstractOrderedLayout; |
| import com.vaadin.ui.FormLayout; |
| import com.vaadin.ui.Label; |
| import com.vaadin.ui.UI; |
| import com.vaadin.ui.VerticalLayout; |
| |
| public abstract class AbstractHybridVaaclipseView implements IHybridVaadinVaaclipseListener, IPartListener, IEntityIdModificationListenerView { |
| |
| @Inject |
| IEventBroker eventBroker; |
| |
| @Inject |
| protected IPersistenceService persistenceService; |
| |
| // |
| // @Inject |
| // private AbstractBlipBPMFunctionProvider taskProvider; |
| // |
| // @Inject |
| // protected IBPMTaskClient taskClient; |
| // |
| // private String workloadDtoFqn; |
| // private IDto initialWorkloadDto; |
| // private Class<?> operativeDtoClass; |
| // private List<IDto> initialOperativeDtos; |
| |
| private static final Logger LOGGER = LoggerFactory.getLogger(AbstractHybridVaaclipseView.class); |
| |
| public static enum RenderMode { |
| SYNCHRONOUSLY, ASYNCHRONOUSLY |
| } |
| |
| private final IEclipseContext fEclipseContext; |
| private final MApplication fE4App; |
| private final VerticalLayout fParent; |
| private boolean fViewInitialized; |
| protected final EventHandler fModifiedEntityIdsListener; |
| private Map<String, Set<Object>> fListeningForEntityIdsModifications = new HashMap<>(); |
| |
| private RenderMode renderMode = RenderMode.ASYNCHRONOUSLY; |
| private boolean firstTime = true; |
| private int pollingInterval = 2000; |
| |
| private RecursiveFocusBlurListener fRecursiveFocusBlurListener; |
| |
| /** |
| * <b><i><u>Warning:</u> never use initializing class attributes in the definition!<br> |
| * Due to Java specific internals the overriden method createView() will be called before that initializing will be done!<br> |
| * Instead put any initializing inside the overriden method createView()!</i></b> |
| * |
| * @param parent |
| * @param context |
| * @param app |
| */ |
| public AbstractHybridVaaclipseView(final VerticalLayout parent, final IEclipseContext context, final MApplication app) { |
| fE4App = app; |
| fEclipseContext = context; |
| fViewInitialized = false; |
| fParent = parent; |
| fModifiedEntityIdsListener = new EventHandler() { |
| |
| @Override |
| public void handleEvent(Event event) { |
| Object data = event.getProperty(EventUtils.DATA); |
| // --- only if data contains an event broker message --- |
| if (data instanceof EventBrokerMsg) { |
| EventBrokerMsg eventBrokerMsg = (EventBrokerMsg) data; |
| // eventBrokerMsg.getInt() == 1 means INSERT and no id check is required |
| // otherwise it is an UPDATE and a id check is mandatory |
| if (eventBrokerMsg.getInt() == 1) { |
| refreshViewDueToModifiedEntityId(eventBrokerMsg.getName(), eventBrokerMsg.getId()); |
| } else { |
| checkOnModifiedEntityId(eventBrokerMsg, true); |
| } |
| } |
| } |
| }; |
| fRecursiveFocusBlurListener = RecursiveFocusBlurListener.attachFor(fParent); |
| } |
| |
| @PostConstruct |
| public void initView() { |
| preInit(); |
| VaadinObservables.getRealm(UI.getCurrent()); |
| UI.getCurrent().setPollInterval(pollingInterval); |
| createView(fParent); |
| postInit(null); |
| renderData(true); |
| } |
| |
| public void promptSecurityMessage(String message, AbstractOrderedLayout layout) { |
| layout.removeAllComponents(); |
| FormLayout area = new FormLayout(); |
| layout.addComponent(area); |
| |
| Label msg = new Label(message); |
| msg.setPrimaryStyleName("osbp"); |
| msg.setStyleName("osbpSecurityPrompt"); |
| if (getThemeResourceService() != null) { |
| msg.setIcon(getThemeResourceService().getThemeResource("locksview.gif", ThemeResourceType.IMAGE)); |
| } |
| else { |
| LOGGER.error("themeResourceService not set!"); |
| } |
| area.addComponent(msg); |
| } |
| |
| private String beautifyEntityName(String entityName) { |
| return StringUtils.strip(entityName.replace('.', '/'), "/").toLowerCase(); |
| } |
| |
| private Object beautifyEntityId(Object id) { |
| if (id instanceof String) { |
| id = ((String) id).trim(); |
| try { |
| Double.parseDouble((String) id); |
| // --- if it's a double --- |
| id = StringUtils.removeEnd((String) id, "0"); |
| id = StringUtils.removeEnd((String) id, "."); |
| } catch (Exception e) { |
| // NOTHING CAN BE DONE |
| } |
| } |
| return id; |
| } |
| |
| @Override |
| public void resetListeningForEntityIdsModifications() { |
| fListeningForEntityIdsModifications = null; |
| } |
| |
| public boolean broadcastEntityIdModified(String packageName, String entityName, String id) { |
| if (eventBroker != null) { |
| return eventBroker.send(EventBrokerMsg.REFRESH_VIEW + EventBrokerMsg.getEntityIdModifiedCategory(packageName, entityName), new EventBrokerMsg(id, entityName)); |
| } else { |
| return false; |
| } |
| } |
| |
| @Override |
| public boolean checkOnModifiedEntityId(EventBrokerMsg message, boolean doRefresh) { |
| return checkOnModifiedEntityId(message.getName(), message.getId(), doRefresh); |
| } |
| |
| @Override |
| public boolean checkOnModifiedEntityId(String entityName, Object id, boolean doRefresh) { |
| // --- check if the entity sent is known --- |
| entityName = beautifyEntityName(entityName); |
| id = beautifyEntityId(id); |
| Set<Object> ids = fListeningForEntityIdsModifications.get(entityName); |
| if (ids instanceof Set) { |
| // --- if the id for that entity is known --- |
| if (ids.contains(id)) { |
| // --- force refresh of the report --- |
| if (doRefresh) { |
| refreshViewDueToModifiedEntityId(entityName, id); |
| } |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public void refreshViewDueToModifiedEntityId(String entity, Object id) { |
| addEntityIdToModifyListener(entity, id); |
| } |
| |
| @Override |
| public void addEntityIdToModifyListener(String entityName, Object id) { |
| // --- build the entity map if necessary --- |
| if (fListeningForEntityIdsModifications == null) { |
| fListeningForEntityIdsModifications = new HashMap<>(); |
| } |
| entityName = beautifyEntityName(entityName); |
| Set<Object> ids = fListeningForEntityIdsModifications.get(entityName); |
| // --- build the ids set if necessary --- |
| if (ids == null) { |
| ids = new HashSet<>(); |
| fListeningForEntityIdsModifications.put(entityName, ids); |
| } |
| // --- put the primary key --- |
| ids.add(beautifyEntityId(id)); |
| } |
| |
| @Override |
| public void removeEntityIdFromModifyListener(String entityName, Object id) { |
| // --- build the entity map if necessary --- |
| if (fListeningForEntityIdsModifications != null) { |
| Set<Object> ids = fListeningForEntityIdsModifications.get(beautifyEntityName(entityName)); |
| // --- build the ids set if necessary --- |
| if (ids != null) { |
| // --- put the primary key --- |
| ids.remove(id); |
| } |
| } |
| } |
| |
| public final MApplication getApplication() { |
| return fE4App; |
| } |
| |
| public final VerticalLayout getParent() { |
| return fParent; |
| } |
| |
| public final IEclipseContext getContext() { |
| return fEclipseContext; |
| } |
| |
| public final MPart getPart() { |
| return (MPart) fEclipseContext.get(MPart.class); |
| } |
| |
| public final String getProcessWorkloadDtoFqn() { |
| return (String) getTransientDataVariable(IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO_FQN); |
| } |
| |
| public final IDto getProcessInitialWorkloadDto() { |
| return (IDto) getTransientDataVariable(IBlipBPMConstants.VARIABLE_PROCESS_WORKLOAD_DTO); |
| } |
| |
| public final Class<?> getTaskOperativeDtoClass() { |
| return (Class<?>) getTransientDataVariable(IBlipBPMConstants.VARIABLE_TASK_OPERATIVE_DTO_CLASS); |
| } |
| |
| public final String getTaskOperativeDtoFqn() { |
| return (String) getTransientDataVariable(IBlipBPMConstants.VARIABLE_TASK_OPERATIVE_DTO_FQN); |
| } |
| |
| public final List<IDto> getTaskInitialOperativeDtos() { |
| return (List<IDto>) getTransientDataVariable(IBlipBPMConstants.VARIABLE_TASK_OPERATIVE_DTOS); |
| } |
| |
| public final Object getTransientDataVariable(String variable) { |
| MPerspective perspective = getPerspective(); |
| if (perspective != null) { |
| Map<String, Object> data = perspective.getTransientData(); |
| if (data != null) { |
| return data.get(variable); |
| } |
| } |
| return null; |
| } |
| |
| public final MPerspective getPerspective() { |
| MUIElement step = getPart(); |
| while ((step != null) && !(step instanceof MPerspective)) { |
| step = step.getParent(); |
| } |
| return (MPerspective) step; |
| } |
| |
| public final IPersistenceService getPersistenceService() { |
| return (IPersistenceService) fEclipseContext.get(IPersistenceService.class); |
| } |
| |
| protected final boolean isViewInitialized() { |
| return fViewInitialized; |
| } |
| |
| /** |
| * <b><i><u>Warning:</u> put any initializing inside the your overriden method createView()!<br> |
| * Due to Java specific internals the overriden method createView() will be called before that initializing will be done!</i></b> |
| * |
| * @param parent |
| */ |
| abstract protected void createView(final VerticalLayout parent); |
| |
| abstract protected void createComponents(); |
| |
| // renderData is used for components that are not fully embedded in vaadin's connector structure |
| // and must be repainted when parent window resizes |
| // but can also be used to make component rendering asynchronously from view creation |
| public void renderData() { |
| LOGGER.debug("renderData not firsttime"); |
| renderData(false); |
| } |
| |
| public void renderData(boolean firstTime) { |
| // the first time we only want to be triggered by the initial createView process, not by changeLocale |
| if (this.firstTime) { |
| if (!firstTime) { |
| LOGGER.debug("renderData ignored because not firsttime"); |
| return; |
| } else { |
| this.firstTime = false; |
| } |
| } |
| if (UI.getCurrent() == null) { |
| LOGGER.debug("renderData has no current ui"); |
| return; |
| } |
| if (renderMode == RenderMode.SYNCHRONOUSLY) { |
| LOGGER.debug("render synchronously"); |
| UI.getCurrent().accessSynchronously(new Runnable() { |
| @Override |
| public void run() { |
| createComponents(); |
| } |
| }); |
| } else { |
| LOGGER.debug("render asynchronously"); |
| UI.getCurrent().access(new Runnable() { |
| @Override |
| public void run() { |
| createComponents(); |
| } |
| }); |
| } |
| } |
| |
| private IThemeResourceService getThemeResourceService() { |
| if (fEclipseContext.containsKey(IThemeResourceService.class)) { |
| return fEclipseContext.get(IThemeResourceService.class); |
| } |
| return null; |
| } |
| |
| private EPartService getPartService() { |
| if (fEclipseContext.containsKey(EPartService.class)) { |
| return fEclipseContext.get(EPartService.class); |
| } |
| return null; |
| } |
| |
| protected void preInit() { |
| getPartService().addPartListener(this); |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).addListener(this); |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).setE4Application(fE4App); |
| } |
| |
| @PreDestroy |
| public void preDestroy() { |
| fRecursiveFocusBlurListener.detach(); |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).removeListener(this); |
| fListeningForEntityIdsModifications = null; |
| } |
| |
| /** |
| * You <b>must call this at the end of the overridden init()</b> |
| */ |
| protected final void postInit(VaadinRequest request) { |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).postInit(request); |
| fViewInitialized = true; |
| if (isAuthenticated()) { |
| setAuthenticated(isAuthenticated()); |
| } |
| } |
| |
| /** |
| * React in the application according to <code>authenticated</code> |
| * |
| * @param authenticated |
| * true if the user is authenticated now! |
| */ |
| public void setAuthenticated(boolean authenticated) { |
| // now send the list of perspectives |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).updatePerspectiveList(); |
| } |
| |
| protected final boolean isAuthenticated() { |
| return HybridVaadinVaaclipseConnector.instance(fEclipseContext).isAuthenticated(); |
| } |
| |
| protected final IDto getAuthenticatedUser() { |
| return HybridVaadinVaaclipseConnector.instance(fEclipseContext).getUser(); |
| } |
| |
| protected final AbstractPosition getAuthenticatedPosition() { |
| return HybridVaadinVaaclipseConnector.instance(fEclipseContext).getPosition(); |
| } |
| |
| protected final Collection<String> getAuthenticatedRoles() { |
| return HybridVaadinVaaclipseConnector.instance(fEclipseContext).getRoles(); |
| } |
| |
| protected final IPermissionList getAuthenticatedPermissions() { |
| return HybridVaadinVaaclipseConnector.instance(fEclipseContext).getPermissions(); |
| } |
| |
| protected final PermissionResult isAuthenticatedPermitted(Permission permission) { |
| return HybridVaadinVaaclipseConnector.instance(fEclipseContext).isPermitted(permission); |
| } |
| |
| protected final Set<String> getAllUsers() { |
| return HybridVaadinVaaclipseConnector.instance(fEclipseContext).getAllUsers(); |
| } |
| |
| /** |
| * Try to authenticate with the credentials given!<br> |
| * {@link #setAuthenticated(boolean)} will explicit be called! |
| * |
| * @param portalId |
| * @param userName |
| * @param password |
| * @return true if the user was authenticated successful |
| */ |
| // protected boolean tryToAuthenticate(String portalId, String userName, String password) { |
| // return HybridVaadinVaaclipseConnector.instance().tryToAuthenticate(portalId, userName, password); |
| // } |
| |
| /** |
| * Logout from the Shiro API and send a LOGOUT event via ActiveMQ |
| */ |
| protected void logout() { |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).logout(); |
| } |
| |
| /** |
| * handle any message received via ActiveMQ |
| * |
| * @param event |
| * @param body |
| */ |
| @Override |
| public final boolean onMessage(ECXMqMessageEvent event, Map<ECXMqMessageAttribute, Object> body) { |
| boolean retcode = false; |
| switch (event) { |
| // !!! handled by connector ... |
| case TRY_AUTHENTICATE: |
| case DISPOSE: |
| case LOGOUT: |
| break; |
| // ... handled by connector !!! |
| case FOCUS_PERSPECTIVE: |
| retcode = HybridVaadinVaaclipseConnector.instance(fEclipseContext).onFocusPerspective(body.get(ECXMqMessageAttribute.PERSPECTIVE_ID).toString()); |
| break; |
| case REQUEST_ICON: |
| retcode = HybridVaadinVaaclipseConnector.instance(fEclipseContext).requestIcon(body.get(ECXMqMessageAttribute.PERSPECTIVE_ID).toString()); |
| break; |
| default: |
| break; |
| } |
| return retcode; |
| } |
| |
| @Override |
| public void partActivated(MPart part) { |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).activatePartStateRefresher(part); |
| MPerspective active = HybridVaadinVaaclipseConnector.findCurrentPerspectiveFor(part == null ? getPartService().getActivePart() : part); |
| if (active instanceof MPerspective) { |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).updatePerspectiveList(); |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).updateFocusPerspective(active.getElementId()); |
| } else if ((part != null || getPartService().getActivePart() != null)) { |
| LOGGER.debug("part activated:" + (part == null ? "<null>" : part.getElementId() + " '" + part.getLabel() + "'")); |
| List<MPerspective> existing = HybridVaadinVaaclipseConnector.instance(fEclipseContext).findPerspectives(); |
| for (MPerspective perspective : existing) { |
| LOGGER.debug(" perspective:" + perspective.getElementId() + " '" + perspective.getLabel() + "'"); |
| } |
| LOGGER.debug(" COULD NOT find the corresponding perspective :-("); |
| } |
| } |
| |
| @Override |
| public void partBroughtToTop(MPart part) { |
| HybridVaadinVaaclipseConnector.instance(fEclipseContext).activatePartStateRefresher(part); |
| } |
| |
| @Override |
| public void partDeactivated(MPart part) { |
| } // NOP |
| |
| @Override |
| public void partHidden(MPart part) { |
| } // NOP |
| |
| @Override |
| public void partVisible(MPart part) { |
| } // NOP |
| |
| /** |
| * Try to authenticate with the credentials given!<br> |
| * {@link #setAuthenticated(boolean)} will explicit be called! |
| * |
| * @param portalId |
| * @param userName |
| * @param password |
| * @return true if the user was authenticated successful |
| */ |
| protected boolean tryToAuthenticate(String portalId, String userName, String password) { |
| return HybridVaadinVaaclipseConnector.instance(fEclipseContext).tryToAuthenticate(portalId, userName, password); |
| } |
| |
| public RenderMode getRenderMode() { |
| return renderMode; |
| } |
| |
| public void setRenderMode(RenderMode renderMode) { |
| this.renderMode = renderMode; |
| } |
| |
| public int getPollingInterval() { |
| return pollingInterval; |
| } |
| |
| public void setPollingInterval(int pollingInterval) { |
| this.pollingInterval = pollingInterval; |
| } |
| |
| } |