/*
* 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.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Named;
import com.google.common.collect.Lists;
import com.thoughtworks.xstream.XStream;
import org.guvnor.common.services.backend.file.LinkedDotFileFilter;
import org.guvnor.common.services.backend.file.LinkedRegularFileFilter;
import org.guvnor.common.services.project.model.Package;
import org.guvnor.common.services.project.model.Project;
import org.guvnor.common.services.shared.metadata.MetadataService;
import org.guvnor.structure.organizationalunit.OrganizationalUnit;
import org.guvnor.structure.repositories.Repository;
import org.kie.workbench.common.screens.explorer.model.FolderItem;
import org.kie.workbench.common.screens.explorer.model.FolderItemOperation;
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.service.ActiveOptions;
import org.kie.workbench.common.screens.explorer.service.Option;
import org.kie.workbench.common.screens.explorer.utils.Sorters;
import org.kie.workbench.common.services.shared.project.KieProjectService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.uberfire.backend.server.UserServicesImpl;
import org.uberfire.backend.server.VFSLockServiceImpl;
import org.uberfire.backend.server.util.Paths;
import org.uberfire.backend.vfs.Path;
import org.uberfire.commons.async.DescriptiveRunnable;
import org.uberfire.commons.async.SimpleAsyncExecutorService;
import org.uberfire.ext.editor.commons.service.CopyService;
import org.uberfire.ext.editor.commons.service.DeleteService;
import org.uberfire.ext.editor.commons.service.RenameService;
import org.uberfire.io.IOService;
import org.uberfire.java.nio.file.DirectoryStream;
import org.uberfire.java.nio.file.Files;
import static java.util.Collections.*;
import static java.util.stream.Collectors.toList;
public class ExplorerServiceHelper {
private static final Logger LOGGER = LoggerFactory.getLogger( ExplorerServiceHelper.class );
private LinkedDotFileFilter dotFileFilter = new LinkedDotFileFilter();
private LinkedRegularFileFilter regularFileFilter = new LinkedRegularFileFilter( dotFileFilter );
private XStream xs = new XStream();
private KieProjectService projectService;
private FolderListingResolver folderListingResolver;
private IOService ioService;
private IOService ioServiceConfig;
private VFSLockServiceImpl lockService;
private MetadataService metadataService;
private UserServicesImpl userServices;
private DeleteService deleteService;
private RenameService renameService;
private CopyService copyService;
public ExplorerServiceHelper() {
//WELD proxy support
}
@Inject
public ExplorerServiceHelper( final KieProjectService projectService,
final FolderListingResolver folderListingResolver,
@Named("ioStrategy") final IOService ioService,
@Named("configIO") final IOService ioServiceConfig,
final VFSLockServiceImpl lockService,
final MetadataService metadataService,
final UserServicesImpl userServices,
final DeleteService deleteService,
final RenameService renameService,
final CopyService copyService ) {
this.projectService = projectService;
this.folderListingResolver = folderListingResolver;
this.ioService = ioService;
this.ioServiceConfig = ioServiceConfig;
this.lockService = lockService;
this.metadataService = metadataService;
this.userServices = userServices;
this.deleteService = deleteService;
this.renameService = renameService;
this.copyService = copyService;
}
public FolderItem toFolderItem( final org.guvnor.common.services.project.model.Package pkg ) {
if ( pkg == null ) {
return null;
}
return new FolderItem( pkg, pkg.getRelativeCaption(), FolderItemType.FOLDER );
}
public FolderItem toFolderItem( final org.uberfire.java.nio.file.Path path ) {
if ( Files.isRegularFile( path ) ) {
final org.uberfire.backend.vfs.Path p = Paths.convert( path );
return new FolderItem( p,
p.getFileName(),
FolderItemType.FILE,
false,
Paths.readLockedBy( p ),
Collections.<String>emptyList(),
getRestrictedOperations( p ) );
} else if ( Files.isDirectory( path ) ) {
final org.uberfire.backend.vfs.Path p = Paths.convert( path );
return new FolderItem( p,
p.getFileName(),
FolderItemType.FOLDER );
}
return null;
}
public List<FolderItem> getPackageSegments( final Package _pkg ) {
List<FolderItem> result = new ArrayList<FolderItem>();
Package pkg = _pkg;
while ( pkg != null ) {
final Package parent = projectService.resolveParentPackage( pkg );
if ( parent != null ) {
result.add( toFolderItem( parent ) );
}
pkg = parent;
}
return Lists.reverse( result );
}
public FolderListing getFolderListing( final FolderItem selectedItem,
final Project selectedProject,
final Package selectedPackage,
final ActiveOptions options ) {
return folderListingResolver.resolve( selectedItem,
selectedProject,
selectedPackage,
this,
options );
}
public FolderListing getFolderListing( final Package pkg,
final ActiveOptions options ) {
return new FolderListing( toFolderItem( pkg ),
getItems( pkg,
options ),
getPackageSegments( pkg ) );
}
public FolderListing getFolderListing( final FolderItem item,
final ActiveOptions options ) {
FolderListing result = null;
if ( item.getItem() instanceof Path ) {
result = getFolderListing( (Path) item.getItem(),
options );
} else if ( item.getItem() instanceof Package ) {
result = getFolderListing( (Package) item.getItem(),
options );
}
return result;
}
public FolderListing getFolderListing( final Path path,
final ActiveOptions options
) {
//Get list of files and folders contained in the path
final List<FolderItem> folderItems = new ArrayList<FolderItem>();
final boolean includeTags = options.contains( Option.SHOW_TAG_FILTER );
//Scan upwards until the path exists (as the current path could have been deleted)
org.uberfire.java.nio.file.Path nioPath = Paths.convert( path );
while ( !Files.exists( nioPath ) ) {
nioPath = nioPath.getParent();
}
final Path basePath = Paths.convert( nioPath );
final DirectoryStream<org.uberfire.java.nio.file.Path> nioPaths = ioService.newDirectoryStream( nioPath,
dotFileFilter );
for ( org.uberfire.java.nio.file.Path np : nioPaths ) {
if ( Files.isRegularFile( np ) ) {
final org.uberfire.backend.vfs.Path p = Paths.convert( np );
final String lockedBy = Paths.readLockedBy( p );
final FolderItem folderItem = new FolderItem( p,
p.getFileName(),
FolderItemType.FILE,
false,
lockedBy,
includeTags ? metadataService.getTags( p ) : Collections.<String>emptyList(),
getRestrictedOperations( p ) );
folderItems.add( folderItem );
} else if ( Files.isDirectory( np ) ) {
final org.uberfire.backend.vfs.Path p = Paths.convert( np );
boolean lockedItems = !lockService.retrieveLockInfos( Paths.convert( np ), true ).isEmpty();
final FolderItem folderItem = new FolderItem( p,
p.getFileName(),
FolderItemType.FOLDER,
lockedItems,
null,
Collections.<String>emptyList(),
getRestrictedOperations( p ) );
folderItems.add( folderItem );
}
}
Collections.sort( folderItems, Sorters.ITEM_SORTER );
return new FolderListing( toFolderItem( nioPath ),
folderItems,
getPathSegments( basePath ) );
}
public boolean hasAssets( final Package pkg ) {
if ( pkg == null ) {
return false;
}
if ( hasAssets( pkg.getPackageMainSrcPath() )
|| hasAssets( pkg.getPackageTestSrcPath() )
|| hasAssets( pkg.getPackageMainResourcesPath() )
|| hasAssets( pkg.getPackageTestResourcesPath() ) ) {
return true;
}
final Set<Package> childPackages = projectService.resolvePackages( pkg );
for ( final Package childPackage : childPackages ) {
if ( hasAssets( childPackage ) ) {
return true;
}
}
return false;
}
boolean hasAssets( final Path packagePath ) {
final org.uberfire.java.nio.file.Path nioPackagePath = Paths.convert( packagePath );
if ( Files.exists( nioPackagePath ) ) {
final DirectoryStream<org.uberfire.java.nio.file.Path> nioPaths = ioService.newDirectoryStream( nioPackagePath,
regularFileFilter );
for ( org.uberfire.java.nio.file.Path nioPath : nioPaths ) {
return true;
}
}
return false;
}
public List<FolderItem> getItems( final Package pkg,
final ActiveOptions options ) {
final List<FolderItem> folderItems = new ArrayList<FolderItem>();
if ( pkg == null ) {
return emptyList();
}
final Set<Package> childPackages = projectService.resolvePackages( pkg );
for ( final Package childPackage : childPackages ) {
folderItems.add( toFolderItem( childPackage ) );
}
folderItems.addAll( getItems( pkg.getPackageMainSrcPath(),
options ) );
folderItems.addAll( getItems( pkg.getPackageTestSrcPath(),
options ) );
folderItems.addAll( getItems( pkg.getPackageMainResourcesPath(),
options ) );
folderItems.addAll( getItems( pkg.getPackageTestResourcesPath(),
options ) );
Collections.sort( folderItems,
Sorters.ITEM_SORTER );
return folderItems;
}
private List<FolderItem> getPathSegments( final Path path ) {
org.uberfire.java.nio.file.Path nioSegmentPath = Paths.convert( path ).getParent();
//We're not interested in the terminal segment prior to root (i.e. the Project name)
final int segmentCount = nioSegmentPath.getNameCount();
if ( segmentCount < 1 ) {
return new ArrayList<FolderItem>();
}
//Order from root to leaf (as we use getParent from the leaf we add them in reverse order)
final FolderItem[] segments = new FolderItem[ segmentCount ];
for ( int idx = segmentCount; idx > 0; idx-- ) {
segments[ idx - 1 ] = toFolderItem( nioSegmentPath );
nioSegmentPath = nioSegmentPath.getParent();
}
return Arrays.asList( segments );
}
private List<FolderItem> getItems( final Path packagePath,
final ActiveOptions options ) {
final List<FolderItem> folderItems = new ArrayList<FolderItem>();
final boolean includeTags = options.contains( Option.SHOW_TAG_FILTER );
final org.uberfire.java.nio.file.Path nioPackagePath = Paths.convert( packagePath );
if ( Files.exists( nioPackagePath ) ) {
final DirectoryStream<org.uberfire.java.nio.file.Path> nioPaths = ioService.newDirectoryStream( nioPackagePath,
regularFileFilter );
for ( org.uberfire.java.nio.file.Path nioPath : nioPaths ) {
final org.uberfire.backend.vfs.Path path = Paths.convert( nioPath );
if ( Paths.isLock( path ) ) {
continue;
}
final String lockedBy = Paths.readLockedBy( path );
final FolderItem folderItem = new FolderItem( path,
path.getFileName(),
FolderItemType.FILE,
false,
lockedBy,
includeTags ? metadataService.getTags( path ) : Collections.<String>emptyList(),
getRestrictedOperations( path ) );
folderItems.add( folderItem );
}
}
return folderItems;
}
public void store( final OrganizationalUnit selectedOrganizationalUnit,
final Repository selectedRepository,
final String branch,
final Project selectedProject,
final FolderListing folderListing,
final Package selectedPackage,
final ActiveOptions options ) {
final org.uberfire.java.nio.file.Path userNavPath = userServices.buildPath( "explorer", "user.nav" );
final org.uberfire.java.nio.file.Path lastUserNavPath = userServices.buildPath( "explorer", "last.user.nav" );
final OrganizationalUnit _selectedOrganizationalUnit = selectedOrganizationalUnit;
final Repository _selectedRepository = selectedRepository;
final String _branch = branch;
final Project _selectedProject = selectedProject;
final FolderItem _selectedItem = folderListing.getItem();
final org.guvnor.common.services.project.model.Package _selectedPackage;
if ( selectedPackage != null ) {
_selectedPackage = selectedPackage;
} else if ( folderListing.getItem().getItem() instanceof Package ) {
_selectedPackage = (Package) folderListing.getItem().getItem();
} else {
_selectedPackage = null;
}
SimpleAsyncExecutorService.getDefaultInstance().execute( new DescriptiveRunnable() {
@Override
public String getDescription() {
return "Serialize Navigation State";
}
@Override
public void run() {
try {
store( userNavPath, lastUserNavPath, _selectedOrganizationalUnit,
_selectedRepository, _branch, _selectedProject,
_selectedPackage, _selectedItem, options );
} catch ( final Exception e ) {
LOGGER.error( "Can't serialize user's state navigation", e );
}
}
} );
}
public void store( final org.uberfire.java.nio.file.Path userNav,
final org.uberfire.java.nio.file.Path lastUserNav,
final OrganizationalUnit organizationalUnit,
final Repository repository,
final String branch,
final Project project,
final Package pkg,
final FolderItem item,
final ActiveOptions options ) {
final UserExplorerData content;
final UserExplorerData _content = loadUserContent( userNav );
if ( _content == null ) {
content = new UserExplorerData();
} else {
content = _content;
}
final UserExplorerLastData lastContent = new UserExplorerLastData();
if ( organizationalUnit != null ) {
content.setOrganizationalUnit( organizationalUnit );
}
if ( repository != null && organizationalUnit != null ) {
content.addRepository( organizationalUnit, repository );
}
if ( project != null && organizationalUnit != null && repository != null ) {
content.addProject( organizationalUnit, repository, project );
}
if ( item != null && organizationalUnit != null && repository != null && branch != null && project != null ) {
lastContent.setFolderItem( organizationalUnit, repository, branch, project, item );
content.addFolderItem( organizationalUnit, repository, project, item );
}
if ( pkg != null && organizationalUnit != null && repository != null && branch != null && project != null ) {
lastContent.setPackage( organizationalUnit, repository, branch, project, pkg );
content.addPackage( organizationalUnit, repository, project, pkg );
}
if ( options != null && !options.isEmpty() ) {
lastContent.setOptions( options );
}
if ( !content.isEmpty() ) {
try {
ioServiceConfig.startBatch( userNav.getFileSystem() );
ioServiceConfig.write( userNav,
xs.toXML( content ) );
ioServiceConfig.write( lastUserNav,
xs.toXML( lastContent ) );
} finally {
ioServiceConfig.endBatch();
}
}
}
public UserExplorerData loadUserContent( final org.uberfire.java.nio.file.Path path ) {
try {
if ( ioServiceConfig.exists( path ) ) {
final String xml = ioServiceConfig.readAllString( path );
return (UserExplorerData) xs.fromXML( xml );
}
} catch ( final Exception ignored ) {
}
return null;
}
public UserExplorerData loadUserContent() {
final UserExplorerData userExplorerData = loadUserContent( userServices.buildPath( "explorer", "user.nav" ) );
if ( userExplorerData != null ) {
return userExplorerData;
}
return new UserExplorerData();
}
public UserExplorerLastData getLastContent() {
try {
final UserExplorerLastData lastData = getLastContent( userServices.buildPath( "explorer", "last.user.nav" ) );
if ( lastData != null ) {
return lastData;
}
} catch ( final Exception ignored ) {
}
return new UserExplorerLastData();
}
public UserExplorerLastData getLastContent( final org.uberfire.java.nio.file.Path path ) {
try {
if ( ioServiceConfig.exists( path ) ) {
final String xml = ioServiceConfig.readAllString( path );
return (UserExplorerLastData) xs.fromXML( xml );
}
} catch ( final Exception ignored ) {
}
return null;
}
public List<FolderItemOperation> getRestrictedOperations( final Path path ) {
final List<FolderItemOperation> restrictedOperations = new ArrayList<FolderItemOperation>();
if ( copyService.hasRestriction( path ) ) {
restrictedOperations.add( FolderItemOperation.COPY );
}
if ( renameService.hasRestriction( path ) ) {
restrictedOperations.add( FolderItemOperation.RENAME );
}
if ( deleteService.hasRestriction( path ) ) {
restrictedOperations.add( FolderItemOperation.DELETE );
}
return restrictedOperations;
}
}