/* * 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. * * 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.structure.backend.repositories; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Event; import javax.inject.Inject; import javax.inject.Named; import org.guvnor.common.services.backend.exceptions.ExceptionUtilities; import org.guvnor.structure.backend.backcompat.BackwardCompatibleUtil; import org.guvnor.structure.organizationalunit.OrganizationalUnit; import org.guvnor.structure.organizationalunit.OrganizationalUnitService; import org.guvnor.structure.repositories.GitMetadataStore; import org.guvnor.structure.repositories.NewRepositoryEvent; import org.guvnor.structure.repositories.Repository; import org.guvnor.structure.repositories.RepositoryAlreadyExistsException; import org.guvnor.structure.repositories.RepositoryEnvironmentConfiguration; import org.guvnor.structure.repositories.RepositoryEnvironmentConfigurations; import org.guvnor.structure.repositories.RepositoryInfo; import org.guvnor.structure.repositories.RepositoryRemovedEvent; import org.guvnor.structure.repositories.RepositoryService; import org.guvnor.structure.server.config.ConfigGroup; import org.guvnor.structure.server.config.ConfigItem; import org.guvnor.structure.server.config.ConfigType; import org.guvnor.structure.server.config.ConfigurationFactory; import org.guvnor.structure.server.config.ConfigurationService; import org.guvnor.structure.server.repositories.RepositoryFactory; import org.jboss.errai.bus.server.annotations.Service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.uberfire.backend.server.util.TextUtil; import org.uberfire.backend.vfs.Path; import org.uberfire.ext.editor.commons.version.impl.PortableVersionRecord; import org.uberfire.io.IOService; import org.uberfire.java.nio.base.version.VersionAttributeView; import org.uberfire.java.nio.base.version.VersionRecord; import org.uberfire.rpc.SessionInfo; import org.uberfire.security.authz.AuthorizationManager; import static org.guvnor.structure.repositories.EnvironmentParameters.*; import static org.guvnor.structure.server.config.ConfigType.*; import static org.uberfire.backend.server.util.Paths.*; @Service @ApplicationScoped public class RepositoryServiceImpl implements RepositoryService { private static final Logger logger = LoggerFactory.getLogger( RepositoryServiceImpl.class ); private static final int HISTORY_PAGE_SIZE = 10; @Inject @Named("ioStrategy") private IOService ioService; @Inject private GitMetadataStore metadataStore; @Inject private ConfigurationService configurationService; @Inject private OrganizationalUnitService organizationalUnitService; @Inject private ConfigurationFactory configurationFactory; @Inject private RepositoryFactory repositoryFactory; @Inject private Event<NewRepositoryEvent> event; @Inject private Event<RepositoryRemovedEvent> repositoryRemovedEvent; @Inject private BackwardCompatibleUtil backward; @Inject private ConfiguredRepositories configuredRepositories; @Inject private AuthorizationManager authorizationManager; @Inject private SessionInfo sessionInfo; private Repository createRepository( final ConfigGroup repositoryConfig ) { final Repository repository = repositoryFactory.newRepository( repositoryConfig ); configurationService.addConfiguration( repositoryConfig ); configuredRepositories.add( repository ); return repository; } public RepositoryInfo getRepositoryInfo( final String alias ) { final Repository repo = getRepository( alias ); String ouName = null; for ( final OrganizationalUnit ou : organizationalUnitService.getAllOrganizationalUnits() ) { for ( Repository repository : ou.getRepositories() ) { if ( repository.getAlias().equals( alias ) ) { ouName = ou.getName(); } } } return new RepositoryInfo( repo.getIdentifier(), alias, ouName, repo.getRoot(), repo.getPublicURIs(), getRepositoryHistory( alias, 0, HISTORY_PAGE_SIZE ) ); } @Override public List<VersionRecord> getRepositoryHistory( final String alias, final int startIndex ) { return getRepositoryHistory( alias, startIndex, startIndex + HISTORY_PAGE_SIZE ); } @Override public List<VersionRecord> getRepositoryHistory( String alias, int startIndex, int endIndex ) { final Repository repo = getRepository( alias ); //This is a work-around for https://bugzilla.redhat.com/show_bug.cgi?id=1199215 //org.kie.workbench.common.screens.contributors.backend.dataset.ContributorsManager is trying to //load a Repository's history for a Repository associated with an Organizational Unit before the //Repository has been setup. if ( repo == null ) { return Collections.EMPTY_LIST; } final VersionAttributeView versionAttributeView = ioService.getFileAttributeView( convert( repo.getRoot() ), VersionAttributeView.class ); final List<VersionRecord> records = versionAttributeView.readAttributes().history().records(); if ( startIndex < 0 ) { startIndex = 0; } if ( endIndex < 0 || endIndex > records.size() ) { endIndex = records.size(); } if ( startIndex >= records.size() || startIndex >= endIndex ) { return Collections.emptyList(); } Collections.reverse( records ); final List<VersionRecord> result = new ArrayList<VersionRecord>( endIndex - startIndex ); for ( VersionRecord record : records.subList( startIndex, endIndex ) ) { result.add( new PortableVersionRecord( record.id(), record.author(), record.email(), record.comment(), record.date(), record.uri() ) ); } return result; } @Override public Repository getRepository( final String alias ) { return configuredRepositories.getRepositoryByRepositoryAlias( alias ); } @Override public Repository getRepository( final Path root ) { return configuredRepositories.getRepositoryByRootPath( root ); } @Override public String normalizeRepositoryName( String name ) { return TextUtil.normalizeRepositoryName( name ); } @Override public boolean validateRepositoryName( String name ) { return name != null && !"".equals( name ) && name.equals( normalizeRepositoryName( name ) ); } @Override public Collection<Repository> getAllRepositories() { return configuredRepositories.getAllConfiguredRepositories(); } @Override public Collection<Repository> getRepositories() { Collection<Repository> result = new ArrayList<>(); for ( Repository repository : configuredRepositories.getAllConfiguredRepositories() ) { if ( authorizationManager.authorize( repository, sessionInfo.getIdentity() ) ) { result.add( repository ); } } return result; } @Override public Repository createRepository( final OrganizationalUnit organizationalUnit, final String scheme, final String alias, final RepositoryEnvironmentConfigurations repositoryEnvironmentConfigurations ) throws RepositoryAlreadyExistsException { try { final Repository repository = createRepository( scheme, alias, repositoryEnvironmentConfigurations ); if ( organizationalUnit != null && repository != null ) { organizationalUnitService.addRepository( organizationalUnit, repository ); } metadataStore.write( alias, (String) repositoryEnvironmentConfigurations.getOrigin() ); return repository; } catch ( final Exception e ) { logger.error( "Error during create repository", e ); throw ExceptionUtilities.handleException( e ); } } protected ConfigGroup findRepositoryConfig( final String alias ) { final Collection<ConfigGroup> groups = configurationService.getConfiguration( ConfigType.REPOSITORY ); if ( groups != null ) { for ( ConfigGroup groupConfig : groups ) { if ( groupConfig.getName().equals( alias ) ) { return groupConfig; } } } return null; } @Override public void removeRepository( final String alias ) { final ConfigGroup thisRepositoryConfig = findRepositoryConfig( alias ); try { configurationService.startBatch(); if ( thisRepositoryConfig != null ) { configurationService.removeConfiguration( thisRepositoryConfig ); } final Repository repo = configuredRepositories.remove( alias ); if ( repo != null ) { repositoryRemovedEvent.fire( new RepositoryRemovedEvent( repo ) ); ioService.delete( convert( repo.getRoot() ).getFileSystem().getPath( null ) ); } //Remove reference to Repository from Organizational Units final Collection<OrganizationalUnit> organizationalUnits = organizationalUnitService.getAllOrganizationalUnits(); for ( OrganizationalUnit ou : organizationalUnits ) { for ( Repository repository : ou.getRepositories() ) { if ( repository.getAlias().equals( alias ) ) { organizationalUnitService.removeRepository( ou, repository ); metadataStore.delete( alias ); } } } } catch ( final Exception e ) { logger.error( "Error during remove repository", e ); throw new RuntimeException( e ); } finally { configurationService.endBatch(); } } @Override public Repository createRepository( final String scheme, final String alias, final RepositoryEnvironmentConfigurations repositoryEnvironmentConfigurations ) { if ( configuredRepositories.containsAlias( alias ) ) { throw new RepositoryAlreadyExistsException( alias ); } Repository repo = null; try { configurationService.startBatch(); final ConfigGroup repositoryConfig = configurationFactory.newConfigGroup( REPOSITORY, alias, "" ); repositoryConfig.addConfigItem( configurationFactory.newConfigItem( "security:groups", new ArrayList<String>() ) ); if ( !repositoryEnvironmentConfigurations.containsConfiguration( SCHEME ) ) { repositoryConfig.addConfigItem( configurationFactory.newConfigItem( SCHEME, scheme ) ); } for ( final RepositoryEnvironmentConfiguration configuration : repositoryEnvironmentConfigurations.getConfigurationList() ) { repositoryConfig.addConfigItem( getRepositoryConfigItem( configuration ) ); } repo = createRepository( repositoryConfig ); return repo; } catch ( final Exception e ) { logger.error( "Error during create repository", e ); throw ExceptionUtilities.handleException( e ); } finally { configurationService.endBatch(); if ( repo != null ) { event.fire( new NewRepositoryEvent( repo ) ); } } } private ConfigItem getRepositoryConfigItem( final RepositoryEnvironmentConfiguration configuration ) { if ( configuration.isSecuredConfigurationItem() ) { return configurationFactory.newSecuredConfigItem( configuration.getName(), configuration.getValue().toString() ); } else { return configurationFactory.newConfigItem( configuration.getName(), configuration.getValue() ); } } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void addGroup( final Repository repository, final String group ) { final ConfigGroup thisRepositoryConfig = findRepositoryConfig( repository.getAlias() ); if ( thisRepositoryConfig != null ) { final ConfigItem<List> groups = backward.compat( thisRepositoryConfig ).getConfigItem( "security:groups" ); groups.getValue().add( group ); configurationService.updateConfiguration( thisRepositoryConfig ); configuredRepositories.update( repositoryFactory.newRepository( thisRepositoryConfig ) ); } else { throw new IllegalArgumentException( "Repository " + repository.getAlias() + " not found" ); } } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void removeGroup( Repository repository, String group ) { final ConfigGroup thisRepositoryConfig = findRepositoryConfig( repository.getAlias() ); if ( thisRepositoryConfig != null ) { final ConfigItem<List> groups = backward.compat( thisRepositoryConfig ).getConfigItem( "security:groups" ); groups.getValue().remove( group ); configurationService.updateConfiguration( thisRepositoryConfig ); configuredRepositories.update( repositoryFactory.newRepository( thisRepositoryConfig ) ); } else { throw new IllegalArgumentException( "Repository " + repository.getAlias() + " not found" ); } } @Override public List<VersionRecord> getRepositoryHistoryAll( final String alias ) { return getRepositoryHistory( alias, 0, -1 ); } @Override public Repository updateRepositoryConfiguration( final Repository repository, final RepositoryEnvironmentConfigurations repositoryEnvironmentConfigurations ) { final ConfigGroup thisRepositoryConfig = findRepositoryConfig( repository.getAlias() ); if ( thisRepositoryConfig != null && repositoryEnvironmentConfigurations != null ) { try { configurationService.startBatch(); for ( final Map.Entry<String, Object> entry : repositoryEnvironmentConfigurations.getConfigurationMap().entrySet() ) { ConfigItem configItem = thisRepositoryConfig.getConfigItem( entry.getKey() ); if ( configItem == null ) { thisRepositoryConfig.addConfigItem( configurationFactory.newConfigItem( entry.getKey(), entry.getValue() ) ); } else { configItem.setValue( entry.getValue() ); } } configurationService.updateConfiguration( thisRepositoryConfig ); final Repository updatedRepo = repositoryFactory.newRepository( thisRepositoryConfig ); configuredRepositories.update( updatedRepo ); return updatedRepo; } catch ( final Exception e ) { logger.error( "Error during remove repository", e ); throw new RuntimeException( e ); } finally { configurationService.endBatch(); } } else { throw new IllegalArgumentException( "Repository " + repository.getAlias() + " not found" ); } } }