/*
* 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.kie.workbench.common.screens.explorer.backend.server;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Named;
import com.thoughtworks.xstream.XStream;
import org.guvnor.common.services.backend.exceptions.ExceptionUtilities;
import org.guvnor.common.services.project.events.DeleteProjectEvent;
import org.guvnor.common.services.project.events.RenameProjectEvent;
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.guvnor.structure.repositories.RepositoryService;
import org.jboss.errai.bus.server.annotations.Service;
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.model.URIStructureExplorerModel;
import org.kie.workbench.common.screens.explorer.service.ActiveOptions;
import org.kie.workbench.common.screens.explorer.service.ExplorerService;
import org.kie.workbench.common.screens.explorer.service.Option;
import org.kie.workbench.common.screens.explorer.service.ProjectExplorerContentQuery;
import org.kie.workbench.common.services.shared.project.KieProject;
import org.kie.workbench.common.services.shared.project.KieProjectService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.uberfire.backend.server.UserServicesBackendImpl;
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.backend.vfs.impl.LockInfo;
import org.uberfire.commons.async.DescriptiveRunnable;
import org.uberfire.commons.async.SimpleAsyncExecutorService;
import org.uberfire.ext.editor.commons.backend.service.helper.CopyHelper;
import org.uberfire.ext.editor.commons.backend.service.helper.RenameHelper;
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.base.options.CommentedOption;
import org.uberfire.java.nio.file.FileSystem;
import org.uberfire.java.nio.file.Files;
import org.uberfire.java.nio.file.StandardDeleteOption;
import org.uberfire.rpc.SessionInfo;
import org.uberfire.security.authz.AuthorizationManager;
import static java.util.Collections.*;
import static org.uberfire.commons.validation.PortablePreconditions.*;
@Service
@Dependent
public class ExplorerServiceImpl
implements ExplorerService {
private static final Logger LOGGER = LoggerFactory.getLogger( ExplorerServiceImpl.class );
@Inject
@Named("ioStrategy")
private IOService ioService;
@Inject
@Named("configIO")
private IOService ioServiceConfig;
@Inject
@Named("systemFS")
private FileSystem fileSystem;
@Inject
private KieProjectService projectService;
@Inject
private ExplorerServiceHelper helper;
@Inject
private OrganizationalUnitService organizationalUnitService;
@Inject
private User identity;
@Inject
private SessionInfo sessionInfo;
@Inject
private UserServicesImpl userServices;
@Inject
private UserServicesBackendImpl userServicesBackend;
@Inject
private Instance<RenameHelper> renameHelpers;
@Inject
private Instance<CopyHelper> copyHelpers;
@Inject
private ProjectExplorerContentResolver projectExplorerContentResolver;
@Inject
private RepositoryService repositoryService;
@Inject
private VFSLockServiceImpl lockService;
@Inject
private DeleteService deleteService;
@Inject
private RenameService renameService;
@Inject
private CopyService copyService;
@Inject
//@AppResourcesAuthz
private AuthorizationManager authorizationManager;
private XStream xs = new XStream();
public ExplorerServiceImpl() {
// Boilerplate sacrifice for Weld
}
public ExplorerServiceImpl( final IOService ioService,
final KieProjectService projectService,
final OrganizationalUnitService organizationalUnitService,
final User identity ) {
this.ioService = ioService;
this.projectService = projectService;
this.organizationalUnitService = organizationalUnitService;
this.identity = identity;
}
@Override
public ProjectExplorerContent getContent( final String _path,
final ActiveOptions activeOptions ) {
checkNotEmpty( "path", _path );
final Path path = Paths.convert( ioService.get( URI.create( _path.trim() ) ) );
final Project project = projectService.resolveProject( path );
final Path convertedPath = Paths.convert( Paths.convert( path ).getRoot() );
final Repository repo = repositoryService.getRepository( convertedPath );
String branch = getBranchName( repo,
convertedPath );
OrganizationalUnit ou = null;
for ( final OrganizationalUnit organizationalUnit : organizationalUnitService.getOrganizationalUnits() ) {
if ( organizationalUnit.getRepositories().contains( repo ) ) {
ou = organizationalUnit;
break;
}
}
return getContent( new ProjectExplorerContentQuery( ou,
repo,
branch,
project,
activeOptions ) );
}
private String getBranchName( final Repository repository,
final Path convertedPath ) {
for ( String branchName : repository.getBranches() ) {
if ( repository.getBranchRoot( branchName ).equals( convertedPath ) ) {
return branchName;
}
}
return null;
}
@Override
public ProjectExplorerContent getContent( final ProjectExplorerContentQuery query ) {
return projectExplorerContentResolver.resolve( query );
}
@Override
public URIStructureExplorerModel getURIStructureExplorerModel( final Path originalURI ) {
final Project project = getURIProject( originalURI );
final Repository repository = getURIRepository( originalURI );
final OrganizationalUnit ou = getURIOrganizationalUnits( repository );
return new URIStructureExplorerModel( ou,
repository,
project );
}
private KieProject getURIProject( final Path originalURI ) {
return projectService.resolveProject( originalURI );
}
private Repository getURIRepository( final Path originalURI ) {
org.uberfire.java.nio.file.Path ufPath = Paths.convert( originalURI );
return repositoryService.getRepository( Paths.convert( ufPath.getRoot() ) );
}
private OrganizationalUnit getURIOrganizationalUnits( final Repository repository ) {
for ( OrganizationalUnit organizationalUnit : getOrganizationalUnits() ) {
if ( organizationalUnit.getRepositories().contains( repository ) ) {
return organizationalUnit;
}
}
throw new OrganizationalUnitNotFoundForURI();
}
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;
}
@Override
public FolderListing getFolderListing( final OrganizationalUnit organizationalUnit,
final Repository repository,
final String branch,
final Project project,
final FolderItem item,
final ActiveOptions options ) {
//TODO: BUSINESS_CONTENT, TECHNICAL_CONTENT
final FolderListing result = helper.getFolderListing( item,
options );
if ( result != null ) {
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" );
SimpleAsyncExecutorService.getDefaultInstance().execute( new DescriptiveRunnable() {
@Override
public String getDescription() {
return "Serialize Navigation State";
}
@Override
public void run() {
try {
Package pkg = null;
if ( item.getItem() instanceof Package ) {
pkg = (Package) item.getItem();
}
helper.store( userNavPath, lastUserNavPath, organizationalUnit,
repository, branch, project, pkg, item, options );
} catch ( final Exception e ) {
LOGGER.error( "Can't serialize user's state navigation", e );
}
}
} );
}
return result;
}
private List<Path> resolvePath( final FolderItem item ) {
if ( item == null ) {
return emptyList();
}
if ( item.getItem() instanceof Package ) {
final Package pkg = ( (Package) item.getItem() );
return new ArrayList<Path>( 4 ) {{
add( pkg.getPackageMainResourcesPath() );
add( pkg.getPackageMainSrcPath() );
add( pkg.getPackageTestResourcesPath() );
add( pkg.getPackageTestSrcPath() );
}};
}
if ( item.getItem() instanceof Path ) {
//Path could represent a package
if ( item.getType() == FolderItemType.FOLDER ) {
final Package pkg = projectService.resolvePackage( (Path) item.getItem() );
if ( pkg == null ) {
return new ArrayList<Path>( 1 ) {{
add( (Path) item.getItem() );
}};
} else {
return new ArrayList<Path>( 4 ) {{
add( pkg.getPackageMainResourcesPath() );
add( pkg.getPackageMainSrcPath() );
add( pkg.getPackageTestResourcesPath() );
add( pkg.getPackageTestSrcPath() );
}};
}
} else {
return new ArrayList<Path>( 1 ) {{
add( (Path) item.getItem() );
}};
}
}
return emptyList();
}
@Override
public Package resolvePackage( final FolderItem item ) {
if ( item == null ) {
return null;
}
if ( item.getItem() instanceof Package ) {
return (Package) item.getItem();
}
if ( item.getItem() instanceof Path ) {
return projectService.resolvePackage( (Path) item.getItem() );
}
return null;
}
@Override
public Set<Option> getLastUserOptions() {
return helper.getLastContent().getOptions();
}
@Override
public void deleteItem( final FolderItem folderItem,
final String comment ) {
final Collection<Path> paths = resolvePath( folderItem );
deleteService.deleteIfExists( paths, comment );
}
@Override
public void renameItem( final FolderItem folderItem,
final String newName,
final String comment ) {
final Collection<Path> paths = resolvePath( folderItem );
renameService.renameIfExists( paths, newName, comment );
}
@Override
public void copyItem( final FolderItem folderItem,
final String newName,
final Path targetDirectory,
final String comment ) {
final List<Path> paths = resolvePath( folderItem );
if ( paths != null && paths.size() == 1 ){
copyService.copy( paths.get( 0 ), newName, targetDirectory, comment );
} else {
// when copying packages
copyService.copyIfExists( paths, newName, comment );
}
}
void onProjectRename( @Observes final RenameProjectEvent event ) {
cleanup( event.getOldProject() );
}
void onProjectDelete( @Observes final DeleteProjectEvent event ) {
cleanup( event.getProject() );
}
private void cleanup( final Project project ) {
final Collection<org.uberfire.java.nio.file.Path> lastNavs = userServicesBackend.getAllUsersData( "explorer", "last.user.nav" );
final Collection<org.uberfire.java.nio.file.Path> userNavs = userServicesBackend.getAllUsersData( "explorer", "user.nav" );
try {
ioServiceConfig.startBatch( fileSystem );
for ( org.uberfire.java.nio.file.Path path : userNavs ) {
final UserExplorerData userContent = helper.loadUserContent( path );
if ( userContent != null ) {
if ( userContent.deleteProject( project ) ) {
ioServiceConfig.write( path, xs.toXML( userContent ) );
}
}
}
for ( org.uberfire.java.nio.file.Path lastNav : lastNavs ) {
final UserExplorerLastData lastUserContent = helper.getLastContent( lastNav );
if ( lastUserContent != null ) {
if ( lastUserContent.deleteProject( project ) ) {
ioServiceConfig.write( lastNav, xs.toXML( lastUserContent ) );
}
}
}
} finally {
ioServiceConfig.endBatch();
}
}
public class OrganizationalUnitNotFoundForURI extends RuntimeException {
}
}