/* * Copyright 2012 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.guvnor.common.services.builder; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; import javax.enterprise.inject.Instance; import javax.inject.Inject; import org.guvnor.common.services.project.builder.events.InvalidateDMOProjectCacheEvent; import org.guvnor.common.services.project.model.Project; import org.guvnor.common.services.project.service.ProjectService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.uberfire.backend.vfs.Path; import org.uberfire.rpc.SessionInfo; import org.uberfire.workbench.events.ResourceAddedEvent; import org.uberfire.workbench.events.ResourceBatchChangesEvent; import org.uberfire.workbench.events.ResourceChange; import org.uberfire.workbench.events.ResourceChangeType; import org.uberfire.workbench.events.ResourceCopiedEvent; import org.uberfire.workbench.events.ResourceDeletedEvent; import org.uberfire.workbench.events.ResourceRenamedEvent; import org.uberfire.workbench.events.ResourceUpdatedEvent; /** * Server side component that observes for the different resource add/delete/update events related to * a given project and that causes the ProjectDataModelOracle to be invalidated. Typically .java, .class and pom.xml * files. When such a resource is modified an InvalidateDMOProjectCacheEvent event is fired. */ @ApplicationScoped public class ResourceChangeObserver { private static final Logger logger = LoggerFactory.getLogger( ResourceChangeObserver.class ); @Inject private ProjectService<? extends Project> projectService; @Inject private ResourceChangeIncrementalBuilder incrementalBuilder; @Inject private Event<InvalidateDMOProjectCacheEvent> invalidateDMOProjectCacheEvent; @Inject @Any private Instance<ResourceChangeObservableFile> observableFiles; @Inject private ObservablePOMFile observablePomFile; public void processResourceAdd( @Observes final ResourceAddedEvent resourceAddedEvent ) { processResourceChange( resourceAddedEvent.getSessionInfo(), resourceAddedEvent.getPath(), ResourceChangeType.ADD ); incrementalBuilder.addResource( resourceAddedEvent.getPath() ); } public void processResourceDelete( @Observes final ResourceDeletedEvent resourceDeletedEvent ) { processResourceChange( resourceDeletedEvent.getSessionInfo(), resourceDeletedEvent.getPath(), ResourceChangeType.DELETE ); incrementalBuilder.deleteResource( resourceDeletedEvent.getPath() ); } public void processResourceUpdate( @Observes final ResourceUpdatedEvent resourceUpdatedEvent ) { processResourceChange( resourceUpdatedEvent.getSessionInfo(), resourceUpdatedEvent.getPath(), ResourceChangeType.UPDATE ); incrementalBuilder.updateResource( resourceUpdatedEvent.getPath() ); } public void processResourceCopied( @Observes final ResourceCopiedEvent resourceCopiedEvent ) { processResourceChange( resourceCopiedEvent.getSessionInfo(), resourceCopiedEvent.getPath(), ResourceChangeType.COPY ); incrementalBuilder.addResource( resourceCopiedEvent.getPath() ); //¿? } public void processResourceRenamed( @Observes final ResourceRenamedEvent resourceRenamedEvent ) { processResourceChange( resourceRenamedEvent.getSessionInfo(), resourceRenamedEvent.getPath(), ResourceChangeType.RENAME ); incrementalBuilder.deleteResource( resourceRenamedEvent.getPath() ); incrementalBuilder.addResource( resourceRenamedEvent.getDestinationPath() ); } public void processBatchChanges( @Observes final ResourceBatchChangesEvent resourceBatchChangesEvent ) { final Map<Path, Collection<ResourceChange>> batchChanges = resourceBatchChangesEvent.getBatch(); if ( batchChanges == null ) { //un expected case logger.warn( "No batchChanges was present for the given resourceBatchChangesEvent: " + resourceBatchChangesEvent ); } else { processBatchResourceChanges( resourceBatchChangesEvent.getSessionInfo(), batchChanges ); incrementalBuilder.batchResourceChanges( resourceBatchChangesEvent.getBatch() ); } } private void processResourceChange( final SessionInfo sessionInfo, final Path path, final ResourceChangeType changeType ) { //Only process Project resources final Project project = projectService.resolveProject( path ); if ( project == null ) { return; } if ( logger.isDebugEnabled() ) { logger.debug( "Processing resource change for sessionInfo: " + sessionInfo + ", project: " + project + ", path: " + path + ", changeType: " + changeType ); } if ( isObservableResource( path ) ) { invalidateDMOProjectCacheEvent.fire( new InvalidateDMOProjectCacheEvent( sessionInfo, project, path ) ); } } private void processBatchResourceChanges( final SessionInfo sessionInfo, final Map<Path, Collection<ResourceChange>> resourceChanges ) { Project project; final Map<Project, Path> pendingNotifications = new HashMap<Project, Path>(); for ( final Map.Entry<Path, Collection<ResourceChange>> pathCollectionEntry : resourceChanges.entrySet() ) { //Only process Project resources project = projectService.resolveProject( pathCollectionEntry.getKey() ); if ( project == null ) { continue; } if ( !pendingNotifications.containsKey( project ) && isObservableResource( pathCollectionEntry.getKey() ) ) { pendingNotifications.put( project, pathCollectionEntry.getKey() ); } else if ( isPomFile( pathCollectionEntry.getKey() ) ) { //if the pom.xml comes in the batch events set then use the pom.xml path for the cache invalidation event pendingNotifications.put( project, pathCollectionEntry.getKey() ); } } for ( final Map.Entry<Project, Path> pendingNotification : pendingNotifications.entrySet() ) { invalidateDMOProjectCacheEvent.fire( new InvalidateDMOProjectCacheEvent( sessionInfo, pendingNotification.getKey(), pendingNotification.getValue() ) ); } } //Check if the changed file should invalidate the DMO cache private boolean isObservableResource( final Path path ) { if ( path == null ) { return false; } for ( ResourceChangeObservableFile observableFile : observableFiles ) { if ( observableFile.accept( path.getFileName() ) ) { return true; } } return false; } private boolean isPomFile( final Path path ) { if ( path == null ) { return false; } return observablePomFile.accept( path.getFileName() ); } }