Merge remote-tracking branch 'eclipse/master' into cleanup-properties

# Conflicts:
#
hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.j
ava
This commit is contained in:
Kai Zimmermann
2016-03-04 12:11:35 +01:00
53 changed files with 1321 additions and 828 deletions

View File

@@ -14,12 +14,11 @@ import java.util.Set;
import javax.servlet.http.Cookie;
import org.eclipse.hawkbit.eventbus.event.EntityEvent;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.ui.components.SPUIErrorHandler;
import org.eclipse.hawkbit.ui.menu.DashboardEvent.PostViewChangeEvent;
import org.eclipse.hawkbit.ui.menu.DashboardMenu;
import org.eclipse.hawkbit.ui.menu.DashboardMenuItem;
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
import org.eclipse.hawkbit.ui.utils.I18N;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
@@ -28,14 +27,8 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventBus.SessionEventBus;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;
import com.vaadin.annotations.Title;
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.View;
@@ -45,9 +38,6 @@ import com.vaadin.server.ClientConnector.DetachListener;
import com.vaadin.server.Responsive;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinSession;
import com.vaadin.server.VaadinSession.State;
import com.vaadin.server.WrappedSession;
import com.vaadin.spring.navigator.SpringViewProvider;
import com.vaadin.ui.Component;
import com.vaadin.ui.CssLayout;
@@ -71,6 +61,8 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener {
private static final String EMPTY_VIEW = "";
private EventPushStrategy pushStrategy;
@Autowired
private SpringViewProvider viewProvider;
@@ -92,69 +84,37 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener {
protected transient EventBus.SessionEventBus eventBus;
/**
* An {@link com.google.common.eventbus.EventBus} subscriber which
* subscribes {@link EntityEvent} from the repository to dispatch these
* events to the UI {@link SessionEventBus}.
*
* @param event
* the entity event which has been published from the repository
* Default constructor.
*/
@Subscribe
@AllowConcurrentEvents
public void dispatch(final org.eclipse.hawkbit.eventbus.event.Event event) {
final VaadinSession session = getSession();
if (session == null || session.getState() != State.OPEN) {
return;
}
final WrappedSession wrappedSession = session.getSession();
if (wrappedSession == null) {
return;
}
final SecurityContext userContext = (SecurityContext) wrappedSession
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
if (!eventSecurityCheck(userContext, event)) {
return;
}
final SecurityContext oldContext = SecurityContextHolder.getContext();
try {
access(new DispatcherRunnable(eventBus, session, userContext, event));
} finally {
SecurityContextHolder.setContext(oldContext);
}
public HawkbitUI() {
// is empty, is ok.
}
protected boolean eventSecurityCheck(final SecurityContext userContext,
final org.eclipse.hawkbit.eventbus.event.Event event) {
if (userContext != null && userContext.getAuthentication() != null) {
final Object tenantAuthenticationDetails = userContext.getAuthentication().getDetails();
if (tenantAuthenticationDetails instanceof TenantAwareAuthenticationDetails) {
return ((TenantAwareAuthenticationDetails) tenantAuthenticationDetails).getTenant()
.equalsIgnoreCase(event.getTenant());
}
}
return false;
/**
* Constructor taking the push strategy.
*
* @param pushStrategy
* the strategy to push events from the backend to the UI
*/
public HawkbitUI(final EventPushStrategy pushStrategy) {
this.pushStrategy = pushStrategy;
}
/*
* (non-Javadoc)
*
* @see
* com.vaadin.server.ClientConnector.DetachListener#detach(com.vaadin.server
* .ClientConnector. DetachEvent)
*/
@Override
public void detach(final DetachEvent event) {
LOG.info("ManagementUI is detached uiid - {}", getUIId());
eventBus.unsubscribe(this);
if (pushStrategy != null) {
pushStrategy.clean();
}
}
@Override
protected void init(final VaadinRequest vaadinRequest) {
LOG.info("ManagementUI init starts uiid - {}", getUI().getUIId());
if (pushStrategy != null) {
pushStrategy.init(getUI());
}
addDetachListener(this);
SpringContextHelper.setContext(context);

View File

@@ -108,8 +108,10 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
public OutputStream receiveUpload(final String fileName, final String mimeType) {
this.fileName = fileName;
this.mimeType = mimeType;
//reset has directory flag before upload
view.setHasDirectory(false);
try {
if (view.validate()) {
if (view.checkIfSoftwareModuleIsSelected()) {
if (view.checkForDuplicate(fileName)) {
view.showDuplicateMessage();
} else {
@@ -167,7 +169,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
view.updateActionCount();
// display the duplicate message after streaming all files
view.displayDuplicateMessageAfterStreamingAll();
view.displayDuplicateValidationMessage();
}
/**
@@ -292,7 +294,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
if (view.enableProcessBtn()) {
infoWindow.uploadSessionFinished();
}
view.displayDuplicateMessageAfterStreamingAll();
view.displayDuplicateValidationMessage();
LOG.info("Streaming failed due to :{}", event.getException());
}
@@ -316,7 +318,6 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
}
view.updateActionCount();
infoWindow.uploadFailed(event.getFilename(), failureReason);
LOG.info("Upload failed for file :{}", event.getReason());
}

View File

@@ -46,6 +46,7 @@ import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventScope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
import com.google.common.base.Strings;
import com.vaadin.event.dd.DragAndDropEvent;
import com.vaadin.event.dd.DropHandler;
import com.vaadin.event.dd.acceptcriteria.AcceptAll;
@@ -116,6 +117,8 @@ public class UploadLayout extends VerticalLayout {
private DragAndDropWrapper dropAreaWrapper;
private Boolean hasDirectory = Boolean.FALSE;
/**
* Initialize the upload layout.
*/
@@ -182,27 +185,60 @@ public class UploadLayout extends VerticalLayout {
@Override
public void drop(final DragAndDropEvent event) {
if (validate()) {
if (validate(event)) {
final Html5File[] files = ((WrapperTransferable) event.getTransferable()).getFiles();
if (files != null) {
for (final Html5File file : files) {
if (!checkForDuplicate(file.getFileName())) {
numberOfFileUploadsExpected.incrementAndGet();
file.setStreamVariable(createStreamVariable(file));
}
}
if (numberOfFileUploadsExpected.get() > 0) {
processBtn.setEnabled(false);
// reset before we start
uploadInfoWindow.uploadSessionStarted();
}
// in case if all selected files are duplicate ,then display
// message
displayDuplicateMessageAfterStreamingAll();
// reset the flag
hasDirectory = Boolean.FALSE;
for (final Html5File file : files) {
processFile(file);
}
if (numberOfFileUploadsExpected.get() > 0) {
processBtn.setEnabled(false);
// reset before we start
uploadInfoWindow.uploadSessionStarted();
} else {
// If the upload is not started, it signifies all
// dropped files as either duplicate or directory.So
// display message accordingly
displayCompositeMessage();
}
}
}
private void processFile(final Html5File file) {
if (!isDirectory(file)) {
if (!checkForDuplicate(file.getFileName())) {
numberOfFileUploadsExpected.incrementAndGet();
file.setStreamVariable(createStreamVariable(file));
}
} else {
hasDirectory = Boolean.TRUE;
}
}
}
private static boolean isDirectory(final Html5File file) {
if (Strings.isNullOrEmpty(file.getType()) && file.getFileSize() % 4096 == 0) {
return true;
}
return false;
}
private void displayCompositeMessage() {
final String duplicateMessage = getDuplicateFileValidationMessage();
final StringBuilder compositeMessage = new StringBuilder();
if (!Strings.isNullOrEmpty(duplicateMessage)) {
compositeMessage.append(duplicateMessage);
}
if (hasDirectory) {
if (compositeMessage.length() > 0) {
compositeMessage.append("<br>");
}
compositeMessage.append(i18n.get("message.no.directory.upload"));
}
if (!compositeMessage.toString().isEmpty()) {
uiNotification.displayValidationError(compositeMessage.toString());
}
}
private VerticalLayout createDropAreaLayout() {
@@ -313,10 +349,33 @@ public class UploadLayout extends VerticalLayout {
}
}
Boolean validate() {
Boolean validate(DragAndDropEvent event) {
// check if drop is valid.If valid ,check if software module is
// selected.
if(!isFilesDropped(event)){
uiNotification.displayValidationError(i18n.get("message.action.not.allowed"));
return false;
}
return checkIfSoftwareModuleIsSelected();
}
private boolean isFilesDropped(DragAndDropEvent event) {
if (event.getTransferable() instanceof WrapperTransferable) {
final Html5File[] files = ((WrapperTransferable) event.getTransferable()).getFiles();
// other components can also be wrapped in WrapperTransferable , so
// additional check on files
if (files == null) {
return false;
}
return true;
} else {
return false;
}
}
Boolean checkIfSoftwareModuleIsSelected() {
if (!isSoftwareModuleSelected()) {
uiNotification.displayValidationError(i18n.get("message.error.noSwModuleSelected"));
return false;
}
return true;
@@ -381,27 +440,30 @@ public class UploadLayout extends VerticalLayout {
}
}
void displayDuplicateMessageAfterStreamingAll() {
void displayDuplicateValidationMessage() {
// check if streaming of all dropped files are completed
if (numberOfFilesActuallyUpload.intValue() == numberOfFileUploadsExpected.intValue()) {
showDuplicateMessage();
displayCompositeMessage();
}
}
/**
* Show duplicate file selected message.
*/
public void showDuplicateMessage() {
private String getDuplicateFileValidationMessage() {
StringBuilder message = new StringBuilder();
if (!duplicateFileNamesList.isEmpty()) {
final String fileNames = StringUtils.collectionToCommaDelimitedString(duplicateFileNamesList);
if (duplicateFileNamesList.size() == 1) {
uiNotification.displayValidationError(i18n.get("message.no.duplicateFile") + fileNames);
message.append(i18n.get("message.no.duplicateFile") + fileNames);
} else if (duplicateFileNamesList.size() > 1) {
uiNotification.displayValidationError(i18n.get("message.no.duplicateFiles"));
message.append(i18n.get("message.no.duplicateFiles"));
}
duplicateFileNamesList.clear();
}
return message.toString();
}
public void showDuplicateMessage() {
uiNotification.displayValidationError(getDuplicateFileValidationMessage());
}
void increaseNumberOfFileUploadsExpected() {
@@ -593,4 +655,8 @@ public class UploadLayout extends VerticalLayout {
return uiNotification;
}
public void setHasDirectory(Boolean hasDirectory) {
this.hasDirectory = hasDirectory;
}
}

View File

@@ -78,7 +78,7 @@ public class TargetTagToken extends AbstractTargetTagToken {
}
private TargetTagAssigmentResult toggleAssignment(final String tagNameSelected) {
final Set<String> targetList = new HashSet<String>();
final Set<String> targetList = new HashSet<>();
targetList.add(selectedTarget.getControllerId());
final TargetTagAssigmentResult result = targetManagement.toggleTagAssignment(targetList, tagNameSelected);
uinotification.displaySuccess(HawkbitCommonUtil.getTargetTagAssigmentMsg(tagNameSelected, result, i18n));
@@ -102,7 +102,7 @@ public class TargetTagToken extends AbstractTargetTagToken {
/* To Be Done : this implementation will vary in views */
private List<String> getClickedTagList() {
return new ArrayList<String>();
return new ArrayList<>();
}
@Override

View File

@@ -16,6 +16,7 @@ import java.util.StringJoiner;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.model.Action;
@@ -43,6 +44,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventScope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
@@ -417,10 +420,10 @@ public class ActionHistoryTable extends TreeTable implements Handler {
final org.eclipse.hawkbit.repository.model.Action action = deploymentManagement
.findActionWithDetails(actionId);
final Pageable pageReq = new PageRequest(0, 1000);
final Page<ActionStatus> actionStatusList = deploymentManagement
.findActionStatusMessagesByActionInDescOrder(pageReq, action,
managementUIState.isActionHistoryMaximized());
final Pageable pageReq = new PageRequest(0, 1000,
new Sort(Direction.DESC, ActionStatusFields.ID.getFieldName()));
final Page<ActionStatus> actionStatusList = deploymentManagement.findActionStatusByAction(pageReq, action,
managementUIState.isActionHistoryMaximized());
final List<ActionStatus> content = actionStatusList.getContent();
/*
* Since the recent action status and messages are already

View File

@@ -107,32 +107,15 @@ public class ManangementConfirmationWindowLayout extends AbstractConfirmationWin
super.inittialize();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.ui.common.confirmwindow.layout.
* AbstractConfirmationWindowLayout# getConfimrationTabs()
*/
@Override
protected Map<String, ConfirmationTab> getConfimrationTabs() {
final Map<String, ConfirmationTab> tabs = new HashMap<String, ConfirmationTab>();
/**
* create tab for deleted distribution.
*/
/* Create tab for SW Module Type delete */
final Map<String, ConfirmationTab> tabs = new HashMap<>();
if (!managementUIState.getDeletedDistributionList().isEmpty()) {
tabs.put(i18n.get("caption.delete.dist.accordion.tab"), createDeletedDistributionTab());
}
/**
* create tab for deleted target.
*/
if (!managementUIState.getDeletedTargetList().isEmpty()) {
tabs.put(i18n.get("caption.delete.target.accordion.tab"), createDeletedTargetTab());
}
/**
* create tab for assignment.
*/
if (!managementUIState.getAssignedList().isEmpty()) {
tabs.put(i18n.get("caption.assign.dist.accordion.tab"), createAssignmentTab());
}
@@ -196,8 +179,8 @@ public class ManangementConfirmationWindowLayout extends AbstractConfirmationWin
private void saveAllAssignments(final ConfirmationTab tab) {
final Set<TargetIdName> itemIds = managementUIState.getAssignedList().keySet();
Long distId;
List<TargetIdName> targetIdSetList = null;
List<TargetIdName> tempIdList = null;
List<TargetIdName> targetIdSetList;
List<TargetIdName> tempIdList;
final ActionType actionType = ((ActionTypeOptionGroupLayout.ActionTypeOption) actionTypeOptionGroupLayout
.getActionTypeOptionGroup().getValue()).getActionType();
final long forcedTimeStamp = (((ActionTypeOptionGroupLayout.ActionTypeOption) actionTypeOptionGroupLayout
@@ -205,7 +188,7 @@ public class ManangementConfirmationWindowLayout extends AbstractConfirmationWin
? actionTypeOptionGroupLayout.getForcedTimeDateField().getValue().getTime()
: Action.NO_FORCE_TIME;
final Map<Long, ArrayList<TargetIdName>> saveAssignedList = new HashMap<Long, ArrayList<TargetIdName>>();
final Map<Long, ArrayList<TargetIdName>> saveAssignedList = new HashMap<>();
int successAssignmentCount = 0;
int duplicateAssignmentCount = 0;
@@ -216,7 +199,7 @@ public class ManangementConfirmationWindowLayout extends AbstractConfirmationWin
if (saveAssignedList.containsKey(distId)) {
targetIdSetList = saveAssignedList.get(distId);
} else {
targetIdSetList = new ArrayList<TargetIdName>();
targetIdSetList = new ArrayList<>();
}
targetIdSetList.add(itemId);
saveAssignedList.put(distId, (ArrayList<TargetIdName>) targetIdSetList);
@@ -275,15 +258,13 @@ public class ManangementConfirmationWindowLayout extends AbstractConfirmationWin
}
private String getAssigmentSuccessMessage(final int assignedCount) {
final String assignment = FontAwesome.TASKS.getHtml() + SPUILabelDefinitions.HTML_SPACE
return FontAwesome.TASKS.getHtml() + SPUILabelDefinitions.HTML_SPACE
+ i18n.get("message.target.assignment", new Object[] { assignedCount });
return assignment;
}
private String getDuplicateAssignmentMessage(final int alreadyAssignedCount) {
final String alreadyAssigned = FontAwesome.TASKS.getHtml() + SPUILabelDefinitions.HTML_SPACE
return FontAwesome.TASKS.getHtml() + SPUILabelDefinitions.HTML_SPACE
+ i18n.get("message.target.alreadyAssigned", new Object[] { alreadyAssignedCount });
return alreadyAssigned;
}
private void discardAllAssignments(final ConfirmationTab tab) {
@@ -456,7 +437,7 @@ public class ManangementConfirmationWindowLayout extends AbstractConfirmationWin
}
private void deleteAllDistributions(final ConfirmationTab tab) {
final Set<Long> deletedIds = new HashSet<Long>();
final Set<Long> deletedIds = new HashSet<>();
managementUIState.getDeletedDistributionList().forEach(distIdName -> deletedIds.add(distIdName.getId()));
distributionSetManagement.deleteDistributionSet(deletedIds.toArray(new Long[deletedIds.size()]));
addToConsolitatedMsg(FontAwesome.TRASH_O.getHtml() + SPUILabelDefinitions.HTML_SPACE
@@ -516,7 +497,7 @@ public class ManangementConfirmationWindowLayout extends AbstractConfirmationWin
final IndexedContainer contactContainer = new IndexedContainer();
contactContainer.addContainerProperty(TARGET_ID, String.class, "");
contactContainer.addContainerProperty(TARGET_NAME, String.class, "");
Item item = null;
Item item;
for (final TargetIdName targteId : managementUIState.getDeletedTargetList()) {
item = contactContainer.addItem(targteId);
item.getItemProperty(TARGET_ID).setValue(targteId.getControllerId());

View File

@@ -0,0 +1,244 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH 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
*/
package org.eclipse.hawkbit.ui.push;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.eventbus.event.DistributionSetTagCreatedBulkEvent;
import org.eclipse.hawkbit.eventbus.event.EntityEvent;
import org.eclipse.hawkbit.eventbus.event.RolloutChangeEvent;
import org.eclipse.hawkbit.eventbus.event.RolloutGroupChangeEvent;
import org.eclipse.hawkbit.eventbus.event.TargetCreatedEvent;
import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent;
import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent;
import org.eclipse.hawkbit.eventbus.event.TargetTagCreatedBulkEvent;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventBus.SessionEventBus;
import com.google.common.collect.Sets;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;
import com.vaadin.server.VaadinSession;
import com.vaadin.server.VaadinSession.State;
import com.vaadin.server.WrappedSession;
import com.vaadin.ui.UI;
/**
* A {@link EventPushStrategy} implementation which retrieves events from
* {@link com.google.common.eventbus.EventBus} and store them first in an queue
* where they will dispatched every 2 seconds to the {@link EventBus} in a
* Vaadin access thread {@link UI#access(Runnable)}.
*
* This strategy avoids blocking UIs when too many events are fired and
* dispatched to the UI thread. The UI will freeze in the time. To avoid that
* all events are collected first and same events are merged to a list of events
* before they dispatched to the UI thread.
*
* The strategy also verifies the current tenant in the session with the tenant
* in the event and only forwards event from the right tenant to the UI.
*
*/
public class DelayedEventBusPushStrategy implements EventPushStrategy {
private static final Logger LOG = LoggerFactory.getLogger(DelayedEventBusPushStrategy.class);
private static final int BLOCK_SIZE = 10_000;
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
private final BlockingDeque<org.eclipse.hawkbit.eventbus.event.Event> queue = new LinkedBlockingDeque<>(BLOCK_SIZE);
private final EventBus.SessionEventBus eventBus;
private final com.google.common.eventbus.EventBus systemEventBus;
private ScheduledFuture<?> jobHandle;
/**
* only events defined in the set are dispatched to the session event bus.
*/
private static final Set<Class<?>> UI_EVENTS = Sets.newHashSet(TargetInfoUpdateEvent.class,
TargetCreatedEvent.class, TargetDeletedEvent.class, RolloutChangeEvent.class, RolloutGroupChangeEvent.class,
TargetTagCreatedBulkEvent.class, DistributionSetTagCreatedBulkEvent.class);
/**
* Constructor.
*
* @param eventBus
* the session event bus to where the events should be dispatched
* @param systemEventBus
* the system event bus where to retrieve the events from the
* back-end
*/
public DelayedEventBusPushStrategy(final SessionEventBus eventBus,
final com.google.common.eventbus.EventBus systemEventBus) {
this.eventBus = eventBus;
this.systemEventBus = systemEventBus;
}
/**
* An {@link com.google.common.eventbus.EventBus} subscriber which
* subscribes {@link EntityEvent} from the repository to dispatch these
* events to the UI {@link SessionEventBus}.
*
* @param event
* the entity event which has been published from the repository
*/
@Subscribe
@AllowConcurrentEvents
public void dispatch(final org.eclipse.hawkbit.eventbus.event.Event event) {
// to dispatch too many events which are not interested on the UI
if (UI_EVENTS.contains(event.getClass()) && !queue.offer(event)) {
LOG.warn("Deque limit is reached, cannot add more events!!! Dropped event is {}", event);
return;
}
}
@Override
public void init(final UI vaadinUI) {
LOG.debug("Initialize delayed event push strategy");
jobHandle = executorService.scheduleWithFixedDelay(new DispatchRunnable(vaadinUI, vaadinUI.getSession()), 500,
2000, TimeUnit.MILLISECONDS);
systemEventBus.register(this);
}
@Override
public void clean() {
LOG.debug("Cleanup resources");
jobHandle.cancel(true);
systemEventBus.unregister(this);
executorService.shutdownNow();
queue.clear();
}
/**
* Checks if the tenant within the event is equal with the current tenant in
* the context.
*
* @param userContext
* the security context of the current session
* @param event
* the event to dispatch to the UI
* @return {@code true} if the event can be dispatched to the UI otherwise
* {@code false}
*/
protected boolean eventSecurityCheck(final SecurityContext userContext,
final org.eclipse.hawkbit.eventbus.event.Event event) {
if (userContext == null || userContext.getAuthentication() == null) {
return false;
}
final Object tenantAuthenticationDetails = userContext.getAuthentication().getDetails();
if (tenantAuthenticationDetails instanceof TenantAwareAuthenticationDetails) {
return ((TenantAwareAuthenticationDetails) tenantAuthenticationDetails).getTenant()
.equalsIgnoreCase(event.getTenant());
}
return false;
}
private final class DispatchRunnable implements Runnable {
private final UI vaadinUI;
private final VaadinSession vaadinSession;
private DispatchRunnable(final UI ui, final VaadinSession session) {
vaadinUI = ui;
vaadinSession = session;
}
@Override
public void run() {
LOG.debug("UI EventBus aggregator started");
final long timestamp = System.currentTimeMillis();
final List<org.eclipse.hawkbit.eventbus.event.Event> events = new LinkedList<>();
for (int i = 0; i < BLOCK_SIZE; i++) {
final org.eclipse.hawkbit.eventbus.event.Event pollEvent = queue.poll();
if (pollEvent == null) {
continue;
}
events.add(pollEvent);
}
if (events.isEmpty()) {
return;
}
if (vaadinSession == null) {
return;
}
LOG.debug("UI EventBus aggregator session: {}", vaadinSession);
final WrappedSession wrappedSession = vaadinSession.getSession();
if (wrappedSession == null) {
return;
}
final int eventsSize = events.size();
doDispatch(events, wrappedSession);
LOG.debug("UI EventBus aggregator done with sending {} events in {} ms", eventsSize,
System.currentTimeMillis() - timestamp);
}
private void doDispatch(final List<org.eclipse.hawkbit.eventbus.event.Event> events,
final WrappedSession wrappedSession) {
final SecurityContext userContext = (SecurityContext) wrappedSession
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
final SecurityContext oldContext = SecurityContextHolder.getContext();
try {
SecurityContextHolder.setContext(userContext);
vaadinUI.access(() -> {
if (vaadinSession.getState() != State.OPEN) {
return;
}
fowardEvents(events, userContext);
// send a list of events, because ui performance issues
publishEventAsList(events, userContext, TargetInfoUpdateEvent.class);
publishEventAsList(events, userContext, TargetCreatedEvent.class);
publishEventAsList(events, userContext, TargetDeletedEvent.class);
});
} finally {
SecurityContextHolder.setContext(oldContext);
}
}
private void publishEventAsList(final List<org.eclipse.hawkbit.eventbus.event.Event> events,
final SecurityContext userContext, final Class<?> eventType) {
final List<org.eclipse.hawkbit.eventbus.event.Event> bulkEvents = events.stream()
.filter(event -> DelayedEventBusPushStrategy.this.eventSecurityCheck(userContext, event)
&& eventType.isInstance(event))
.collect(Collectors.toList());
if (bulkEvents.isEmpty()) {
return;
}
eventBus.publish(vaadinUI, bulkEvents);
}
private void fowardEvents(final List<org.eclipse.hawkbit.eventbus.event.Event> events,
final SecurityContext userContext) {
events.stream().filter(event -> DelayedEventBusPushStrategy.this.eventSecurityCheck(userContext, event))
.forEach(event -> eventBus.publish(vaadinUI, event));
}
}
}

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH 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
*/
package org.eclipse.hawkbit.ui.push;
import com.vaadin.ui.UI;
/**
* Interface declaring a strategy to push events from the back-end to the UI.
*
*/
public interface EventPushStrategy {
/**
* Initialize the event push strategy, this is bound to the life-cycle of
* the {@link UI} so the strategy can be initialized based a {@link UI}.
*
* @param vaadinUI
* the {@link UI}
*/
void init(UI vaadinUI);
/**
* Cleans up resources when the strategy is not be used anymore e.g.
* {@link UI#detach()}.
*/
void clean();
}

View File

@@ -313,7 +313,7 @@ soft.module.os =OS
message.error.noFileSelected = No file selected for upload
message.error.noProvidedName = Please provide custom file name
message.error.noSwModuleSelected = Please select a software module
message.no.duplicateFiles = duplicate files selected
message.no.duplicateFiles = Duplicate files selected
message.no.duplicateFile = Duplicate file selected :
message.delete.artifact = Are you sure that you want to delete artifact {0} ?
message.duplicate.filename = Duplicate file name

View File

@@ -310,7 +310,7 @@ soft.module.os =OS
message.error.noFileSelected = No file selected for upload
message.error.noProvidedName = Please provide custom file name
message.error.noSwModuleSelected = Please select a software module
message.no.duplicateFiles = duplicate files selected
message.no.duplicateFiles = Duplicate files selected
message.no.duplicateFile = Duplicate file selected :
message.delete.artifact = Are you sure that you want to delete artifact {0} ?
message.duplicate.filename = Duplicate file name

View File

@@ -305,7 +305,7 @@ soft.module.os =OS
message.error.noFileSelected = No file selected for upload
message.error.noProvidedName = Please provide custom file name
message.error.noSwModuleSelected = Please select a software module
message.no.duplicateFiles = duplicate files selected
message.no.duplicateFiles = Duplicate files selected
message.no.duplicateFile = Duplicate file selected :
message.delete.artifact = Are you sure that you want to delete artifact {0} ?
message.duplicate.filename = Duplicate file name