/*
* Copyright 2014 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.kie.workbench.common.screens.explorer.backend.server;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.inject.Inject;
import org.guvnor.common.services.backend.file.LinkedDotFileFilter;
import org.guvnor.common.services.project.model.Package;
import org.guvnor.common.services.project.model.Project;
import org.guvnor.structure.organizationalunit.OrganizationalUnit;
import org.guvnor.structure.organizationalunit.OrganizationalUnitService;
import org.guvnor.structure.repositories.Repository;
import org.jboss.errai.security.shared.api.identity.User;
import org.kie.workbench.common.screens.explorer.model.FolderItem;
import org.kie.workbench.common.screens.explorer.model.FolderItemType;
import org.kie.workbench.common.screens.explorer.model.FolderListing;
import org.kie.workbench.common.screens.explorer.model.ProjectExplorerContent;
import org.kie.workbench.common.screens.explorer.service.ActiveOptions;
import org.kie.workbench.common.screens.explorer.service.Option;
import org.kie.workbench.common.screens.explorer.service.ProjectExplorerContentQuery;
import org.kie.workbench.common.screens.explorer.utils.Sorters;
import org.kie.workbench.common.services.shared.project.KieProjectService;
import org.uberfire.backend.server.util.Paths;
import org.uberfire.backend.vfs.Path;
import org.uberfire.java.nio.file.Files;
import org.uberfire.security.authz.AuthorizationManager;
import static java.util.Collections.*;
public class ProjectExplorerContentResolver {
private LinkedDotFileFilter dotFileFilter = new LinkedDotFileFilter();
private KieProjectService projectService;
private ExplorerServiceHelper helper;
private AuthorizationManager authorizationManager;
private OrganizationalUnitService organizationalUnitService;
private ExplorerServiceHelper explorerServiceHelper;
@Inject
protected User identity;
@Inject
public ProjectExplorerContentResolver( final KieProjectService projectService,
final ExplorerServiceHelper helper,
final AuthorizationManager authorizationManager,
final OrganizationalUnitService organizationalUnitService,
final ExplorerServiceHelper explorerServiceHelper ) {
this.projectService = projectService;
this.helper = helper;
this.authorizationManager = authorizationManager;
this.organizationalUnitService = organizationalUnitService;
this.explorerServiceHelper = explorerServiceHelper;
}
public ProjectExplorerContent resolve( final ProjectExplorerContentQuery query ) {
final Content content = setupSelectedItems( query );
//Content may contain invalid state, e.g. Repository deleted, Project deleted etc so validate and reset as appropriate
setSelectedOrganizationalUnit( content );
setSelectedRepository( content );
setSelectedBranch( content );
setSelectedProject( content );
setSelectedPackage( content );
setSelectedItem( content );
if ( content.getSelectedOrganizationalUnit() == null || content.getSelectedRepository() == null || content.getSelectedProject() == null ) {
return emptyProjectExplorerContent( content );
} else {
return projectExplorerContentWithSelections( content,
query.getOptions() );
}
}
private ProjectExplorerContent projectExplorerContentWithSelections( final Content content,
final ActiveOptions options ) {
setFolderListing( content,
options );
setSiblings( content );
helper.store( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
content.getSelectedBranch(),
content.getSelectedProject(),
content.getFolderListing(),
content.getSelectedPackage(),
options );
return new ProjectExplorerContent(
new TreeSet<OrganizationalUnit>( Sorters.ORGANIZATIONAL_UNIT_SORTER ) {{
addAll( content.getOrganizationalUnits() );
}},
content.getSelectedOrganizationalUnit(),
new TreeSet<Repository>( Sorters.REPOSITORY_SORTER ) {{
addAll( content.getRepositories().values() );
}},
content.getSelectedRepository(),
content.getSelectedBranch(),
new TreeSet<Project>( Sorters.PROJECT_SORTER ) {{
addAll( content.getProjects().values() );
}},
content.getSelectedProject(),
content.getFolderListing(),
content.getSiblings()
);
}
private void setFolderListing( final Content content,
final ActiveOptions options ) {
content.setFolderListing( helper.getFolderListing( content.getSelectedItem(),
content.getSelectedProject(),
content.getSelectedPackage(),
options ) );
}
private void setSiblings( final Content content ) {
if ( content.getFolderListing().getSegments().size() > 1 ) {
final ListIterator<FolderItem> li = content.getFolderListing().getSegments().listIterator( content.getFolderListing().getSegments().size() );
while ( li.hasPrevious() ) {
final FolderItem currentItem = li.previous();
final List<FolderItem> result = new ArrayList<FolderItem>();
result.add( currentItem );
if ( currentItem.getItem() instanceof Package ) {
result.addAll( getSegmentSiblings( (Package) currentItem.getItem() ) );
} else if ( currentItem.getItem() instanceof Path ) {
result.addAll( getSegmentSiblings( (Path) currentItem.getItem() ) );
}
content.getSiblings().put( currentItem, result );
}
}
if ( content.getSelectedItem() != null && content.getSelectedItem().getType().equals( FolderItemType.FOLDER ) &&
!content.getSiblings().containsKey( content.getSelectedItem() ) ) {
final List<FolderItem> result = new ArrayList<FolderItem>();
result.add( content.getSelectedItem() );
if ( content.getSelectedItem().getItem() instanceof Package ) {
result.addAll( getSegmentSiblings( (Package) content.getSelectedItem().getItem() ) );
} else if ( content.getSelectedItem().getItem() instanceof Path ) {
result.addAll( getSegmentSiblings( (Path) content.getSelectedItem().getItem() ) );
}
content.getSiblings().put( content.getSelectedItem(),
result );
}
if ( content.getFolderListing().getItem().getType().equals( FolderItemType.FOLDER ) &&
!content.getSiblings().containsKey( content.getFolderListing().getItem() ) ) {
final List<FolderItem> result = new ArrayList<FolderItem>();
result.add( content.getFolderListing().getItem() );
if ( content.getFolderListing().getItem().getItem() instanceof Package ) {
result.addAll( getSegmentSiblings( (Package) content.getFolderListing().getItem().getItem() ) );
} else if ( content.getFolderListing().getItem().getItem() instanceof Path ) {
result.addAll( getSegmentSiblings( (Path) content.getFolderListing().getItem().getItem() ) );
}
if ( !result.isEmpty() ) {
content.getSiblings().put( content.getFolderListing().getItem(),
result );
}
}
//Sort sibling lists before returning to client
for ( Map.Entry<FolderItem, List<FolderItem>> e : content.getSiblings().entrySet() ) {
Collections.sort( e.getValue(),
Sorters.ITEM_SORTER );
}
}
private ProjectExplorerContent emptyProjectExplorerContent( final Content content ) {
return new ProjectExplorerContent(
new TreeSet<OrganizationalUnit>( Sorters.ORGANIZATIONAL_UNIT_SORTER ) {{
addAll( content.getOrganizationalUnits() );
}},
content.getSelectedOrganizationalUnit(),
new TreeSet<Repository>( Sorters.REPOSITORY_SORTER ) {{
addAll( content.getRepositories().values() );
}},
content.getSelectedRepository(),
content.getSelectedBranch(),
new TreeSet<Project>( Sorters.PROJECT_SORTER ) {{
addAll( content.getProjects().values() );
}},
content.getSelectedProject(),
new FolderListing( null, Collections.<FolderItem>emptyList(), Collections.<FolderItem>emptyList() ),
Collections.<FolderItem, List<FolderItem>>emptyMap()
);
}
private void setSelectedPackage( final Content content ) {
if ( content.getSelectedProject() == null ) {
content.setSelectedPackage( null );
} else {
final Project selectedProject = content.getSelectedProject();
if ( content.getSelectedPackage() != null ) {
if ( !content.getSelectedPackage().getProjectRootPath().equals( selectedProject.getRootPath() ) ) {
content.setSelectedPackage( null );
content.setSelectedItem( null );
}
}
}
}
private void setSelectedItem( final Content content ) {
if ( content.getSelectedProject() == null ) {
content.setSelectedItem( null );
} else {
final Project selectedProject = content.getSelectedProject();
if ( content.getSelectedItem() != null ) {
if ( content.getSelectedItem().getItem() instanceof Package ) {
final Package pkg = (Package) content.getSelectedItem().getItem();
if ( !pkg.getProjectRootPath().equals( selectedProject.getRootPath() ) ) {
content.setSelectedPackage( null );
content.setSelectedItem( null );
}
} else if ( content.getSelectedItem().getItem() instanceof Path ) {
final Path itemPath = (Path) content.getSelectedItem().getItem();
final Project owningProject = projectService.resolveProject( itemPath );
if ( !owningProject.getRootPath().equals( selectedProject.getRootPath() ) ) {
content.setSelectedPackage( null );
content.setSelectedItem( null );
}
}
}
}
}
private void setSelectedProject( final Content content ) {
content.setProjects( getProjects( content.getSelectedRepository(),
content.getSelectedBranch() ) );
if ( content.getSelectedProject() == null || !content.getProjects().containsKey( content.getSelectedProject().getProjectName() ) ) {
content.setSelectedProject( ( content.getProjects().isEmpty() ? null : content.getProjects().values().iterator().next() ) );
} else {
content.setSelectedProject( content.getProjects().get( content.getSelectedProject().getProjectName() ) );
}
}
private void setSelectedRepository( final Content content ) {
content.setRepositories( getRepositories( content.getSelectedOrganizationalUnit() ) );
if ( content.getSelectedRepository() == null || !content.getRepositories().containsKey( content.getSelectedRepository().getAlias() ) ) {
content.setSelectedRepository( ( content.getRepositories().isEmpty() ? null : content.getRepositories().values().iterator().next() ) );
}
}
private void setSelectedBranch( final Content content ) {
if ( content.getSelectedRepository() == null ) {
return;
}
if ( !content.getSelectedRepository().getBranches().contains( content.getSelectedBranch() ) ) {
content.setSelectedBranch( getBranch( content ) );
}
}
private String getBranch( final Content content ) {
if ( content.getSelectedRepository().getBranches().contains( content.getSelectedBranch() ) ) {
return content.getSelectedBranch();
} else if ( content.getSelectedRepository().getBranches().contains( "master" ) ) {
return "master";
} else if ( content.getSelectedRepository().getBranches().isEmpty() ) {
return null;
} else {
return content.getSelectedRepository().getBranches().iterator().next();
}
}
private boolean isCurrentRepositoryUpToDate( final Content content ) {
return !content.getSelectedRepository().equals( content.getRepositories().get( content.getSelectedRepository().getAlias() ) );
}
private void setSelectedOrganizationalUnit( final Content content ) {
content.setOrganizationalUnits( getOrganizationalUnits() );
if ( !content.getOrganizationalUnits().contains( content.getSelectedOrganizationalUnit() ) ) {
content.setSelectedOrganizationalUnit( ( content.getOrganizationalUnits().isEmpty() ? null : content.getOrganizationalUnits().iterator().next() ) );
}
}
protected Content setupSelectedItems( ProjectExplorerContentQuery query ) {
final Content content = new Content( query );
final UserExplorerLastData lastContent = helper.getLastContent();
final UserExplorerData userContent = helper.loadUserContent();
if ( !lastContent.isDataEmpty() ) {
if ( query.getOrganizationalUnit() == null && query.getRepository() == null && query.getProject() == null ) {
//If nothing has been selected (i.e. on start-up) set-up Content from last saved state
if ( query.getOptions().contains( Option.BUSINESS_CONTENT ) && lastContent.getLastPackage() != null ) {
content.setSelectedOrganizationalUnit( lastContent.getLastPackage().getOrganizationalUnit() );
content.setSelectedRepository( lastContent.getLastPackage().getRepository() );
content.setSelectedBranch( lastContent.getLastPackage().getBranch() );
content.setSelectedProject( lastContent.getLastPackage().getProject() );
content.setSelectedPackage( lastContent.getLastPackage().getPkg() );
content.setSelectedItem( null );
} else if ( query.getOptions().contains( Option.TECHNICAL_CONTENT ) && lastContent.getLastFolderItem() != null ) {
content.setSelectedOrganizationalUnit( lastContent.getLastFolderItem().getOrganizationalUnit() );
content.setSelectedRepository( lastContent.getLastFolderItem().getRepository() );
content.setSelectedBranch( lastContent.getLastFolderItem().getBranch() );
content.setSelectedProject( lastContent.getLastFolderItem().getProject() );
content.setSelectedItem( lastContent.getLastFolderItem().getItem() );
content.setSelectedPackage( null );
}
} else if ( query.getOptions().contains( Option.BUSINESS_CONTENT ) && lastContent.getLastPackage() != null ) {
if ( !query.getOrganizationalUnit().equals( lastContent.getLastPackage().getOrganizationalUnit() )
|| query.getRepository() != null
&& !query.getRepository().equals( lastContent.getLastPackage().getRepository() )
|| query.getBranch() != null
&& !query.getBranch().equals( lastContent.getLastPackage().getBranch() )
|| query.getProject() != null
&& !query.getProject().equals( lastContent.getLastPackage().getProject() ) ) {
//Handle a change in selected OU, Repository or Project in BUSINESS_CONTENT view
content.setSelectedOrganizationalUnit( loadOrganizationalUnit( query.getOrganizationalUnit(),
userContent ) );
content.setSelectedRepository( loadRepository( content.getSelectedOrganizationalUnit(),
query.getRepository(),
userContent ) );
content.setSelectedBranch( loadBranch( content.getSelectedOrganizationalUnit(),
query.getRepository(),
query.getBranch() ) );
content.setSelectedProject( loadProject( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
query.getProject(),
userContent ) );
content.setSelectedPackage( loadPackage( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
content.getSelectedProject(),
query.getPkg(),
userContent ) );
content.setSelectedItem( null );
} else {
//Fall back to the last saved state
content.setSelectedOrganizationalUnit( loadOrganizationalUnit( lastContent.getLastPackage().getOrganizationalUnit(),
userContent ) );
content.setSelectedRepository( loadRepository( content.getSelectedOrganizationalUnit(),
lastContent.getLastPackage().getRepository(),
userContent ) );
content.setSelectedBranch( loadBranch( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
lastContent.getLastPackage().getBranch() ) );
content.setSelectedProject( loadProject( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
lastContent.getLastPackage().getProject(),
userContent ) );
content.setSelectedPackage( loadPackage( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
content.getSelectedProject(),
lastContent.getLastPackage().getPkg(),
userContent ) );
content.setSelectedItem( null );
}
} else if ( query.getOptions().contains( Option.TECHNICAL_CONTENT ) && lastContent.getLastFolderItem() != null ) {
if ( lastContent.getOptions().contains( Option.BUSINESS_CONTENT ) ) {
//When switching from BUSINESS_VIEW we cannot use LastFolderItem().getItem() and must use Project root; set by FolderListingResolver.getFolderListing()
content.setSelectedOrganizationalUnit( loadOrganizationalUnit( lastContent.getLastFolderItem().getOrganizationalUnit(),
userContent ) );
content.setSelectedRepository( loadRepository( content.getSelectedOrganizationalUnit(),
lastContent.getLastFolderItem().getRepository(),
userContent ) );
content.setSelectedBranch( loadBranch( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
lastContent.getLastPackage().getBranch() ) );
content.setSelectedProject( loadProject( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
lastContent.getLastFolderItem().getProject(),
userContent ) );
content.setSelectedItem( null );
content.setSelectedPackage( null );
} else if ( !query.getOrganizationalUnit().equals( lastContent.getLastFolderItem().getOrganizationalUnit() ) ||
query.getRepository() != null && !query.getRepository().equals( lastContent.getLastFolderItem().getRepository() ) ||
query.getProject() != null && !query.getProject().equals( lastContent.getLastFolderItem().getProject() ) ) {
//Handle a change in selected OU, Repository or Project in TECHNICAL_CONTENT view
content.setSelectedOrganizationalUnit( loadOrganizationalUnit( query.getOrganizationalUnit(),
userContent ) );
content.setSelectedRepository( loadRepository( content.getSelectedOrganizationalUnit(),
query.getRepository(),
userContent ) );
content.setSelectedBranch( loadBranch( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
query.getBranch() ) );
content.setSelectedProject( loadProject( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
query.getProject(),
userContent ) );
content.setSelectedItem( null );
content.setSelectedPackage( null );
} else {
//Fall back to the last saved state
content.setSelectedOrganizationalUnit( loadOrganizationalUnit( lastContent.getLastFolderItem().getOrganizationalUnit(),
userContent ) );
content.setSelectedRepository( loadRepository( content.getSelectedOrganizationalUnit(),
lastContent.getLastFolderItem().getRepository(),
userContent ) );
content.setSelectedBranch( loadBranch( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
lastContent.getLastFolderItem().getBranch() ) );
content.setSelectedProject( loadProject( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
lastContent.getLastFolderItem().getProject(),
userContent ) );
content.setSelectedItem( loadFolderItem( content.getSelectedOrganizationalUnit(),
content.getSelectedRepository(),
content.getSelectedProject(),
lastContent.getLastFolderItem().getItem(),
userContent ) );
content.setSelectedPackage( null );
}
}
}
return content;
}
private List<FolderItem> getSegmentSiblings( final Path path ) {
final List<FolderItem> result = new ArrayList<FolderItem>();
org.uberfire.java.nio.file.Path nioParentPath = Paths.convert( path ).getParent();
for ( org.uberfire.java.nio.file.Path sibling : Files.newDirectoryStream( nioParentPath, dotFileFilter ) ) {
result.add( explorerServiceHelper.toFolderItem( sibling ) );
}
return result;
}
private List<FolderItem> getSegmentSiblings( final Package pkg ) {
final List<FolderItem> result = new ArrayList<FolderItem>();
final Package parentPkg = projectService.resolveParentPackage( pkg );
if ( parentPkg == null ) {
return emptyList();
}
final Set<Package> siblings = projectService.resolvePackages( parentPkg );
if ( siblings != null && !siblings.isEmpty() ) {
for ( final Package sibling : siblings ) {
if ( !sibling.equals( pkg ) ) {
result.add( explorerServiceHelper.toFolderItem( sibling ) );
}
}
}
return result;
}
private OrganizationalUnit loadOrganizationalUnit( final OrganizationalUnit organizationalUnit,
final UserExplorerData content ) {
if ( organizationalUnit != null ) {
return organizationalUnit;
}
return content.getOrganizationalUnit();
}
private Repository loadRepository( final OrganizationalUnit organizationalUnit,
final Repository repository,
final UserExplorerData content ) {
if ( organizationalUnit == null ) {
return null;
}
if ( repository != null ) {
return repository;
}
return content.get( organizationalUnit );
}
private String loadBranch( final OrganizationalUnit selectedOrganizationalUnit,
final Repository repository,
final String branch ) {
if ( selectedOrganizationalUnit == null ) {
return null;
} else if ( repository == null ) {
return null;
} else if ( branch != null ) {
return branch;
} else if ( !repository.getBranches().isEmpty() ) {
return repository.getBranches().iterator().next();
} else {
return null;
}
}
private Project loadProject( final OrganizationalUnit organizationalUnit,
final Repository repository,
final Project project,
final UserExplorerData content ) {
if ( repository == null ) {
return null;
}
if ( project != null ) {
return project;
}
return content.get( organizationalUnit, repository );
}
private Package loadPackage( final OrganizationalUnit organizationalUnit,
final Repository repository,
final Project project,
final Package pkg,
final UserExplorerData content ) {
if ( project == null ) {
return null;
}
if ( pkg != null ) {
return pkg;
}
return content.getPackage( organizationalUnit, repository, project );
}
private FolderItem loadFolderItem( final OrganizationalUnit organizationalUnit,
final Repository repository,
final Project project,
final FolderItem item,
final UserExplorerData content ) {
if ( project == null ) {
return null;
}
if ( item != null ) {
return item;
}
return content.getFolderItem( organizationalUnit, repository, project );
}
private Set<OrganizationalUnit> getOrganizationalUnits() {
final Collection<OrganizationalUnit> organizationalUnits = organizationalUnitService.getOrganizationalUnits();
final Set<OrganizationalUnit> authorizedOrganizationalUnits = new HashSet<OrganizationalUnit>();
for ( OrganizationalUnit organizationalUnit : organizationalUnits ) {
if ( authorizationManager.authorize( organizationalUnit,
identity ) ) {
authorizedOrganizationalUnits.add( organizationalUnit );
}
}
return authorizedOrganizationalUnits;
}
private Map<String, Repository> getRepositories( final OrganizationalUnit organizationalUnit ) {
final Map<String, Repository> authorizedRepositories = new HashMap<String, Repository>();
if ( organizationalUnit == null ) {
return authorizedRepositories;
}
//Reload OrganizationalUnit as the organizational unit's repository list might have been changed server-side
final Collection<Repository> repositories = organizationalUnitService.getOrganizationalUnit( organizationalUnit.getName() ).getRepositories();
for ( Repository repository : repositories ) {
if ( authorizationManager.authorize( repository,
identity ) ) {
authorizedRepositories.put( repository.getAlias(),
repository );
}
}
return authorizedRepositories;
}
private Map<String, Project> getProjects( final Repository repository,
final String branch ) {
final Map<String, Project> authorizedProjects = new HashMap<String, Project>();
if ( repository == null ) {
return authorizedProjects;
} else {
Set<Project> allProjects = projectService.getProjects( repository,
branch );
for ( Project project : allProjects ) {
if ( authorizationManager.authorize( project,
identity ) ) {
authorizedProjects.put( project.getProjectName(),
project );
}
}
return authorizedProjects;
}
}
}