/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.uberfire.backend.server.io.watch; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.ejb.Singleton; import javax.ejb.Startup; import javax.ejb.TransactionAttribute; import javax.enterprise.event.Event; import javax.inject.Inject; import org.jboss.errai.security.shared.api.identity.UserImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.uberfire.backend.server.util.Filter; import org.uberfire.backend.vfs.Path; import org.uberfire.commons.data.Pair; import org.uberfire.java.nio.base.WatchContext; import org.uberfire.java.nio.file.StandardWatchEventKind; import org.uberfire.java.nio.file.WatchEvent; import org.uberfire.java.nio.file.WatchKey; import org.uberfire.rpc.SessionInfo; import org.uberfire.rpc.impl.SessionInfoImpl; import org.uberfire.workbench.events.ResourceAdded; import org.uberfire.workbench.events.ResourceAddedEvent; import org.uberfire.workbench.events.ResourceBatchChangesEvent; import org.uberfire.workbench.events.ResourceChange; import org.uberfire.workbench.events.ResourceDeleted; import org.uberfire.workbench.events.ResourceDeletedEvent; import org.uberfire.workbench.events.ResourceEvent; import org.uberfire.workbench.events.ResourceRenamed; import org.uberfire.workbench.events.ResourceRenamedEvent; import org.uberfire.workbench.events.ResourceUpdated; import org.uberfire.workbench.events.ResourceUpdatedEvent; import static javax.ejb.TransactionAttributeType.NOT_SUPPORTED; import static org.uberfire.backend.server.util.Paths.convert; @Singleton @Startup @TransactionAttribute(NOT_SUPPORTED) public class IOWatchServiceExecutorImpl implements IOWatchServiceExecutor { private static final Logger LOGGER = LoggerFactory.getLogger(IOWatchServiceExecutorImpl.class); @Inject private Event<ResourceBatchChangesEvent> resourceBatchChanges; @Inject private Event<ResourceUpdatedEvent> resourceUpdatedEvent; @Inject private Event<ResourceRenamedEvent> resourceRenamedEvent; @Inject private Event<ResourceDeletedEvent> resourceDeletedEvent; @Inject private Event<ResourceAddedEvent> resourceAddedEvent; public void setEvents(final Event<ResourceBatchChangesEvent> resourceBatchChanges, final Event<ResourceUpdatedEvent> resourceUpdatedEvent, final Event<ResourceRenamedEvent> resourceRenamedEvent, final Event<ResourceDeletedEvent> resourceDeletedEvent, final Event<ResourceAddedEvent> resourceAddedEvent) { this.resourceBatchChanges = resourceBatchChanges; this.resourceUpdatedEvent = resourceUpdatedEvent; this.resourceRenamedEvent = resourceRenamedEvent; this.resourceDeletedEvent = resourceDeletedEvent; this.resourceAddedEvent = resourceAddedEvent; } @Override public void execute(final WatchKey wk, final Filter<WatchEvent<?>> filter) { final List<WatchEvent<?>> events = wk.pollEvents(); WatchContext firstContext = null; if (events.size() > 1) { final Map<Path, Collection<ResourceChange>> changes = new HashMap<Path, Collection<ResourceChange>>(); for (final WatchEvent event : events) { if (!filter.doFilter(event)) { if (firstContext == null) { firstContext = (WatchContext) event.context(); } final Pair<Path, ResourceChange> result = buildChange(event); if (result != null) { if (!changes.containsKey(result.getK1())) { changes.put(result.getK1(), new ArrayList<ResourceChange>()); } changes.get(result.getK1()).add(result.getK2()); } } } if (changes.size() == 1 && changes.values().size() == 1) { final ResourceChange _event = changes.values().iterator().next().iterator().next(); if (_event instanceof ResourceUpdated) { resourceUpdatedEvent.fire((ResourceUpdatedEvent) toEvent(changes.keySet().iterator().next(), _event, firstContext)); } else if (_event instanceof ResourceAdded) { resourceAddedEvent.fire((ResourceAddedEvent) toEvent(changes.keySet().iterator().next(), _event, firstContext)); } else if (_event instanceof ResourceRenamed) { resourceRenamedEvent.fire((ResourceRenamedEvent) toEvent(changes.keySet().iterator().next(), _event, firstContext)); } else if (_event instanceof ResourceDeleted) { resourceDeletedEvent.fire((ResourceDeletedEvent) toEvent(changes.keySet().iterator().next(), _event, firstContext)); } } else if (changes.size() > 1) { resourceBatchChanges.fire(new ResourceBatchChangesEvent(changes, message(firstContext), sessionInfo(firstContext))); } } else if (events.size() == 1) { final WatchEvent<?> event = events.get(0); if (!filter.doFilter(event)) { if (event.kind().equals(StandardWatchEventKind.ENTRY_MODIFY)) { resourceUpdatedEvent.fire(buildEvent(ResourceUpdatedEvent.class, event).getK2()); } else if (event.kind().equals(StandardWatchEventKind.ENTRY_CREATE)) { resourceAddedEvent.fire(buildEvent(ResourceAddedEvent.class, event).getK2()); } else if (event.kind().equals(StandardWatchEventKind.ENTRY_RENAME)) { resourceRenamedEvent.fire(buildEvent(ResourceRenamedEvent.class, event).getK2()); } else if (event.kind().equals(StandardWatchEventKind.ENTRY_DELETE)) { resourceDeletedEvent.fire(buildEvent(ResourceDeletedEvent.class, event).getK2()); } } } } private String message(final WatchContext context) { if (context == null) { return null; } return context.getMessage(); } private <T extends ResourceEvent> Pair<Path, T> buildEvent(final Class<T> clazz, final WatchEvent<?> event) { final WatchContext context = (WatchContext) event.context(); final Path _affectedPath; final T result; if (event.kind().equals(StandardWatchEventKind.ENTRY_MODIFY)) { _affectedPath = convert(context.getOldPath()); result = (T) new ResourceUpdatedEvent(_affectedPath, context.getMessage(), sessionInfo(context)); } else if (event.kind().equals(StandardWatchEventKind.ENTRY_CREATE)) { _affectedPath = convert(context.getPath()); result = (T) new ResourceAddedEvent(_affectedPath, context.getMessage(), sessionInfo(context)); } else if (event.kind().equals(StandardWatchEventKind.ENTRY_RENAME)) { _affectedPath = convert(context.getOldPath()); result = (T) new ResourceRenamedEvent(_affectedPath, convert(context.getPath()), context.getMessage(), sessionInfo(context)); } else if (event.kind().equals(StandardWatchEventKind.ENTRY_DELETE)) { _affectedPath = convert(context.getOldPath()); result = (T) new ResourceDeletedEvent(_affectedPath, context.getMessage(), sessionInfo(context)); } else { _affectedPath = null; result = null; } if (_affectedPath == null) { return null; } return Pair.newPair(_affectedPath, result); } private Pair<Path, ResourceChange> buildChange(final WatchEvent<?> event) { final WatchContext context = (WatchContext) event.context(); final Path _affectedPath; final ResourceChange result; if (event.kind().equals(StandardWatchEventKind.ENTRY_MODIFY)) { _affectedPath = convert(context.getOldPath()); result = new ResourceUpdated(context.getMessage()); } else if (event.kind().equals(StandardWatchEventKind.ENTRY_CREATE)) { _affectedPath = convert(context.getPath()); result = new ResourceAdded(context.getMessage()); } else if (event.kind().equals(StandardWatchEventKind.ENTRY_RENAME)) { _affectedPath = convert(context.getOldPath()); result = new ResourceRenamed(convert(context.getPath()), context.getMessage()); } else if (event.kind().equals(StandardWatchEventKind.ENTRY_DELETE)) { _affectedPath = convert(context.getOldPath()); result = new ResourceDeleted(context.getMessage()); } else { _affectedPath = null; result = null; } if (_affectedPath == null) { return null; } return Pair.newPair(_affectedPath, result); } private ResourceEvent toEvent(final Path path, final ResourceChange change, final WatchContext context) { if (change instanceof ResourceUpdated) { return new ResourceUpdatedEvent(path, context.getMessage(), sessionInfo(context)); } else if (change instanceof ResourceAdded) { return new ResourceAddedEvent(path, context.getMessage(), sessionInfo(context)); } else if (change instanceof ResourceRenamed) { return new ResourceRenamedEvent(path, ((ResourceRenamed) change).getDestinationPath(), context.getMessage(), sessionInfo(context)); } else if (change instanceof ResourceDeleted) { return new ResourceDeletedEvent(path, context.getMessage(), sessionInfo(context)); } return null; } private SessionInfo sessionInfo(final WatchContext context) { final String sessionId; final String user; if (context.getSessionId() == null) { sessionId = "<system>"; } else { sessionId = context.getSessionId(); } if (context.getUser() == null) { user = "<system>"; } else { user = context.getUser(); } return new SessionInfoImpl(sessionId, new UserImpl(user)); } }